W8.2: the seat-list wiring is mesh-sdk's seatlist.Part; seatlist.go is deleted
Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ Builds: design 47 G §204
This commit is contained in:
@@ -40,6 +40,7 @@ import (
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/announce"
|
||||
"git.novox.be/novox/mesh-sdk/go/process"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatlist"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/views"
|
||||
@@ -148,8 +149,8 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
}}
|
||||
f.Part.Bindings.Start(ctx, f.Part)
|
||||
// The seat list: read over the connection and the hub, given to catalogue at every change, and a pass composes again then.
|
||||
gate := &seatGate{}
|
||||
gate.follow(seatlist.ProcessBus(conn.Call, hub), f.Wake, logger.Printf)
|
||||
gate := newSeatGate()
|
||||
gate.Follow(seatlist.ProcessBus(conn.Call, hub), f.Wake, logger.Printf)
|
||||
f.Part.SeatList = gate
|
||||
f.Part.Say = sayCond
|
||||
fv.Start(ctx, f.Wake)
|
||||
@@ -220,7 +221,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
|
||||
if err := hub.Start(ctx, js, account); err != nil {
|
||||
return err
|
||||
}
|
||||
gate.eventsLive()
|
||||
gate.EventsLive()
|
||||
hears, err := grants.OwnHears(ownStore{conn}, account.Node)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -292,3 +293,24 @@ func hearRunning(ctx context.Context, account process.Account, js jetstream.JetS
|
||||
hearingRunning.cc = cc
|
||||
return nil
|
||||
}
|
||||
|
||||
// seatGate is the part's seat-list wiring (mesh-sdk seatlist.Part, ADR 0636 §1, §7) that also says the definitions the
|
||||
// list holds, which the part makes each kept event's stream from.
|
||||
type seatGate struct{ *seatlist.Part }
|
||||
|
||||
// seatListAgainCallers may read the seat list again (ADR 0636 §7): every operator's session and the healers. A call through
|
||||
// the mesh MCP server is proved only as its machine's tool runner (<node>.node-tools, issue 627), so node-tools stands for an
|
||||
// operator's session until a session is proved (issue 1966).
|
||||
var seatListAgainCallers = []string{stdio.AnyPerson, "node-tools", "mesh-healers"}
|
||||
|
||||
func newSeatGate() *seatGate {
|
||||
return &seatGate{seatlist.NewPart("grants", seatListAgainCallers)}
|
||||
}
|
||||
|
||||
// Definitions are the seat definitions the reader holds; none before it has started.
|
||||
func (g *seatGate) Definitions() map[string]seatdef.Definition {
|
||||
if r := g.Reader(); r != nil {
|
||||
return r.Definitions()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"mesh-grants/internal/grants"
|
||||
"sync/atomic"
|
||||
|
||||
stdio "git.novox.be/novox/mesh-sdk/go"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatlist"
|
||||
)
|
||||
|
||||
// The grants part composes from the seat list it reads (novox/hq ADR 0635 §1, ADR 0636 §1, D-30): through the seat
|
||||
// mesh-catalog's verb seat-definitions and its two events, from the bootstrapped definitions until the seat has answered. What
|
||||
// the reader holds is given to catalogue at every change, which composes every membership and grant, and a module that names a
|
||||
// seat the list does not yet is held back, as a manifest waiting for a judge is, and what runs is composed from its running
|
||||
// build's manifest. The process reads over its connection and the event hub; the tools' bundle over the runtime.
|
||||
|
||||
// seatListTools are the reader's two tools (ADR 0636 §7): every operator's session and the healers may read again. A call
|
||||
// through the mesh MCP server is proved only as its machine's tool runner (<node>.node-tools, issue 627), so node-tools
|
||||
// stands for an operator's session until a session is proved (issue 1966).
|
||||
var seatListAgainCallers = []string{stdio.AnyPerson, "node-tools", "mesh-healers"}
|
||||
|
||||
// seatGate is the reader the part gates by, set once it is started; before, it acts on nothing new.
|
||||
type seatGate struct {
|
||||
reader atomic.Pointer[seatlist.Reader]
|
||||
}
|
||||
|
||||
func (g *seatGate) MayAct(seats ...string) bool {
|
||||
r := g.reader.Load()
|
||||
return r != nil && r.MayAct(seats...)
|
||||
}
|
||||
|
||||
// Definitions are the seat definitions the reader holds: what the part makes each kept event's stream from.
|
||||
func (g *seatGate) Definitions() map[string]seatdef.Definition {
|
||||
if r := g.reader.Load(); r != nil {
|
||||
return r.Definitions()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// follow starts the reader over bus: what it holds is given to catalogue at once and at every change, and changed is called
|
||||
// then (a pass composes again).
|
||||
func (g *seatGate) follow(bus seatlist.Bus, changed func(), logf func(string, ...any)) *seatlist.Reader {
|
||||
reader, err := seatlist.Start(seatlist.Config{Bus: bus, Bootstrap: seatlist.Bootstrapped(),
|
||||
OnChange: func(seats []catalogue.Seat) {
|
||||
catalogue.UseSeats(seats)
|
||||
if changed != nil {
|
||||
changed()
|
||||
}
|
||||
}})
|
||||
if err != nil {
|
||||
logf("the grants part cannot follow its seat list, so it composes only the modules the bootstrapped seats name: %v", err)
|
||||
}
|
||||
if reader != nil {
|
||||
catalogue.UseSeats(reader.Seats())
|
||||
g.reader.Store(reader)
|
||||
}
|
||||
return reader
|
||||
}
|
||||
|
||||
// eventsLive is called when the part's own consumer on EVENTS is heard. A seat that was silent at the part's start may have said it
|
||||
// speaks before that consumer existed, which starts at the stream's end, so its event is never heard: while the list is unread the
|
||||
// part reads it now (ADR 0636 §1), on a goroutine of its own so the pass is not held; the reader changes the catalogue and wakes
|
||||
// the part when the seat answers, and stays unread, to be read at the seat's next event, when it does not.
|
||||
func (g *seatGate) eventsLive() {
|
||||
if r := g.reader.Load(); r != nil {
|
||||
r.ReloadIfUnread()
|
||||
}
|
||||
}
|
||||
|
||||
// tools are the two tools over whatever reader the gate holds at the call.
|
||||
func (g *seatGate) tools() []stdio.Tool {
|
||||
names := []string{grants.ToolSeatList, grants.ToolSeatListAgain}
|
||||
shape := seatlist.Tools(&seatlist.Reader{}, names[0], names[1], seatListAgainCallers)
|
||||
for i := range shape {
|
||||
run := i
|
||||
shape[i].Run = func(args map[string]any) (any, error) {
|
||||
r := g.reader.Load()
|
||||
if r == nil {
|
||||
return nil, errors.New("the seat list reader has not started yet: the runtime has not served this module")
|
||||
}
|
||||
return seatlist.Tools(r, names[0], names[1], seatListAgainCallers)[run].Run(args)
|
||||
}
|
||||
}
|
||||
return shape
|
||||
}
|
||||
@@ -266,14 +266,14 @@ func recordHandAct(what, why string) error {
|
||||
// serveTools serves the tools to the runtime until it stops.
|
||||
func serveTools() error {
|
||||
tv := &toolViews{}
|
||||
gate := &seatGate{}
|
||||
gate := newSeatGate()
|
||||
p := &grants.Part{Read: runtimeReader{views: tv}, Call: runtimeBus{}, Store: runtimeStore{}, Emit: runtimeBus{}, SeatList: gate}
|
||||
// The reader asks through the runtime, which serves once Serve has its channel.
|
||||
go func() {
|
||||
<-stdio.Served()
|
||||
gate.follow(seatlist.StdioBus(), nil, func(f string, a ...any) { fmt.Fprintf(os.Stderr, "mesh-grants: "+f+"\n", a...) })
|
||||
gate.Follow(seatlist.StdioBus(), nil, func(f string, a ...any) { fmt.Fprintf(os.Stderr, "mesh-grants: "+f+"\n", a...) })
|
||||
}()
|
||||
tools := append(toolsOf(p), gate.tools()...)
|
||||
tools := append(toolsOf(p), gate.Tools()...)
|
||||
for i := range tools {
|
||||
run := tools[i].Run
|
||||
tools[i].Run = func(a map[string]any) (any, error) { tv.fresh(); return run(a) }
|
||||
|
||||
Reference in New Issue
Block a user