The switch to release 6 is today's controller's last plan, and the bus runs the user list it composes until the new controller writes one: so the new controller's writes of each node's compositions and their digests, each new node-engine's reads of its own compositions and wants and its backup holder's verbs and word, and the assigner's read of the digests must be granted by this controller already (ADR 0539 clauses 2, 6, 9 and 16; the review's A1).
83 lines
3.3 KiB
Go
83 lines
3.3 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 packages each node declares
|
|
// among them, which the pacman module reads, ADR 0507 §5), the chain's buckets and the grants issued, which the assigner
|
|
// reads (ADR 0528 clause 2).
|
|
var controllerReadable = []string{MirrorAssignments, MirrorDeclaredConfig, MirrorPredefined, ChainBuilds, ChainRollouts,
|
|
MirrorDeclaredPackages, ControllerGrants, ControllerComposed}
|
|
|
|
// 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
|
|
}
|