Documentation
¶
Overview ¶
The node registry: which bot nodes are connected, and how to reach one.
A bot node runs on someone's machine and dials in, holding a long-lived socket. That socket is the only way to reach it — you cannot spawn a rendezvous per request, because the node is already attached to one. This is that rendezvous.
Org is part of a node's identity, not a lookup filter ¶
The TypeScript registry this replaces keyed nodes by id alone (nodesById: Map<string, NodeSession>), with no tenant dimension anywhere in the type. Isolation was then a property of deployment — one shared singleton, per-viewer bearers, careful caching — rather than of the data structure.
Here a node is addressed by (org, nodeID). Two orgs may use the same node id and never see each other, and a lookup without an org cannot compile. That is the difference between multi-tenant and single-tenant-with-care.
Index ¶
- Variables
- type InvokeResult
- type NodeKey
- type Registry
- func (r *Registry) Answer(corrID string, res InvokeResult)
- func (r *Registry) Invoke(ctx context.Context, key NodeKey, frame func(corrID string) ([]byte, error), ...) (InvokeResult, error)
- func (r *Registry) List(org string) []*Session
- func (r *Registry) Register(s *Session) error
- func (r *Registry) Unregister(connID string)
- type Session
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNoSuchNode means no node with that id is connected FOR THAT ORG. It is // deliberately indistinguishable from "exists but belongs to another org": // telling those apart would leak the existence of another tenant's nodes. ErrNoSuchNode = errors.New("bot: no such node") // ErrInvokeTimeout means the node held the socket but did not answer. ErrInvokeTimeout = errors.New("bot: node invoke timed out") // ErrNodeGone means the socket closed while the call was in flight. ErrNodeGone = errors.New("bot: node disconnected mid-invoke") )
Errors a caller is expected to handle.
Functions ¶
This section is empty.
Types ¶
type InvokeResult ¶ added in v1.801.261
InvokeResult is what a node answered.
type NodeKey ¶ added in v1.801.261
NodeKey addresses a node. Both fields are required; there is no way to name a node without naming its tenant.
type Registry ¶ added in v1.801.261
type Registry struct {
// contains filtered or unexported fields
}
Registry tracks connected nodes and correlates in-flight invocations.
It is transport-agnostic on purpose: the WS layer registers a Session with a send func and feeds answers back by correlation id. Keeping the socket out of here is what lets the routing be tested without a network.
func NewRegistry ¶ added in v1.801.261
func NewRegistry() *Registry
func (*Registry) Answer ¶ added in v1.801.261
func (r *Registry) Answer(corrID string, res InvokeResult)
Answer delivers a node's reply to whoever is waiting on it.
An answer with no waiter is dropped rather than queued: it means the caller already timed out or went away, and holding it would only surface as a reply to an unrelated later call.
func (*Registry) Invoke ¶ added in v1.801.261
func (r *Registry) Invoke(ctx context.Context, key NodeKey, frame func(corrID string) ([]byte, error), timeout time.Duration) (InvokeResult, error)
Invoke sends a command to a node and waits for its answer.
The org comes from the caller's validated identity, never from the request body, so a caller cannot reach another tenant's node by naming it.
func (*Registry) List ¶ added in v1.801.261
List returns the nodes connected for one org, and only that org.
func (*Registry) Register ¶ added in v1.801.261
Register adds a connected node.
A second connection for the same (org, node) replaces the first and closes nothing: the old socket is simply no longer addressable. A node that reconnects after a network blip would otherwise be unreachable behind a dead entry until a timeout expired.
func (*Registry) Unregister ¶ added in v1.801.261
Unregister removes a node by its connection id, and fails every call still waiting on it. A pending invoke whose node has gone will never be answered; leaving it to time out would hold the caller for the full timeout on a question that is already unanswerable.
type Session ¶ added in v1.801.261
type Session struct {
Key NodeKey
ConnID string
DisplayName string
Platform string
Version string
Caps []string
Commands []string
Permissions map[string]bool
RemoteIP string
ConnectedAt time.Time
// contains filtered or unexported fields
}
Session is a connected node.