Documentation
¶
Overview ¶
Package registry manages all available node types and their factories.
Index ¶
- func SignalReady(ctx context.Context)
- func WithReady(ctx context.Context, ready func()) context.Context
- func WithRuntime(ctx context.Context, rt *NodeRuntime) context.Context
- type Closeable
- type ContextStore
- type EagerlyReadyNode
- type EmittingNode
- type EventBus
- func (b *EventBus) OnComplete(handler func(NodeCompleteEvent))
- func (b *EventBus) OnError(handler func(NodeErrorEvent))
- func (b *EventBus) OnStatus(handler func(NodeStatusEvent))
- func (b *EventBus) PublishComplete(evt NodeCompleteEvent)
- func (b *EventBus) PublishError(evt NodeErrorEvent)
- func (b *EventBus) PublishStatus(evt NodeStatusEvent)
- type MultiOutputExecutor
- type Node
- type NodeCompleteEvent
- type NodeErrorEvent
- type NodeExecutor
- type NodeFactory
- type NodeMetadata
- type NodeRegistry
- func (r *NodeRegistry) GetAllNodes() []NodeMetadata
- func (r *NodeRegistry) GetExecutor(nodeType string) (NodeExecutor, error)
- func (r *NodeRegistry) GetMetadata(nodeType string) (NodeMetadata, error)
- func (r *NodeRegistry) GetNodesByCategory(category string) []NodeMetadata
- func (r *NodeRegistry) InitializeNode(nodeType string, config map[string]interface{}) (NodeExecutor, error)
- func (r *NodeRegistry) IsRegistered(nodeType string) bool
- func (r *NodeRegistry) RegisterFactory(nodeType string, factory NodeFactory, metadata NodeMetadata) error
- func (r *NodeRegistry) RegisterNode(node *Node) error
- func (r *NodeRegistry) Unregister(nodeType string) error
- type NodeRuntime
- func (r *NodeRuntime) GetNode(nodeID string) (NodeExecutor, bool)
- func (r *NodeRuntime) OnComplete(handler func(NodeCompleteEvent))
- func (r *NodeRuntime) OnError(handler func(NodeErrorEvent))
- func (r *NodeRuntime) OnStatus(handler func(NodeStatusEvent))
- func (r *NodeRuntime) ReportError(err error)
- func (r *NodeRuntime) ReportStatus(status, detail string)
- func (r *NodeRuntime) SubmitToNode(nodeID string, payload map[string]interface{})
- type NodeStatusEvent
- type Port
- type Property
- type Schema
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SignalReady ¶
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 ¶
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 (*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.