registry

package
v0.0.0-...-0c19b3a Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package registry manages all available node types and their factories.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func SignalReady

func SignalReady(ctx context.Context)

SignalReady invokes the ready callback embedded by WithReady, if any. Safe to call even if none was embedded (e.g. a unit test calling Start directly with a plain context.Background()) and safe to call more than once - the engine's own callback is idempotent, and a node need not track whether it already called this itself.

func WithReady

func WithReady(ctx context.Context, ready func()) context.Context

WithReady returns a copy of ctx carrying ready, retrievable via SignalReady. The engine embeds this into the context passed to an EagerlyReadyNode's Start, alongside the NodeRuntime from WithRuntime - see EagerlyReadyNode's doc comment in registry.go for why this exists.

func WithRuntime

func WithRuntime(ctx context.Context, rt *NodeRuntime) context.Context

WithRuntime returns a copy of ctx carrying rt, retrievable via RuntimeFromContext. Called by the engine when constructing the context it passes into a node's Execute/ExecuteMulti/Start.

Types

type Closeable

type Closeable interface {
	Close() error
}

Closeable is implemented by nodes that hold resources (open connections, timers, file handles, ...) which must be released when their flow is undeployed. The engine calls Close exactly once per node instance during Undeploy, after the flow's context has been cancelled and any Start goroutine (see EmittingNode) has returned.

type ContextStore

type ContextStore struct {
	// contains filtered or unexported fields
}

ContextStore is a thread-safe key-value store, mirroring Node-RED's flow/global context (`flow.get`/`flow.set`, `global.get`/`global.set`). The engine owns one global ContextStore shared by every flow; each active flow owns its own, private to that flow. Nodes reach both through NodeRuntime (see runtime.go).

func NewContextStore

func NewContextStore() *ContextStore

NewContextStore creates an empty ContextStore.

func (*ContextStore) Delete

func (s *ContextStore) Delete(key string)

Delete removes key from the store. It is a no-op if key is not present.

func (*ContextStore) Get

func (s *ContextStore) Get(key string) (interface{}, bool)

Get returns the value stored under key, and whether it was present.

func (*ContextStore) Keys

func (s *ContextStore) Keys() []string

Keys returns the currently stored keys, in no particular order.

func (*ContextStore) Set

func (s *ContextStore) Set(key string, value interface{})

Set stores value under key, overwriting any existing value.

type EagerlyReadyNode

type EagerlyReadyNode interface {
	EmittingNode

	// EagerlyReady is a marker method with no meaningful behavior of its
	// own - implementing it opts a node into the engine's ready-wait (see
	// startEmittingNodes). The node's real obligation is to call
	// SignalReady(ctx) synchronously, as the first thing Start does,
	// once its setup is complete.
	EagerlyReady()
}

EagerlyReadyNode is an optional marker an EmittingNode additionally implements to tell the engine: "my Start does synchronous setup - e.g. subscribing to this flow's EventBus - that other nodes' very first Execute call might race against, so wait for it before returning from Deploy." Without this, Deploy returns as soon as Start's goroutine has merely been launched, not run; a message injected immediately afterward (the common "deploy, then inject" sequence in tests and in any caller that doesn't add its own delay) can reach a node that publishes an event - e.g. NodeRuntime.ReportStatus, or the engine's own automatic error/complete events after every Execute - before a Catch/ Status/Complete node's Start has actually called OnError/OnStatus/ OnComplete to subscribe, silently dropping it (registry.EventBus has no replay/buffering for a subscriber that arrives late).

Implementing this interface only makes sense for a node whose readiness depends on order relative to *other nodes in the same flow*, not on an external event source (a TCP listener, an MQTT subscription, a filesystem watch): those originate their own events independently of this flow's message processing, so there's nothing for them to race against in the same "Deploy then inject" sequence, and requiring the engine to wait for them would only add needless latency to every Deploy. Implemented by catch/status/complete; SignalReady/WithReady live in ready.go.

type EmittingNode

type EmittingNode interface {
	NodeExecutor

	Start(ctx context.Context, emit func(payload map[string]interface{})) error
}

EmittingNode is implemented by nodes that originate messages on their own instead of only reacting to an incoming one (e.g. a TCP listener, an MQTT subscription, a file watcher). The engine invokes Start once, in its own goroutine, when the node's flow is deployed. Start must block until ctx is cancelled (which happens when the flow is undeployed) and call emit for every message it wants to inject at this node's output.

type EventBus

type EventBus struct {
	// contains filtered or unexported fields
}

EventBus is a simple, thread-safe pub/sub for flow-wide error, status, and completion events. Each active flow owns one. Handlers are called synchronously, in registration order, on the goroutine that published the event; handlers must not block for long or call back into the engine in a way that could deadlock (e.g. undeploying the same flow).

func NewEventBus

func NewEventBus() *EventBus

NewEventBus creates an empty EventBus.

func (*EventBus) OnComplete

func (b *EventBus) OnComplete(handler func(NodeCompleteEvent))

OnComplete registers a handler invoked for every published NodeCompleteEvent.

func (*EventBus) OnError

func (b *EventBus) OnError(handler func(NodeErrorEvent))

OnError registers a handler invoked for every published NodeErrorEvent.

func (*EventBus) OnStatus

func (b *EventBus) OnStatus(handler func(NodeStatusEvent))

OnStatus registers a handler invoked for every published NodeStatusEvent.

func (*EventBus) PublishComplete

func (b *EventBus) PublishComplete(evt NodeCompleteEvent)

PublishComplete notifies all registered complete handlers.

func (*EventBus) PublishError

func (b *EventBus) PublishError(evt NodeErrorEvent)

PublishError notifies all registered error handlers.

func (*EventBus) PublishStatus

func (b *EventBus) PublishStatus(evt NodeStatusEvent)

PublishStatus notifies all registered status handlers.

type MultiOutputExecutor

type MultiOutputExecutor interface {
	NodeExecutor

	// ExecuteMulti behaves like Execute but returns one payload per output
	// port ID (matching registry.Port.ID from the node's NodeMetadata.Outputs).
	// A port that is absent from the result, or mapped to nil, means: do not
	// send a message on that port for this invocation.
	ExecuteMulti(ctx interface{}, input map[string]interface{}) (map[string]map[string]interface{}, error)
}

MultiOutputExecutor is implemented by nodes that route different payloads to different output ports of the same node (e.g. a future Switch node picking one of several outputs, or a Catch/RBE node that may emit on no port at all for a given input). The engine calls ExecuteMulti instead of Execute when a node implements this interface.

type Node

type Node struct {
	Type     string
	Metadata NodeMetadata
	Factory  NodeFactory
}

Node represents a registered node type.

type NodeCompleteEvent

type NodeCompleteEvent struct {
	FlowID    string
	NodeID    string
	NodeType  string
	Payload   map[string]interface{}
	Timestamp time.Time
}

NodeCompleteEvent describes a node finishing a message successfully, published on a flow's EventBus so that Complete-style nodes can react to it. Payload is the message payload the node produced.

type NodeErrorEvent

type NodeErrorEvent struct {
	FlowID    string
	NodeID    string
	NodeType  string
	Err       error
	Payload   map[string]interface{}
	Timestamp time.Time
}

NodeErrorEvent describes a node execution failure, published on a flow's EventBus so that Catch-style nodes (docs/NODE_PALETTE_PLAN.md, Phase 1) can react to errors from other nodes without a normal wire connection. Payload is the message payload the failing node was processing (not the full engine message - this package cannot depend on internal/engine without an import cycle, since engine already depends on registry for NodeExecutor and friends).

type NodeExecutor

type NodeExecutor interface {
	// Execute processes the input message and returns output.
	// The context can be used for timeout and cancellation.
	Execute(ctx interface{}, input map[string]interface{}) (map[string]interface{}, error)

	// Validate checks the node configuration.
	// Should return an error if the configuration is invalid.
	Validate() error

	// GetConfig returns the current configuration as a map.
	GetConfig() map[string]interface{}

	// SetConfig sets the configuration from a map.
	// Should validate the configuration and return an error if invalid.
	SetConfig(config map[string]interface{}) error
}

