bot

package
v1.801.264 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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

type InvokeResult struct {
	OK      bool
	Payload []byte
	Code    string
	Message string
}

InvokeResult is what a node answered.

type NodeKey added in v1.801.261

type NodeKey struct {
	Org    string
	NodeID string
}

NodeKey addresses a node. Both fields are required; there is no way to name a node without naming its tenant.

func (NodeKey) String added in v1.801.261

func (k NodeKey) String() string

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

func (r *Registry) List(org string) []*Session

List returns the nodes connected for one org, and only that org.

func (*Registry) Register added in v1.801.261

func (r *Registry) Register(s *Session) error

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

func (r *Registry) Unregister(connID string)

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL