Skip to main content

SpoePlugin

pub trait SpoePlugin:
    Debug
    + Send
    + Sync {
    // Required methods
    fn init(&mut self, context: &PluginContext) -> RResult<(), RBoxError>;
    fn process(
        &self,
        message: &SpoeMessage,
    ) -> RResult<ProcessingResult, RBoxError>;
    fn name<'_self>(&'_self self) -> RStr<'_self>;
    fn version<'_self>(&'_self self) -> RStr<'_self>;
    fn shutdown(&self);

    // Provided methods
    fn config_schema(&self) -> ROption<RString> { ... }
    fn validate(&self, _: &PluginContext) -> RVec<Diagnostic> { ... }
}
Expand description

The trait that all SPOA hub plugins must implement.

Plugins are loaded as shared libraries at runtime. The hub calls init once after loading, then process for each SPOE message that matches the plugin’s configured message names.

§Thread Safety

Send + Sync is required because plugin instances are shared across connections via Arc. The process method takes &self, so plugins must use interior mutability for any mutable state.

§Panic Safety

Use the define_plugin! macro to implement plugins — it wraps process in catch_unwind to prevent panics from aborting the hub process.

Required Methods§

Source

fn init(&mut self, context: &PluginContext) -> RResult<(), RBoxError>

Initialize the plugin. Called once after loading.

The context provides the plugin name and any configuration parameters from the [plugins.params] TOML table. Use this to set up resources (database connections, lookup tables, etc.). Return RErr to abort plugin registration — the hub will log the error and skip this plugin.

Source

fn process(&self, message: &SpoeMessage) -> RResult<ProcessingResult, RBoxError>

Process an SPOE message and return transaction variables.

Called for each SPOE message that matches this plugin’s configured message names. The message contains pre-parsed typed arguments and connection metadata (stream/frame IDs).

When this plugin depends on another, the upstream plugin’s output variables are merged into message.args with their namespace-prefixed names (e.g., "ja3.hash").

Variable names in the result should be unprefixed — the hub adds the plugin namespace automatically.

Source

fn name<'_self>(&'_self self) -> RStr<'_self>

Human-readable plugin name used for logging and variable namespace prefixing.

Source

fn version<'_self>(&'_self self) -> RStr<'_self>

Semantic version string (e.g., "0.1.0"). Logged at plugin load time.

Source

fn shutdown(&self)

Called during hub shutdown. Use this to clean up resources (close file handles, flush buffers, disconnect from databases).

This is the last field in the current ABI version. Methods added in future minor versions will appear below this line with default implementations.

Provided Methods§

Source

fn config_schema(&self) -> ROption<RString>

Return a JSON Schema string to validate plugin configuration.

The hub calls this after new() and before init(). If RSome(schema) is returned, the hub parses the string as JSON Schema and validates the plugin’s [plugins.params] against it. Validation failure prevents init() from being called.

Return RNone (the default) to skip validation.

Source

fn validate(&self, _: &PluginContext) -> RVec<Diagnostic>

Deep validation of the plugin’s [plugins.params] subtree.

Called by the hub before init() (production mode) and by the validator sidecar in --validate-socket mode. Returns a list of Diagnostic findings; an empty list means “the plugin’s configuration is valid as far as this plugin can tell.”

§Purity contract

validate() MUST be pure: no tokio tasks, no goroutines, no network I/O, no file I/O beyond what the PluginContext carries, no global state mutation. Plugins MAY use process-internal caches scoped to plugin-instance lifetime. Side effects in validation would surface in the validator sidecar, which has no business contacting external services.

§Default behavior

The default impl returns an empty RVec, so existing plugins built against the prior plugin-api version continue to work unchanged. Plugins that want to surface line/column-precise errors at admission time (and in the production hub’s startup logs) override this method.

§Diagnostic.path

Plugins MUST leave the path field of returned diagnostics empty. The hub fills it post-hoc with the file identity it knows about. See Diagnostic for details.

See specs/004-validate-mode/ for the full design.

Implementors§

Source§

impl<'lt, _ErasedPtr> SpoePlugin for SpoePlugin_TO<'lt, _ErasedPtr>
where Self: Debug + Send + Sync, _ErasedPtr: AsMutPtr<PtrTarget = ()>,