mesh_wait goes through the runner's approval gate (node-tools/internal/approval, Gate.Waited): a wait whose
subjects overlap a marked subject of any module the catalog half lists (the newest entry of every followed
branch, with the served entry of each module this runner serves) is an act of the runner's own module and
build (MESH_FINGERPRINT at its start), asked once on operator-channel as "Wait on <names> on <node>?", and
held, subscribing nothing but its ask's decided, until its timeout, its caller's going or the choice. On a
warrant it subscribes, its timeout running from then, and answers {answer, approval}. Before the marks are
read nothing is asked; a wait from a seat is never marked. The state fixture moves to meshtest so the
console's table can hold a gate.
Builds: design 34 every-event §34, §35, §36, §37; design 47 G lead answer A-168
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
88 lines
1.8 KiB
Go
88 lines
1.8 KiB
Go
package meshtest
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sort"
|
|
"sync"
|
|
|
|
stdio "git.novox.be/novox/mesh-sdk/go"
|
|
)
|
|
|
|
// State is a module's state as a fixture, the shape a gate's Store takes: Fail makes every read and write fail, as a bus
|
|
// refusing them; Vals are its values by key.
|
|
type State struct {
|
|
mu sync.Mutex
|
|
Vals map[string]json.RawMessage
|
|
revs map[string]uint64
|
|
n uint64
|
|
Fail error
|
|
}
|
|
|
|
// NewState is an empty State.
|
|
func NewState() *State { return &State{Vals: map[string]json.RawMessage{}, revs: map[string]uint64{}} }
|
|
|
|
func (m *State) Get(k string) (*stdio.StateEntry, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if m.Fail != nil {
|
|
return nil, m.Fail
|
|
}
|
|
v, ok := m.Vals[k]
|
|
if !ok {
|
|
return nil, nil
|
|
}
|
|
return &stdio.StateEntry{Key: k, Value: v, Revision: m.revs[k]}, nil
|
|
}
|
|
func (m *State) Create(k string, v any) (uint64, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if m.Fail != nil {
|
|
return 0, m.Fail
|
|
}
|
|
if _, ok := m.Vals[k]; ok {
|
|
return 0, stdio.ErrChanged
|
|
}
|
|
return m.put(k, v)
|
|
}
|
|
func (m *State) Update(k string, v any, rev uint64) (uint64, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if m.Fail != nil {
|
|
return 0, m.Fail
|
|
}
|
|
if rev == 0 || m.revs[k] != rev {
|
|
return 0, stdio.ErrChanged
|
|
}
|
|
return m.put(k, v)
|
|
}
|
|
func (m *State) Put(k string, v any) (uint64, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if m.Fail != nil {
|
|
return 0, m.Fail
|
|
}
|
|
return m.put(k, v)
|
|
}
|
|
func (m *State) Keys() ([]string, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if m.Fail != nil {
|
|
return nil, m.Fail
|
|
}
|
|
var out []string
|
|
for k := range m.Vals {
|
|
out = append(out, k)
|
|
}
|
|
sort.Strings(out)
|
|
return out, nil
|
|
}
|
|
func (m *State) put(k string, v any) (uint64, error) {
|
|
raw, ok := v.(json.RawMessage)
|
|
if !ok {
|
|
raw, _ = json.Marshal(v)
|
|
}
|
|
m.n++
|
|
m.Vals[k], m.revs[k] = raw, m.n
|
|
return m.n, nil
|
|
}
|