82 lines
3.1 KiB
Go
82 lines
3.1 KiB
Go
package broker
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/announce"
|
|
)
|
|
|
|
// Who may read a module's state is what the module announced (novox/hq ADR 0495 clauses 2 and 3, ADR 0513 §3; issue
|
|
// 1790). A module says on the bus which states it keeps and which others may read (announce.Subject); the controller
|
|
// keeps the last word of each (announce.KeptBucket) and grants a reader's `reads: <owner>.<name>` only when the owner
|
|
// announced that state readable. An owner that has announced nothing yet is read as before, from the reader's `reads`
|
|
// (the transition, until every module announces), and is named as not yet announced.
|
|
|
|
// StatesAnnouncedBucket is the controller's bucket of the last announcement of each module (announce.KeptBucket).
|
|
const StatesAnnouncedBucket = announce.KeptBucket
|
|
|
|
// controllerReadable are the controller's states others may read: the record mirrors, the chain's buckets, the checks
|
|
// running and the plans building.
|
|
var controllerReadable = []string{MirrorAssignments, MirrorDeclaredConfig, MirrorPredefined, ChainBuilds, ChainRollouts,
|
|
ChecksRunning, PlansBuilding}
|
|
|
|
// ControllerAnnouncement is what the controller announces it keeps (ADR 0495 clause 2): every bucket of its own by its local
|
|
// name, the ones others may read marked readable. It announces itself, as any module does from its code.
|
|
func ControllerAnnouncement(node string) announce.States {
|
|
s := announce.States{Module: ControllerSeat, Node: node}
|
|
readable := map[string]bool{}
|
|
for _, n := range controllerReadable {
|
|
readable[n] = true
|
|
}
|
|
for _, bucket := range ControllerBuckets() {
|
|
local, mine := strings.CutPrefix(bucket, ControllerSeat+"_")
|
|
if !mine {
|
|
continue
|
|
}
|
|
s.States = append(s.States, announce.State{Name: local, Readable: readable[local]})
|
|
}
|
|
sort.Slice(s.States, func(i, j int) bool { return s.States[i].Name < s.States[j].Name })
|
|
return s
|
|
}
|
|
|
|
// ReadsAnnounced splits a reader's `reads` (`<owner>.<name>`) by what each owner announced: granted when the owner
|
|
// announced the state readable, or announced nothing yet (the transition); refused when the owner announced and did
|
|
// not announce that state readable.
|
|
func ReadsAnnounced(reads []string, announced map[string]announce.States) (granted, refused []string) {
|
|
for _, r := range reads {
|
|
owner, name, ok := strings.Cut(r, ".")
|
|
s, said := announced[owner]
|
|
switch {
|
|
case !ok || !said || s.Readable(name):
|
|
granted = append(granted, r)
|
|
default:
|
|
refused = append(refused, r)
|
|
}
|
|
}
|
|
return granted, refused
|
|
}
|
|
|
|
// NotAnnounced are the owners some module reads the state of and that have announced nothing yet, sorted: read from the
|
|
// readers' `reads` as before, until they announce.
|
|
func NotAnnounced(r Records) []string {
|
|
seen := map[string]bool{}
|
|
var out []string
|
|
for _, ds := range r.Assigned {
|
|
for _, d := range ds {
|
|
for _, read := range append(append([]string(nil), d.Reads...), d.ReadsRefused...) {
|
|
owner, _, ok := strings.Cut(read, ".")
|
|
if !ok || seen[owner] {
|
|
continue
|
|
}
|
|
if _, said := r.Announced[owner]; !said {
|
|
seen[owner] = true
|
|
out = append(out, owner)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|