Files
mesh-controller/modules/route-proxy/vendor/git.novox.be/novox/mesh-sdk/go/keeps.go
T

81 lines
2.3 KiB
Go

package stdio
import (
"encoding/json"
"fmt"
"os"
"strings"
"sync"
"git.novox.be/novox/mesh-sdk/go/announce"
)
// What this bundle said it keeps (novox/hq ADR 0495 clause 2; issue 1790).
var (
keepsMu sync.Mutex
kept map[string]bool // nil until Keeps: no state is refused then
announced []byte // the announcement, published once the bundle serves
)
// Keeps says on the bus, as this bundle's module, every state it keeps and which of them others may read (novox/hq
// ADR 0495 clause 2): what a reader is granted is what the owner announced (clause 3). Call it before Serve; the
// announcement is published through the runtime once the bundle serves, or at once when it already does. From then
// on a state of the module's own that it did not announce is refused at the call, naming it, so code and announcement
// cannot drift (clause 5). It refuses a state no bucket could be named by and a state given twice.
func Keeps(states ...announce.State) error {
module := os.Getenv("MESH_MODULE")
if module == "" {
module = os.Getenv(ServedAs)
}
data, err := announce.Encode(announce.States{Module: module, Node: os.Getenv("MESH_NODE"), States: states})
if err != nil {
return err
}
names := map[string]bool{}
for _, s := range states {
names[s.Name] = true
}
keepsMu.Lock()
kept, announced = names, data
keepsMu.Unlock()
currentMu.Lock()
serving := current != nil
currentMu.Unlock()
if serving {
return announce1()
}
return nil
}
// announce1 publishes the announcement Keeps made, if any.
func announce1() error {
keepsMu.Lock()
data := announced
keepsMu.Unlock()
if data == nil {
return nil
}
return Emit(announce.Event, json.RawMessage(data))
}
// refusedUnannounced is the error of a call on a state of the module's own that Keeps did not name, or nil. A read of
// another module's state (`<module>.<name>`) is the grant's business.
func refusedUnannounced(name string) error {
if strings.Contains(name, ".") {
return nil
}
keepsMu.Lock()
defer keepsMu.Unlock()
if kept != nil && !kept[name] {
return fmt.Errorf("the state %q is not among the states this module announced it keeps (stdio.Keeps)", name)
}
return nil
}
// forgetKeeps is for a test: nothing announced.
func forgetKeeps() {
keepsMu.Lock()
kept, announced = nil, nil
keepsMu.Unlock()
}