Derived at every pass from the catalog graph's manifests and the seat definitions' callers, never from a manifest field. Builds: design 47 G §59, §124, §442 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
87 lines
3.1 KiB
Go
87 lines
3.1 KiB
Go
package grants
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
|
)
|
|
|
|
// **A module's sent store is read by the modules it is for** (design 47 G §59, §124): the grants part derives, from the
|
|
// catalog graph and the seat definitions, never from a manifest field, a standing read of `<module>_sent-objects` for the
|
|
// callers the module's seat definition names for the verbs it serves, and for the consumers whose `consumes` declare its
|
|
// events. The grant follows the catalog graph, so it is composed with each module's declaration at every pass.
|
|
|
|
// verbCallersOf is, by seat and verb, the callers each verb of the definitions admits (a verb naming none takes its class's
|
|
// default).
|
|
func verbCallersOf(defs map[string]seatdef.Definition) map[string]map[string][]string {
|
|
out := map[string]map[string][]string{}
|
|
for _, d := range defs {
|
|
for _, v := range d.Verbs {
|
|
if out[d.Seat] == nil {
|
|
out[d.Seat] = map[string][]string{}
|
|
}
|
|
out[d.Seat][v.Name] = v.EffectiveCallers()
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// admits says whether a verb's callers name the module: `invokers` (every module whose manifest invokes the verb), the module
|
|
// itself, or a seat it claims.
|
|
func admits(callers []string, m catalogue.Manifest) bool {
|
|
for _, c := range callers {
|
|
switch {
|
|
case c == seatdef.CallerInvokers, c == seatdef.CallerModulePrefix+m.Module:
|
|
return true
|
|
}
|
|
if seat, ok := strings.CutPrefix(c, seatdef.CallerSeatPrefix); ok && slices.ContainsFunc(m.Claims, func(x catalogue.Claim) bool { return x.Name == seat }) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// sentStoresRead are the bus names of the sent stores the module m reads: of each module whose event it consumes (the module's
|
|
// own, or the seat a module claims), and of each module claiming a seat whose verb m invokes where the verb's callers admit m.
|
|
// Never m's own store, which its binding grants it.
|
|
func sentStoresRead(m catalogue.Manifest, all map[string]catalogue.Manifest, callers map[string]map[string][]string) []string {
|
|
claimants := func(name string) []string {
|
|
var out []string
|
|
if _, ok := all[name]; ok {
|
|
out = append(out, name)
|
|
}
|
|
for module, x := range all {
|
|
if slices.ContainsFunc(x.Claims, func(c catalogue.Claim) bool { return c.Name == name }) {
|
|
out = append(out, module)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
var stores []string
|
|
for _, c := range m.Consumes {
|
|
name, _, ok := strings.Cut(strings.TrimPrefix(c, "seat:"), ".")
|
|
if !ok || name == "*" {
|
|
continue
|
|
}
|
|
for _, module := range claimants(name) {
|
|
stores = append(stores, catalogue.SentObjectsName(module))
|
|
}
|
|
}
|
|
for _, in := range m.Invokes {
|
|
seat, verb, ok := catalogue.SeatInvoke(in)
|
|
if !ok || !admits(callers[seat][verb], m) {
|
|
continue
|
|
}
|
|
for module, x := range all {
|
|
if slices.ContainsFunc(x.Claims, func(c catalogue.Claim) bool { return c.Name == seat }) {
|
|
stores = append(stores, catalogue.SentObjectsName(module))
|
|
}
|
|
}
|
|
}
|
|
stores = slices.DeleteFunc(stores, func(s string) bool { return s == catalogue.SentObjectsName(m.Module) })
|
|
slices.Sort(stores)
|
|
return slices.Compact(stores)
|
|
}
|