Read seat verbs' replaces from mesh-sdk's seat contract and seat holders from placement's seat-holders state, so the console asks the controller for neither (issue 1955, ADR 0571 clauses 4 and 5)
Pins mesh-sdk f9a496d. The controller's nodes and modules reads remain.
This commit is contained in:
@@ -17,6 +17,9 @@ package console
|
||||
// session — so a tool that arrived a minute ago is found without the client reconnecting.
|
||||
|
||||
import (
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -134,7 +137,11 @@ type index struct {
|
||||
// what it serves in time, or it answered before and not now. An address it might answer is never
|
||||
// called missing while it is here (2026-10-05).
|
||||
Unheard []unheard
|
||||
// Replaces is what each verb and tool replaces, from the controller's records (novox/hq ADR 0245):
|
||||
// Placed is the state seat-holders as the seat mesh-placement's holder wrote it (novox/hq ADR 0571 clause 4), by its
|
||||
// keys `<seat>` and `<seat>.<node>`, read with delivery.HoldersOf; PlacedWhy says why it could not be read.
|
||||
Placed map[string][]byte
|
||||
PlacedWhy string
|
||||
// Replaces is what each verb and tool replaces (novox/hq ADR 0245):
|
||||
// `seat:<seat>.<verb>` and `<module>.<tool>`.
|
||||
Replaces map[string][]string
|
||||
// Earlier is every runtime not heard this round whose last answer, within RuntimeForgotten, this
|
||||
@@ -283,18 +290,13 @@ type recordedMachine struct {
|
||||
func indexOn(conn *bus.Conn, held announce.Known, before func(announce.Discovery) []earlier) (*index, error) {
|
||||
var wg sync.WaitGroup
|
||||
var nodesOut, modulesOut string
|
||||
var toolsAnswer json.RawMessage
|
||||
var placed map[string][]byte
|
||||
var placedErr error
|
||||
wg.Add(3)
|
||||
go func() { defer wg.Done(); nodesOut, _ = controllerOutput(conn, "nodes") }()
|
||||
go func() { defer wg.Done(); modulesOut, _ = controllerOutput(conn, "modules") }()
|
||||
// The seats' verbs as the records define them, for what each replaces (novox/hq ADR 0245): answered
|
||||
// in-process from the records, never a command.
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if got, err := conn.Ask("seat:mesh-controller.tools", map[string]any{}, ""); err == nil {
|
||||
toolsAnswer = got.Result
|
||||
}
|
||||
}()
|
||||
// Who holds which seat on which node, from placement (ADR 0571 clause 4): no call of the controller.
|
||||
go func() { defer wg.Done(); placed, placedErr = seatHoldersOn(conn) }()
|
||||
d, err := announce.Gather(conn, held)
|
||||
wg.Wait()
|
||||
if err != nil {
|
||||
@@ -333,6 +335,10 @@ func indexOn(conn *bus.Conn, held announce.Known, before func(announce.Discovery
|
||||
l := x.Listing
|
||||
x.Discovery = d
|
||||
x.Stale, x.Earlier = stale, earlierAt
|
||||
x.Placed = placed
|
||||
if placedErr != nil {
|
||||
x.PlacedWhy = placedErr.Error()
|
||||
}
|
||||
for _, s := range d.Silent {
|
||||
x.Unheard = append(x.Unheard, unheard{Runtime: s.Name, Machine: s.Machine,
|
||||
Why: fmt.Sprintf("it answered PING; what it serves did not arrive within %s", announce.Patience)})
|
||||
@@ -342,7 +348,7 @@ func indexOn(conn *bus.Conn, held announce.Known, before func(announce.Discovery
|
||||
// a module with no tools is never a name here.
|
||||
var recorded []recordedModule
|
||||
recordedOK := json.Unmarshal([]byte(jsonIn(modulesOut)), &recorded) == nil
|
||||
x.Replaces = replacesOf(toolsAnswer, recorded)
|
||||
x.Replaces = replacesOf(catalogue.DefaultSeats(), recorded)
|
||||
if recordedOK {
|
||||
for _, m := range recorded {
|
||||
if !m.Tools {
|
||||
@@ -360,6 +366,10 @@ func indexOn(conn *bus.Conn, held announce.Known, before func(announce.Discovery
|
||||
} else {
|
||||
l.NotAnswering = append(l.NotAnswering, "mesh-controller (its records of the modules did not answer, so what is missing cannot be said)")
|
||||
}
|
||||
if x.PlacedWhy != "" {
|
||||
l.NotAnswering = append(l.NotAnswering, delivery.SeatHoldersRead+" (who holds which seat by placement could not be read: "+
|
||||
x.PlacedWhy+")")
|
||||
}
|
||||
for _, u := range x.Unheard {
|
||||
l.NotAnswering = append(l.NotAnswering, "the runtime "+sayUnheard([]unheard{u}))
|
||||
}
|
||||
@@ -381,6 +391,50 @@ func indexOn(conn *bus.Conn, held announce.Known, before func(announce.Discovery
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// seatHoldersOn reads the state seat-holders whole (novox/hq ADR 0571 clause 4): its current values, through the
|
||||
// runtime's own membership, which reads it as delivery.SeatHoldersRead.
|
||||
func seatHoldersOn(conn *bus.Conn) (map[string][]byte, error) {
|
||||
var mu sync.Mutex
|
||||
keys := map[string][]byte{}
|
||||
stop, err := conn.StateWatch(conn.Credential().Module, delivery.SeatHoldersRead, "", func(c bus.StateChange) error {
|
||||
if c.Current && c.Op == "put" {
|
||||
mu.Lock()
|
||||
keys[c.Key] = c.Value
|
||||
mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stop()
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
// placedHolders is who holds seat (on node, for a seat held per machine) by placement, or none.
|
||||
func (x *index) placedHolders(seat, node string) []delivery.SeatHolder {
|
||||
if len(x.Placed) == 0 {
|
||||
return nil
|
||||
}
|
||||
hs, err := delivery.HoldersOf(x.Placed, seat, node)
|
||||
if err != nil || len(hs) > 0 || node != "" {
|
||||
return hs
|
||||
}
|
||||
// A seat held per machine, asked without one: every node's key of it.
|
||||
var all []delivery.SeatHolder
|
||||
for key := range x.Placed {
|
||||
if s, n, ok := strings.Cut(key, "."); ok && s == seat {
|
||||
if more, err := delivery.HoldersOf(x.Placed, seat, n); err == nil {
|
||||
all = append(all, more...)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(all, func(i, j int) bool { return all[i].Node+"/"+all[i].Module < all[j].Node+"/"+all[j].Module })
|
||||
return all
|
||||
}
|
||||
|
||||
func containsHolder(hs []holder, h holder) bool {
|
||||
for _, x := range hs {
|
||||
if x == h {
|
||||
@@ -606,6 +660,14 @@ func resolve(x *index, address string) (target, error) {
|
||||
return target{}, fmt.Errorf("%s is assigned to %s in the mesh's records, but nothing that answered discovery serves it: %s. "+
|
||||
"Ask again in a moment; mesh_runtimes shows which runtimes answered", prefix, strings.Join(on, ", "), why)
|
||||
}
|
||||
if hs := x.placedHolders(prefix, node); len(hs) > 0 {
|
||||
var held []string
|
||||
for _, h := range hs {
|
||||
held = append(held, h.Module+" on "+h.Node)
|
||||
}
|
||||
return target{}, fmt.Errorf("the seat %s is held by %s by placement, but no holder of it announced itself on the bus. "+
|
||||
"Ask again in a moment; mesh_runtimes shows which runtimes answered", prefix, strings.Join(held, ", "))
|
||||
}
|
||||
if len(x.Unheard) > 0 {
|
||||
return target{}, fmt.Errorf("nothing that answered discovery is called %s, but not every runtime answered: %s — "+
|
||||
"%s may be theirs. Ask again in a moment; mesh_runtimes shows which runtimes answered", prefix, sayUnheard(x.Unheard), prefix)
|
||||
|
||||
Reference in New Issue
Block a user