A holder says a held call's end on its seat's gated-ended, kept last per subject for a day in SEAT_<seat>_gated-ended, which the grants part makes from the definition seatdef.Resolve gives (A-264). The caller is granted hearing gated-ended.<caller>.> under its own escaped account name, and an ordered consumer on that stream filtered to it, from its invokes of the marked verb by name; a module or process that answers a marked verb is granted saying the event to any caller. No process of mesh-delivery holds a marked verb, so no holder here takes NewGateChannel. Builds: design 47 G §677, §700, A-264, A-273 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
55 lines
2.3 KiB
Go
55 lines
2.3 KiB
Go
package buscompose
|
|
|
|
import (
|
|
"slices"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/keys"
|
|
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
|
)
|
|
|
|
// **A held call's end is heard by its caller alone** (design 47 G §677; lead answer A-264): a holder says the end of a call of
|
|
// a marked verb on its seat's event `gated-ended`, subject `mesh.seat.<seat>.event.gated-ended.<caller>.<call>`, `<caller>` the
|
|
// account the bus proved escaped as a key's name is, kept last per subject for a day in the stream SEAT_<seat>_gated-ended
|
|
// (KeptEventsOf, from the definition seatdef.Resolve gives). The caller is granted hearing `gated-ended.<caller>.>` and no other
|
|
// caller's, from its invokes of the marked verb by name; it reads the stream through an ordered consumer filtered to its own
|
|
// subjects (mesh-sdk process awaitGated), made for the read. A process that answers a marked verb says the event to any caller.
|
|
|
|
// gatedEndedGrants are the grants of the principal user from the marked verbs (`seat:<seat>.<verb>`) it invokes by name and
|
|
// those it answers.
|
|
func gatedEndedGrants(user string, marked, invokes, answers []string) (pub, sub []string) {
|
|
caller := keys.EscapeName(user)
|
|
if user == "" {
|
|
return nil, nil
|
|
}
|
|
var heard, said []string
|
|
for _, v := range marked {
|
|
seat, _, ok := strings.Cut(strings.TrimPrefix(v, "seat:"), ".")
|
|
if !ok || !safeSubject.MatchString(seat) {
|
|
continue
|
|
}
|
|
if slices.Contains(invokes, v) {
|
|
heard = append(heard, seat)
|
|
}
|
|
if slices.Contains(answers, v) {
|
|
said = append(said, seat)
|
|
}
|
|
}
|
|
for _, seat := range unique(heard) {
|
|
stream := seatdef.KeptStream(seat, seatdef.Message{Name: seatdef.GatedEndedEvent})
|
|
own := GatedEndedSubject(seat, caller) + ".>"
|
|
sub = append(sub, own)
|
|
pub = append(pub, "$JS.API.STREAM.INFO."+stream, "$JS.API.CONSUMER.CREATE."+stream+".*."+own,
|
|
"$JS.API.CONSUMER.MSG.NEXT."+stream+".*", "$JS.API.CONSUMER.INFO."+stream+".*", "$JS.API.CONSUMER.DELETE."+stream+".*")
|
|
}
|
|
for _, seat := range unique(said) {
|
|
pub = append(pub, GatedEndedSubject(seat, "*")+".*")
|
|
}
|
|
return pub, sub
|
|
}
|
|
|
|
// GatedEndedSubject is the subject of the seat's gated-ended for one caller, its escaped name (keys.EscapeName) or `*`.
|
|
func GatedEndedSubject(seat, caller string) string {
|
|
return seatdef.EventSubject(seat, seatdef.GatedEndedEvent) + "." + caller
|
|
}
|