Files
mesh-sdk/go/delivery/noderecord.go
T
jschoubben 85ba0a9a70
mesh/delivery merged: source.main moved to novox/mesh-sdk@5a38a1221659
mesh/delivery-group group feat/l3-final merged: every member is merged
mesh/check pass 85ba0a9a70d8 on 52e564845e44 | unit 3760 run, 4992 kept, 56 skipped | integration 3841 run, 5103 kept, 59 skipped | over bound: unit, …
A node record states the reader capabilities its engine reads, a module value the ones its manifest needs, and a want of rule 9 or 10 reads (ADR 0614 §2, §4, issue 774)
NodeRecord.ManifestReads (`manifest-reads`) and Module.Needs (`needs`) are additive at Version 1, read leniently by
every running part. checkRule takes 1 to 10 so a later release may number the verb wait and the capability hold;
nothing writes 9 or 10 in this one. kept_until_delivered.go stays: this release still builds beside mesh-host 798d73e,
and its head comment names the next mesh-sdk release as the one that removes it.

Claude-Session: https://claude.ai/code/session_01JG73KG7AfSdh6FP8VrBqCn
2026-11-03 23:18:22 +01:00

112 lines
5.2 KiB
Go

package delivery
import (
"encoding/json"
"fmt"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A node's record is what the machine observes of itself (issue 1126, ADR 0555 §3), written by its own agent in its
// own have key, `<node>.node` of the node-engine's have bucket (HaveNode.Record), whenever an observed fact changes and
// only when the value differs. The key's change is the event its readers hear: every node and the parts that compose
// watch it. Where a module runs, and every fact a person decides of the node (its endpoint, site, hub, address on the
// private network, public domain, accounts, the tunnel found at adoption), are the catalogue's placement
// (placement.go). Nothing in it is secret: its keys are public halves.
// RecordTunnel is a tunnel found on a node when it was adopted, as compose.Tunnel holds it: public keys and addresses
// only. After the node took it over the tunnel is no longer there to observe, so it is kept as what was decided at
// adoption, in the node's placement (NodeDecided.Tunnel).
type RecordTunnel struct {
Interface string `json:"interface"`
Unit string `json:"unit,omitempty"`
Config string `json:"config,omitempty"`
Port int `json:"port,omitempty"`
MTU int `json:"mtu,omitempty"`
Address string `json:"address,omitempty"`
Range string `json:"range,omitempty"`
PublicKey string `json:"public-key,omitempty"`
Peers []RecordTunnelPeer `json:"peers,omitempty"`
}
// RecordTunnelPeer is one peer of a found tunnel.
type RecordTunnelPeer struct {
PublicKey string `json:"public-key"`
Address string `json:"address,omitempty"`
}
// NodeRecord is one node's record: what the machine observes of itself (issue 1126, ADR 0555: what a person decides
// lives in the catalogue's placement file, Placement.Decided; what the machine observes lives here). TunnelKey is the
// public key of its private-network tunnel; Certificate the one the mesh issued for its internal name, public, as the
// node holds it. The tunnel found at adoption and the names given to its peers are decisions kept in the placement;
// whether the hub took its found tunnel over, and which node enrolled under a carried peer's key, are read from both.
type NodeRecord struct {
V int `json:"v"`
Node string `json:"node"`
TunnelKey string `json:"tunnel-key,omitempty"`
Capabilities []string `json:"capabilities,omitempty"`
SealingKey string `json:"sealing-key,omitempty"`
ServingKey string `json:"serving-key,omitempty"`
Certificate string `json:"certificate,omitempty"`
OutwardLinks []string `json:"outward-links,omitempty"`
Networks []catalogue.AttachedNetwork `json:"networks,omitempty"`
NetworksSaid bool `json:"networks-said,omitempty"`
Contract int `json:"contract,omitempty"`
// Authority is the mesh's own certificate as this machine holds it (public): the one its declaration last wrote where
// a module asked for it. A node composing its own composes a certificate with it (compose.Input.Authority).
Authority string `json:"authority,omitempty"`
// Trusts is what this machine trusts a mesh signature from now (Trusts in signers.go, ADR 0550 §2): the controller's
// key until the lease is handed away, and the vault's key and authority once it reads them from `signers`. The gate
// before the lease write reads every node's from the bus.
Trusts []string `json:"trusts,omitempty"`
// ManifestReads are the reader capabilities of the shared contract this machine's node-engine is built with
// (catalogue.ManifestReads, novox/hq ADR 0614 §4): the manifest words, forms and seat names it reads. Empty for an
// engine built before it said them, which a reader takes as the baseline (catalogue.StatedManifestReads).
ManifestReads []string `json:"manifest-reads,omitempty"`
}
func (r NodeRecord) check() error {
if err := checkName("node", r.Node); err != nil {
return err
}
for _, c := range r.Capabilities {
if c == "" {
return fmt.Errorf("delivery: the record of %s names an empty capability", r.Node)
}
}
for _, c := range r.ManifestReads {
if c == "" {
return fmt.Errorf("delivery: the record of %s names an empty reader capability", r.Node)
}
}
return nil
}
// EncodeNodeRecord is r as JSON at Version; it refuses what DecodeNodeRecord refuses.
func EncodeNodeRecord(r NodeRecord) ([]byte, error) {
if err := r.check(); err != nil {
return nil, err
}
r.V = Version
return json.Marshal(r)
}
// DecodeNodeRecord reads a node record; it refuses an unknown version (ErrUnknownVersion), a node that is not a name, and
// an empty capability.
func DecodeNodeRecord(data []byte) (NodeRecord, error) {
var r NodeRecord
if err := decode(data, &r); err != nil {
return NodeRecord{}, err
}
if err := r.check(); err != nil {
return NodeRecord{}, err
}
return r, nil
}
// SameNodeRecord says whether two records are the same value, so the agent writes only when they differ.
func SameNodeRecord(a, b NodeRecord) bool {
a.V, b.V = 0, 0
return jsonEqual(a, b)
}