81 lines
2.3 KiB
Go
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()
|
|
}
|