Files
mesh-tools/node-tools/internal/runtime/gate.go
T
jschoubben 14f464e8bc C1c-4: the tool runner sends a bundle's chunked seat answer in chunks, and a node's chunked verb is asked of the node
A seat verb whose definition says chunks, served by a bundle that answers the whole file as the member `file`, is sent by the
runner with buscalls.SeatChunks.Send and answered with the chunk count (Conn.AnswerChunked, called from serveSeats). A chunked verb
asked of one machine (`@<node>`) is received in chunks as the verb is.

Builds: design 47 G A-257, A-249, A-254, §681

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 09:43:08 +01:00

109 lines
4.2 KiB
Go

package runtime
import (
"fmt"
"strings"
"git.novox.be/novox/mesh-sdk/go/approval"
"git.novox.be/novox/mesh-sdk/go/seatdef"
"github.com/novox/mesh-tools/node-tools/internal/launch"
)
// FingerprintWord is the word of a module's composed environment that names the build its bundle serves (design 47 G §424).
const FingerprintWord = "MESH_FINGERPRINT"
// Gate is the approval gate the runner serves through (design 46 7-approval-mark §4, §20; node-tools/internal/approval).
type Gate interface {
// Unserved is, of a module's marked tools, those its bundle does not register, saying it as the module's finding.
Unserved(module, fingerprint string, registered []string) []string
// Run is a call through the gate: run is called only when the call may run now, once.
Run(call approval.Call, run func() (any, error)) (any, error)
}
// gatedRun is how a handler calls a tool: through the gate where there is one.
type gatedRun func(call approval.Call, t launch.Tool, caller string) (any, error)
// gated calls the tool through the gate, or straight where the runner has none.
func (c *consumers) gated(call approval.Call, t launch.Tool, caller string) (any, error) {
run := func() (any, error) { return t.Run(caller, call.Args) }
if c.gate == nil {
return run()
}
return c.gate.Run(call, run)
}
// WithGate serves every call through the approval gate.
func WithGate(g Gate) Option { return func(c *consumers) { c.gate = g } }
var _ Gate = (*approval.Gate)(nil)
// WithSeatDefinitions refuses, where a seat's verb is answered, a caller outside the verb's effective callers, before the
// bundle runs (design 47 G §610; lead answers A-165, A-179): defs are the seat definitions the runner's seat list holds.
// Without it a verb is answered for every caller, as before.
func WithSeatDefinitions(defs func() map[string]seatdef.Definition) Option {
return func(c *consumers) { c.definitions = defs }
}
// admitted says why a seat's verb is refused to a caller, nil when it is answered: an unproven caller is refused, and so is
// every caller while the seat's definition is not read, names no such verb, or the verb's effective callers are empty; a
// proven caller is among them, since the grants part composes a verb's call subject only for its effective callers (A-179).
func (c *consumers) admitted(seat, verb, caller string) error {
if c.definitions == nil {
return nil
}
if caller == "" {
return fmt.Errorf("Not run: %s.%s takes no unproven caller: call it on its subject that names its caller, "+
"mesh.seat.%s.call.%s.<caller>", seat, verb, seat, verb)
}
def, ok := c.definitions()[seat]
if !ok {
return fmt.Errorf("Not run: the definition of the seat %s is not yet read by this tool runner's seat list, so no caller "+
"of %s.%s is admitted", seat, seat, verb)
}
for _, v := range def.Verbs {
if v.Name == verb {
if len(v.EffectiveCallers()) == 0 {
return fmt.Errorf("Not run: %s.%s is open to no caller", seat, verb)
}
return nil
}
}
return fmt.Errorf("Not run: the seat %s's definition names no verb %s, so no caller is admitted", seat, verb)
}
// unservedMarks is, of the module's marked tools, those its bundle's registrations under its own name do not register.
func (r *runner) unservedMarks(module string, regs []launch.Registration) []string {
if r.events.gate == nil {
return nil
}
var registered []string
for _, reg := range regs {
if reg.Module == module {
for _, t := range reg.Tools {
registered = append(registered, t.Name)
}
}
}
return r.events.gate.Unserved(module, r.fingerprintOf(module), registered)
}
// chunked says whether key names a seat's verb whose definition says `chunks` (design 47 G A-249): its answer is received in
// chunks by the runner, whose call hands the bundle the whole.
func (c *consumers) chunked(key string) bool {
if c.definitions == nil || !strings.HasPrefix(key, "seat:") {
return false
}
name, _, _ := strings.Cut(key, "@") // a verb asked of the machine that ran the ask is chunked as the verb is (A-254)
seat, verb, ok := strings.Cut(strings.TrimPrefix(name, "seat:"), ".")
if !ok {
return false
}
for _, v := range c.definitions()[seat].Verbs {
if v.Name == verb {
return v.Chunks
}
}
return false
}