| Crates.io | reinhardt-dentdelion |
| lib.rs | reinhardt-dentdelion |
| version | 0.1.0-alpha.1 |
| created_at | 2026-01-23 10:57:25.366554+00 |
| updated_at | 2026-01-23 10:57:25.366554+00 |
| description | Plugin system for Reinhardt framework - easy to create, distribute, and install |
| homepage | |
| repository | https://github.com/kent8192/reinhardt-web |
| max_upload_size | |
| id | 2064127 |
| size | 619,499 |
Plugin system for the Reinhardt framework - easy to create, distribute, and install.
Dentdelion (French for "lion's tooth" = dandelion) provides a comprehensive plugin architecture for extending Reinhardt applications. It supports both static plugins (Rust crates compiled into your application) and dynamic plugins (WebAssembly modules loaded at runtime).
on_load, on_enable, on_disable, on_unloadAdd reinhardt to your Cargo.toml:
[dependencies]
reinhardt = { version = "0.1.0-alpha.1", features = ["dentdelion"] }
# Or use a preset:
# reinhardt = { version = "0.1.0-alpha.1", features = ["standard"] } # Recommended
# reinhardt = { version = "0.1.0-alpha.1", features = ["full"] } # All features
Then import dentdelion features:
use reinhardt::dentdelion::prelude::*;
Note: Dentdelion features are included in the standard and full feature presets.
| Feature | Description |
|---|---|
default |
Core plugin system only |
wasm |
WebAssembly plugin support (requires wasmtime) |
cli |
CLI support for crates.io integration |
full |
All features enabled |
use reinhardt::dentdelion::prelude::*;
pub struct MyPlugin {
metadata: PluginMetadata,
}
impl MyPlugin {
pub fn new() -> Self {
Self {
metadata: PluginMetadata::builder("my-plugin", "1.0.0")
.description("My custom plugin")
.author("Your Name")
.build()
.unwrap(),
}
}
}
impl Plugin for MyPlugin {
fn metadata(&self) -> &PluginMetadata {
&self.metadata
}
fn capabilities(&self) -> &[Capability] {
&[
Capability::Core(PluginCapability::Middleware),
Capability::Core(PluginCapability::Commands),
]
}
}
use reinhardt::dentdelion::prelude::*;
use std::sync::Arc;
let mut registry = PluginRegistry::new();
// Register a plugin
let plugin = Arc::new(MyPlugin::new());
registry.register(plugin)?;
// Enable the plugin
registry.enable("my-plugin")?;
// Query plugins by capability
let middleware_plugins = registry.plugins_with_capability(&Capability::Core(PluginCapability::Middleware));
use reinhardt::dentdelion::prelude::*;
#[async_trait]
impl PluginLifecycle for MyPlugin {
async fn on_load(&self, ctx: &PluginContext) -> PluginResult<()> {
// Initialize resources
Ok(())
}
async fn on_enable(&self, ctx: &PluginContext) -> PluginResult<()> {
// Activate plugin features
Ok(())
}
async fn on_disable(&self, ctx: &PluginContext) -> PluginResult<()> {
// Deactivate plugin features
Ok(())
}
async fn on_unload(&self, ctx: &PluginContext) -> PluginResult<()> {
// Cleanup resources
Ok(())
}
}
The fundamental interface all plugins must implement:
pub trait Plugin: Send + Sync {
fn metadata(&self) -> &PluginMetadata;
fn capabilities(&self) -> &[Capability];
fn has_capability(&self, capability: &Capability) -> bool;
fn is_dynamic(&self) -> bool;
fn name(&self) -> &str;
fn version(&self) -> &semver::Version;
}
Standard capabilities that plugins can provide:
| Capability | Description | WASM Support |
|---|---|---|
Middleware |
HTTP middleware components | ✅ |
Models |
Database models and migrations | ❌ (Static only) |
Commands |
CLI management commands | ✅ |
ViewSets |
REST API ViewSets | ✅ |
Signals |
Custom signals | ✅ |
Services |
DI services | ✅ |
Auth |
Authentication backends | ✅ |
Templates |
Template engines or filters | ✅ |
StaticFiles |
Static file handling | ✅ |
Routing |
URL routing | ✅ |
SignalReceivers |
Signal receivers | ✅ |
Handlers |
HTTP handlers/views | ✅ |
NetworkAccess |
HTTP client for external requests | ✅ |
DatabaseAccess |
SQL query execution | ✅ |
Central plugin management:
Plugin identification information:
let metadata = PluginMetadata::builder("my-plugin", "1.0.0")
.description("My plugin description")
.author("Author Name")
.license("MIT")
.repository("https://github.com/example/my-plugin")
.add_dependency("other-plugin", ">=1.0.0")
.build()?;
Plugin configuration file:
[plugins]
my-plugin = { version = "1.0.0", enabled = true }
other-plugin = { version = "2.0.0", enabled = false }
[wasm]
plugins_dir = "plugins/"
memory_limit = 134217728 # 128MB
timeout_seconds = 30
wasm featuredentdelion-plugin WIT worldwit-bindgen or cargo-component for code generationDentdelion uses the WebAssembly Interface Types (WIT) standard for plugin interfaces. The complete interface is defined in wit/dentdelion.wit:
package reinhardt:dentdelion@0.1.0;
// Host functions available to plugins
interface host {
get-config: func(key: string) -> option<list<u8>>;
set-config: func(key: string, value: list<u8>) -> result<_, plugin-error>;
log-info: func(message: string);
log-warn: func(message: string);
log-error: func(message: string);
http-get: func(url: string, headers: list<tuple<string, string>>) -> result<http-response, plugin-error>;
db-query: func(sql: string, params: list<u8>) -> result<list<u8>, plugin-error>;
}
// Plugin functions that must be implemented
interface plugin {
get-metadata: func() -> plugin-metadata;
get-capabilities: func() -> list<capability>;
on-load: func(config: list<u8>) -> result<_, plugin-error>;
on-enable: func() -> result<_, plugin-error>;
on-disable: func() -> result<_, plugin-error>;
on-unload: func() -> result<_, plugin-error>;
}
use reinhardt::dentdelion::wasm::{WasmRuntime, WasmRuntimeConfigBuilder};
use std::time::Duration;
let config = WasmRuntimeConfigBuilder::new()
.memory_limit_mb(128)
.timeout(Duration::from_secs(30))
.fuel_metering(true)
.initial_fuel(100_000_000)
.build();
let runtime = WasmRuntime::new(config)?;
WASM plugins can access the following host functions:
| Category | Functions | Capability Required |
|---|---|---|
| Config | get_config, set_config |
None |
| Logging | log_debug, log_info, log_warn, log_error |
None |
| Services | register_service, get_service, unregister_service |
Services |
| HTTP | http_get, http_post |
NetworkAccess |
| Database | db_query, db_execute |
DatabaseAccess |
Data Serialization:
rmp-serde crate in Rust plugins for MessagePack serializationWASM plugins must declare required capabilities in their manifest:
[wasm.my-plugin]
capabilities = ["NetworkAccess", "DatabaseAccess"]
Host functions check capabilities at runtime:
http_get/http_post require NetworkAccess capabilitydb_query/db_execute require DatabaseAccess capabilityPluginError with code 403use reinhardt::dentdelion::wasm::{WasmPluginLoader, WasmRuntime};
use std::sync::Arc;
let runtime = Arc::new(WasmRuntime::new(Default::default())?);
let loader = WasmPluginLoader::new("plugins/", runtime);
// Discover .wasm files
let discovered = loader.discover().await?;
// Load and instantiate
for path in discovered {
let instance = loader.load(&path).await?;
// Initialize plugin
let ctx = PluginContext::default();
instance.on_load(&ctx).await?;
instance.on_enable(&ctx).await?;
}
WasmRuntimeConfig)When using the cli feature, the following commands are available:
# List installed plugins
reinhardt plugin list
# Show plugin details
reinhardt plugin info <name>
# Install from crates.io
reinhardt plugin install <name>
# Remove a plugin
reinhardt plugin remove <name>
# Enable/disable plugins
reinhardt plugin enable <name>
reinhardt plugin disable <name>
# Search crates.io
reinhardt plugin search <query>
# Update a plugin
reinhardt plugin update <name>
flowchart TB
subgraph Registry["PluginRegistry"]
plugins["plugins<br/>HashMap"]
capability["capability<br/>map"]
dependency["dependency_graph<br/>(topological)"]
end
Registry --> Static["Static Plugins<br/>(Rust crate)"]
Registry --> WASM["WASM Plugins<br/>(.wasm)"]
Registry --> Remote["Remote<br/>(crates.io)"]
reinhardt-commands: CLI command integrationreinhardt-di: Dependency injection for servicesreinhardt-middleware: Middleware integrationreinhardt-signals: Signal systemLicensed under the MIT license.