NodeExecutor is the base interface for all nodes. Every node in Go—RED must implement this interface.

type NodeFactory

type NodeFactory func() NodeExecutor

NodeFactory is a function that creates a new NodeExecutor instance.

type NodeMetadata

type NodeMetadata struct {
	ID           string   `json:"id"`
	Type         string   `json:"type"`
	Name         string   `json:"name"`
	Description  string   `json:"description"`
	Category     string   `json:"category"`     // input, output, function, flow-control, storage
	Inputs       []Port   `json:"inputs"`       // Input ports
	Outputs      []Port   `json:"outputs"`      // Output ports
	ConfigSchema Schema   `json:"configSchema"` // Configuration schema
	Icon         string   `json:"icon"`         // SVG icon for UI
	Tags         []string `json:"tags"`         // Search tags
}

NodeMetadata contains metadata about a node type. This is used by the UI to display node information.

type NodeRegistry

type NodeRegistry struct {
	// contains filtered or unexported fields
}

NodeRegistry manages all registered node types.

func GetGlobalRegistry

func GetGlobalRegistry() *NodeRegistry

GetGlobalRegistry returns the global NodeRegistry instance.

func NewNodeRegistry

func NewNodeRegistry() *NodeRegistry

NewNodeRegistry creates a new NodeRegistry instance.

func (*NodeRegistry) GetAllNodes

func (r *NodeRegistry) GetAllNodes() []NodeMetadata

GetAllNodes returns metadata for all registered nodes.

func (*NodeRegistry) GetExecutor

func (r *NodeRegistry) GetExecutor(nodeType string) (NodeExecutor, error)

GetExecutor returns a new NodeExecutor instance for the given node type.

func (*NodeRegistry) GetMetadata

func (r *NodeRegistry) GetMetadata(nodeType string) (NodeMetadata, error)

GetMetadata returns the metadata for a node type.

func (*NodeRegistry) GetNodesByCategory

func (r *NodeRegistry) GetNodesByCategory(category string) []NodeMetadata

GetNodesByCategory returns nodes filtered by category.

func (*NodeRegistry) InitializeNode

func (r *NodeRegistry) InitializeNode(nodeType string, config map[string]interface{}) (NodeExecutor, error)

InitializeNode initializes a node with its configuration.

func (*NodeRegistry) IsRegistered

func (r *NodeRegistry) IsRegistered(nodeType string) bool

IsRegistered checks if a node type is registered.

func (*NodeRegistry) RegisterFactory

func (r *NodeRegistry) RegisterFactory(nodeType string, factory NodeFactory, metadata NodeMetadata) error

RegisterFactory registers a node factory with metadata. This is a convenience method that creates a Node and registers it.

func (*NodeRegistry) RegisterNode

func (r *NodeRegistry) RegisterNode(node *Node) error

RegisterNode registers a new node type.

func (*NodeRegistry) Unregister

func (r *NodeRegistry) Unregister(nodeType string) error

Unregister removes a node type from the registry.

type NodeRuntime

type NodeRuntime struct {
	FlowID        string
	NodeID        string
	NodeType      string
	FlowContext   *ContextStore
	GlobalContext *ContextStore
	// contains filtered or unexported fields
}

NodeRuntime gives a running node access to engine-level services that don't fit the input->output NodeExecutor.Execute contract: flow/global key-value context, error/status/complete event reporting and subscription (for Catch/Status/Complete nodes, docs/NODE_PALETTE_PLAN.md Phase 1), and submitting a message directly to another node in the same flow (for Link nodes). A node obtains it via RuntimeFromContext(ctx) inside Execute, ExecuteMulti, or Start - the engine embeds it into the context.Context it passes to all three.

func NewNodeRuntime

func NewNodeRuntime(flowID, nodeID, nodeType string, flowContext, globalContext *ContextStore, events *EventBus, submit func(nodeID string, payload map[string]interface{}), getNode func(nodeID string) (NodeExecutor, bool)) *NodeRuntime

NewNodeRuntime constructs a NodeRuntime. events, submit, and getNode may be nil (a runtime built for a context where no engine is backing it, e.g. a unit test); every method on NodeRuntime tolerates that.

