rustbridge-consumer 1.0.1

Rust consumer for rustbridge plugins
Documentation

rustbridge-consumer

Rust consumer for dynamically loading and invoking rustbridge plugins.

Overview

This crate enables Rust applications to load and invoke rustbridge plugin bundles (.rbp files) or shared libraries at runtime. It provides the same functionality available to Java, Kotlin, C#, and Python consumers.

Key Features

  • Dynamic Loading: Load plugins at runtime without compile-time linking
  • Bundle Support: Load from .rbp bundles with automatic platform detection
  • JSON Transport: Make calls using JSON serialization
  • Binary Transport: High-performance binary struct transport (7x faster)
  • Lifecycle Management: Full OSGI-inspired lifecycle state machine
  • Logging Integration: Route plugin logs through host callbacks

Usage

Loading a Shared Library

use rustbridge_consumer::{NativePluginLoader, ConsumerResult};

fn main() -> ConsumerResult<()> {
    // Load plugin from shared library
    let plugin = NativePluginLoader::load("target/release/libmy_plugin.so")?;

    // Make a JSON call
    let response = plugin.call("echo", r#"{"message": "Hello"}"#)?;
    println!("Response: {response}");

    // Plugin is automatically shut down when dropped
    Ok(())
}

Loading from a Bundle

use rustbridge_consumer::{NativePluginLoader, PluginConfig, ConsumerResult};

fn main() -> ConsumerResult<()> {
    let config = PluginConfig::default();

    // Load from bundle (extracts library for current platform)
    let plugin = NativePluginLoader::load_bundle_with_config(
        "my-plugin-1.0.0.rbp",
        &config,
        None,  // No log callback
    )?;

    // Make typed calls with automatic serialization
    let response: MyResponse = plugin.call_typed("my.handler", &MyRequest { ... })?;

    Ok(())
}

With Logging

use rustbridge_consumer::{NativePluginLoader, LogCallbackFn};
use rustbridge_core::LogLevel;

fn main() -> ConsumerResult<()> {
    // Create a log callback
    let log_callback: LogCallbackFn = Box::new(|level, target, message| {
        println!("[{level}] {target}: {message}");
    });

    let plugin = NativePluginLoader::load_with_config(
        "target/release/libmy_plugin.so",
        &PluginConfig::default(),
        Some(log_callback),
    )?;

    // Plugin logs will now be routed to our callback
    Ok(())
}

Binary Transport

For performance-critical paths, use binary transport:

use rustbridge_consumer::NativePluginLoader;

fn main() -> ConsumerResult<()> {
    let plugin = NativePluginLoader::load("target/release/libmy_plugin.so")?;

    // Check if binary transport is available
    if plugin.has_binary_transport() {
        // Make binary call (message_id maps to registered handler)
        let response_bytes = plugin.call_raw(1, &request_bytes)?;
    }

    Ok(())
}

Plugin Lifecycle

Plugins follow an OSGI-inspired lifecycle:

Installed -> Starting -> Active -> Stopping -> Stopped
                           |
                      (any) -> Failed
  • Installed: Plugin loaded but not initialized
  • Starting: Plugin is initializing
  • Active: Plugin is ready to handle requests
  • Stopping: Plugin is shutting down
  • Stopped: Plugin has been shut down
  • Failed: Plugin encountered a fatal error

Error Handling

All operations return ConsumerResult<T> which wraps ConsumerError:

use rustbridge_consumer::{ConsumerError, ConsumerResult};

fn handle_plugin() -> ConsumerResult<()> {
    let plugin = NativePluginLoader::load("path/to/plugin.so")?;

    match plugin.call("handler", "{}") {
        Ok(response) => println!("Success: {response}"),
        Err(ConsumerError::NotActive(state)) => {
            println!("Plugin not active: {state:?}");
        }
        Err(ConsumerError::CallFailed(e)) => {
            println!("Call failed with code {}: {e}", e.error_code());
        }
        Err(e) => return Err(e),
    }

    Ok(())
}

License

MIT OR Apache-2.0