package process import ( "encoding/json" "fmt" "github.com/nats-io/nats.go" "git.novox.be/novox/mesh-sdk/go/announce" ) // Keeps says on the bus, as this process's module, every state it keeps and which of them others may read (novox/hq // ADR 0495 clause 2; issue 1790), on announce.Subject; what a reader is granted is what the owner announced (clause 3). // It publishes at once and again after every reconnect, so the controller hears it whenever it missed it. From then on // a state of the module 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 (c *Conn) Keeps(states ...announce.State) error { if err := c.remember(states); err != nil { return err } c.mu.Lock() first := !c.reannounces c.reannounces = true c.mu.Unlock() if first { before := c.nc.Opts.ReconnectedCB c.nc.SetReconnectHandler(func(nc *nats.Conn) { if before != nil { before(nc) } _ = c.publishKeeps() }) } return c.publishKeeps() } // remember makes the announcement of states and binds only them from now on. func (c *Conn) remember(states []announce.State) error { data, err := announce.Encode(announce.States{Module: c.account.Module, Node: c.account.Node, States: states}) if err != nil { return err } names := map[string]bool{} for _, s := range states { names[s.Name] = true } c.mu.Lock() c.kept, c.announced = names, data c.mu.Unlock() return nil } func (c *Conn) publishKeeps() error { c.mu.Lock() data := c.announced c.mu.Unlock() if err := c.Emit(announce.Event, json.RawMessage(data)); err != nil { return fmt.Errorf("announcing what %s keeps: %w", c.account.Module, err) } return nil } // refusedUnannounced is the error of a bind of a state Keeps did not name, or nil (also before Keeps). func (c *Conn) refusedUnannounced(name string) error { c.mu.Lock() defer c.mu.Unlock() if c.kept != nil && !c.kept[name] { return fmt.Errorf("the state %q is not among the states %s announced it keeps (Conn.Keeps)", name, c.account.Module) } return nil }