func RuntimeFromContext

func RuntimeFromContext(ctx context.Context) (*NodeRuntime, bool)

RuntimeFromContext extracts the NodeRuntime embedded by the engine into a node's execution context, if any. Nodes running outside the engine (e.g. direct unit tests calling Execute with a plain context.Background()) will get ok == false and should treat runtime services as unavailable.

func (*NodeRuntime) GetNode

func (r *NodeRuntime) GetNode(nodeID string) (NodeExecutor, bool)

GetNode returns the live NodeExecutor instance for nodeID within this node's flow - used to reach a shared config node (e.g. an mqtt-broker's connection, a tls-config's certificate) referenced by ID from a node's own configuration (see docs/NODE_PALETTE_PLAN.md, Phase 6's config-node concept). Resolved lazily, at Execute/ExecuteMulti/Start call time rather than at SetConfig time, since Deploy initializes a flow's nodes by iterating a Go map (unordered) - a config node is not guaranteed to exist yet when a node referencing it is constructed, but every node exists by the time any Execute/Start call happens. A no-op returning (nil, false) if there is no backing engine or nodeID does not exist in this flow.

func (*NodeRuntime) OnComplete

func (r *NodeRuntime) OnComplete(handler func(NodeCompleteEvent))

OnComplete subscribes handler to every NodeCompleteEvent published on this node's flow. Used by Complete-style nodes. A no-op if there is no backing EventBus.

func (*NodeRuntime) OnError

func (r *NodeRuntime) OnError(handler func(NodeErrorEvent))

OnError subscribes handler to every NodeErrorEvent published on this node's flow, for the lifetime of the EventBus (typically the flow's deployment). Used by Catch-style nodes, normally from within EmittingNode.Start. A no-op if there is no backing EventBus.

func (*NodeRuntime) OnStatus

func (r *NodeRuntime) OnStatus(handler func(NodeStatusEvent))

OnStatus subscribes handler to every NodeStatusEvent published on this node's flow. Used by Status-style nodes. A no-op if there is no backing EventBus.

func (*NodeRuntime) ReportError

func (r *NodeRuntime) ReportError(err error)

ReportError publishes a NodeErrorEvent on behalf of this node, for non-fatal errors a node wants to surface to Catch nodes without failing the message it is currently processing (Execute/ExecuteMulti errors are already published automatically by the engine).

func (*NodeRuntime) ReportStatus

func (r *NodeRuntime) ReportStatus(status, detail string)

ReportStatus publishes a NodeStatusEvent on behalf of this node. Safe to call even if no Status node is listening.

func (*NodeRuntime) SubmitToNode

func (r *NodeRuntime) SubmitToNode(nodeID string, payload map[string]interface{})

SubmitToNode delivers payload directly to nodeID's output, as if nodeID had just produced it, bypassing the normal input->output wire of nodeID itself (used by Link nodes to jump to a Link In node elsewhere in the same flow without a drawn wire). A no-op if there is no backing engine or nodeID does not exist in this flow.

type NodeStatusEvent

type NodeStatusEvent struct {
	FlowID    string
	NodeID    string
	NodeType  string
	Status    string
	Detail    string
	Timestamp time.Time
}

NodeStatusEvent describes a node-reported status change (e.g. "connected", "disconnected", a progress message), published on a flow's EventBus so that Status-style nodes can react to it. Status is free-form and defined by the reporting node; the engine does not interpret it.

type Port

type Port struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	Required    bool   `json:"required"`
}

Port defines an input or output port for a node.

type Property

type Property struct {
	Type        string      `json:"type"` // string, number, boolean, object, array
	Description string      `json:"description"`
	Default     interface{} `json:"default"`
	Enum        []string    `json:"enum"` // Possible values for dropdowns
	Min         *float64    `json:"min"`
	Max         *float64    `json:"max"`
	Pattern     string      `json:"pattern"` // Regex pattern for strings
}

Property defines a configuration property for a node.

type Schema

type Schema struct {
	Properties map[string]Property `json:"properties"`
	Required   []string            `json:"required"`
}

Schema defines the configuration schema for a node.

Jump to

Keyboard shortcuts

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