Give modules the seat traffic and the contract to ask a person and answer on a channel (hq ADR 0259)
This commit is contained in:
+62
-1
@@ -64,6 +64,9 @@ type channel struct {
|
||||
subscribed int
|
||||
// watches are this bundle's state watches by the id each was asked with (ADR 0201).
|
||||
watches map[string]func(StateChange) error
|
||||
// takers and provers are this bundle's seat work and proof handlers, by worker and subject (ADR 0259).
|
||||
takers map[string]func(Work) error
|
||||
provers map[string]func(subject string, body json.RawMessage) (any, error)
|
||||
}
|
||||
|
||||
type listener struct {
|
||||
@@ -150,7 +153,8 @@ func ServeOn(name string, tools []Tool, in io.Reader, out io.Writer) error {
|
||||
for _, t := range tools {
|
||||
byName[t.Name] = t
|
||||
}
|
||||
c := &channel{enc: json.NewEncoder(out), waiting: map[string]chan message{}, watches: map[string]func(StateChange) error{}}
|
||||
c := &channel{enc: json.NewEncoder(out), waiting: map[string]chan message{}, watches: map[string]func(StateChange) error{},
|
||||
takers: map[string]func(Work) error{}, provers: map[string]func(string, json.RawMessage) (any, error){}}
|
||||
currentMu.Lock()
|
||||
current = c
|
||||
currentMu.Unlock()
|
||||
@@ -276,6 +280,63 @@ func ServeOn(name string, tools []Tool, in io.Reader, out io.Writer) error {
|
||||
}
|
||||
c.say(map[string]any{"id": id, "result": map[string]any{}})
|
||||
}(id, *p.Change)
|
||||
case "mesh/work":
|
||||
// One piece of a seat's work this bundle takes (novox/hq ADR 0259): taken by an answer that is
|
||||
// not an error, offered again after one. Beside the loop, like a tool call.
|
||||
var p struct {
|
||||
Work *Work `json:"work"`
|
||||
}
|
||||
if json.Unmarshal(m.Params, &p) != nil || p.Work == nil {
|
||||
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32602, "message": "mesh/work carries no work"}})
|
||||
continue
|
||||
}
|
||||
c.mu.Lock()
|
||||
handle := c.takers[p.Work.Worker]
|
||||
if handle == nil && len(c.takers) == 1 {
|
||||
for _, h := range c.takers {
|
||||
handle = h
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
go func(id any, w Work) {
|
||||
if handle == nil {
|
||||
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": "nothing here takes " + w.Subject}})
|
||||
return
|
||||
}
|
||||
if err := handle(w); err != nil {
|
||||
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": err.Error()}})
|
||||
return
|
||||
}
|
||||
c.say(map[string]any{"id": id, "result": map[string]any{}})
|
||||
}(id, *p.Work)
|
||||
case "mesh/proof":
|
||||
// One proof this bundle answers (novox/hq ADR 0259): what the handler returns is the answer; an
|
||||
// error is answered in words, never as silence.
|
||||
var p struct {
|
||||
Subject string `json:"subject"`
|
||||
Body json.RawMessage `json:"body"`
|
||||
}
|
||||
_ = json.Unmarshal(m.Params, &p)
|
||||
c.mu.Lock()
|
||||
var handle func(string, json.RawMessage) (any, error)
|
||||
for pattern, h := range c.provers {
|
||||
if subjectMatches(pattern, p.Subject) {
|
||||
handle = h
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
go func(id any, subject string, body json.RawMessage) {
|
||||
if handle == nil {
|
||||
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": "nothing here answers " + subject}})
|
||||
return
|
||||
}
|
||||
out, err := handle(subject, body)
|
||||
if err != nil {
|
||||
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32000, "message": err.Error()}})
|
||||
return
|
||||
}
|
||||
c.say(map[string]any{"id": id, "result": out})
|
||||
}(id, p.Subject, p.Body)
|
||||
default:
|
||||
if id != nil {
|
||||
c.say(map[string]any{"id": id, "error": map[string]any{"code": -32601, "message": "no " + m.Method}})
|
||||
|
||||
Reference in New Issue
Block a user