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<()> {
let plugin = NativePluginLoader::load("target/release/libmy_plugin.so")?;
let response = plugin.call("echo", r#"{"message": "Hello"}"#)?;
println!("Response: {response}");
Ok(())
}
Loading from a Bundle
use rustbridge_consumer::{NativePluginLoader, PluginConfig, ConsumerResult};
fn main() -> ConsumerResult<()> {
let config = PluginConfig::default();
let plugin = NativePluginLoader::load_bundle_with_config(
"my-plugin-1.0.0.rbp",
&config,
None, )?;
let response: MyResponse = plugin.call_typed("my.handler", &MyRequest { ... })?;
Ok(())
}
With Logging
use rustbridge_consumer::{NativePluginLoader, LogCallbackFn};
use rustbridge_core::LogLevel;
fn main() -> ConsumerResult<()> {
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),
)?;
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")?;
if plugin.has_binary_transport() {
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