Nerve Plugin System API
Comprehensive API documentation for the Nerve Framework plugin system.
Overview
The Nerve Plugin System provides a flexible and extensible architecture for adding custom functionality to the framework. This document covers the APIs for creating, managing, and integrating plugins.
Core Plugin API
Plugin Trait
/// Base trait that all plugins must implement
pub trait Plugin: Send + Sync {
/// Unique identifier for the plugin
fn name(&self) -> &str;
/// Plugin version
fn version(&self) -> &str;
/// Plugin description
fn description(&self) -> &str;
/// Initialize the plugin
fn initialize(&self, context: &PluginContext) -> Result<(), PluginError>;
/// Shutdown the plugin
fn shutdown(&self) -> Result<(), PluginError>;
/// Get plugin metadata
fn metadata(&self) -> PluginMetadata;
}
Plugin Context
/// Context provided to plugins during initialization
pub struct PluginContext {
/// System configuration
pub config: Arc<SystemConfig>,
/// Event bus for system events
pub event_bus: Arc<dyn EventBus>,
/// Logger instance
pub logger: Arc<dyn Logger>,
/// Metrics collector
pub metrics: Arc<dyn MetricsCollector>,
}
impl PluginContext {
/// Create a new plugin context
pub fn new(
config: Arc<SystemConfig>,
event_bus: Arc<dyn EventBus>,
logger: Arc<dyn Logger>,
metrics: Arc<dyn MetricsCollector>,
) -> Self {
Self {
config,
event_bus,
logger,
metrics,
}
}
/// Get system configuration
pub fn config(&self) -> &SystemConfig {
&self.config
}
/// Get event bus
pub fn event_bus(&self) -> &dyn EventBus {
&*self.event_bus
}
/// Get logger
pub fn logger(&self) -> &dyn Logger {
&*self.logger
}
/// Get metrics collector
pub fn metrics(&self) -> &dyn MetricsCollector {
&*self.metrics
}
}
Plugin Registry
/// Manages plugin lifecycle and registration
pub struct PluginRegistry {
plugins: HashMap<String, Arc<dyn Plugin>>,
initialized: bool,
}
impl PluginRegistry {
/// Create a new plugin registry
pub fn new() -> Self {
Self {
plugins: HashMap::new(),
initialized: false,
}
}
/// Register a plugin
pub fn register<P>(&mut self, plugin: P) -> Result<(), PluginError>
where
P: Plugin + 'static,
{
let name = plugin.name().to_string();
if self.plugins.contains_key(&name) {
return Err(PluginError::AlreadyRegistered(name));
}
self.plugins.insert(name, Arc::new(plugin));
Ok(())
}
/// Initialize all registered plugins
pub fn initialize_all(&mut self, context: &PluginContext) -> Result<(), PluginError> {
if self.initialized {
return Err(PluginError::AlreadyInitialized);
}
for (name, plugin) in &self.plugins {
plugin.initialize(context)
.map_err(|e| PluginError::InitializationFailed(name.clone(), e))?;
}
self.initialized = true;
Ok(())
}
/// Shutdown all plugins
pub fn shutdown_all(&mut self) -> Result<(), PluginError> {
if !self.initialized {
return Ok(());
}
let mut errors = Vec::new();
for (name, plugin) in &self.plugins {
if let Err(e) = plugin.shutdown() {
errors.push(PluginError::ShutdownFailed(name.clone(), e));
}
}
self.initialized = false;
if errors.is_empty() {
Ok(())
} else {
Err(PluginError::MultipleErrors(errors))
}
}
/// Get a plugin by name
pub fn get_plugin(&self, name: &str) -> Option<Arc<dyn Plugin>> {
self.plugins.get(name).cloned()
}
/// List all registered plugins
pub fn list_plugins(&self) -> Vec<PluginInfo> {
self.plugins
.values()
.map(|plugin| {
let metadata = plugin.metadata();
PluginInfo {
name: plugin.name().to_string(),
version: plugin.version().to_string(),
description: plugin.description().to_string(),
metadata,
}
})
.collect()
}
}
Plugin Types
Communication Plugin
/// Plugin for custom communication protocols
pub trait CommunicationPlugin: Plugin {
/// Create a new communication endpoint
fn create_endpoint(&self, config: &EndpointConfig) -> Result<Box<dyn CommunicationEndpoint>, PluginError>;
/// Supported protocol types
fn supported_protocols(&self) -> Vec<ProtocolType>;
}
Storage Plugin
/// Plugin for custom storage backends
pub trait StoragePlugin: Plugin {
/// Create a new storage instance
fn create_storage(&self, config: &StorageConfig) -> Result<Box<dyn StorageBackend>, PluginError>;
/// Supported storage types
fn supported_storage_types(&self) -> Vec<StorageType>;
}
Monitoring Plugin
/// Plugin for custom monitoring solutions
pub trait MonitoringPlugin: Plugin {
/// Create a new monitoring instance
fn create_monitor(&self, config: &MonitorConfig) -> Result<Box<dyn SystemMonitor>, PluginError>;
/// Supported metric types
fn supported_metrics(&self) -> Vec<MetricType>;
}
Authentication Plugin
/// Plugin for custom authentication mechanisms
pub trait AuthenticationPlugin: Plugin {
/// Create a new authenticator
fn create_authenticator(&self, config: &AuthConfig) -> Result<Box<dyn Authenticator>, PluginError>;
/// Supported authentication methods
fn supported_methods(&self) -> Vec<AuthMethod>;
}
Plugin Configuration
Plugin Configuration Structure
/// Configuration for plugin system
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginConfig {
/// Plugin directory path
pub plugin_dir: PathBuf,
/// Auto-load plugins
pub auto_load: bool,
/// Plugin-specific configurations
pub plugins: HashMap<String, PluginSpecificConfig>,
}
impl Default for PluginConfig {
fn default() -> Self {
Self {
plugin_dir: PathBuf::from("plugins"),
auto_load: false,
plugins: HashMap::new(),
}
}
}
Plugin Discovery
/// Discovers and loads plugins
pub struct PluginDiscovery {
plugin_dir: PathBuf,
}
impl PluginDiscovery {
/// Create a new plugin discovery instance
pub fn new(plugin_dir: PathBuf) -> Self {
Self { plugin_dir }
}
/// Discover available plugins
pub fn discover_plugins(&self) -> Result<Vec<DiscoveredPlugin>, PluginError> {
let mut plugins = Vec::new();
if !self.plugin_dir.exists() {
return Ok(plugins);
}
for entry in std::fs::read_dir(&self.plugin_dir)
.map_err(|e| PluginError::DiscoveryFailed(e.to_string()))?
{
let entry = entry.map_err(|e| PluginError::DiscoveryFailed(e.to_string()))?;
let path = entry.path();
if path.is_file() && is_plugin_file(&path) {
if let Some(plugin_info) = self.load_plugin_info(&path)? {
plugins.push(DiscoveredPlugin {
path,
info: plugin_info,
});
}
}
}
Ok(plugins)
}
/// Load plugin from file
pub fn load_plugin(&self, path: &Path) -> Result<Box<dyn Plugin>, PluginError> {
// Implementation for loading plugins from shared libraries
// or configuration files
todo!()
}
}
Plugin Lifecycle
Lifecycle Management
/// Manages plugin lifecycle states
pub struct PluginLifecycleManager {
registry: PluginRegistry,
discovery: PluginDiscovery,
state: PluginSystemState,
}
impl PluginLifecycleManager {
/// Create a new lifecycle manager
pub fn new(config: PluginConfig) -> Self {
Self {
registry: PluginRegistry::new(),
discovery: PluginDiscovery::new(config.plugin_dir),
state: PluginSystemState::Stopped,
}
}
/// Start the plugin system
pub fn start(&mut self, context: &PluginContext) -> Result<(), PluginError> {
if self.state != PluginSystemState::Stopped {
return Err(PluginError::InvalidState(self.state));
}
// Discover and load plugins
let discovered = self.discovery.discover_plugins()?;
for discovered_plugin in discovered {
let plugin = self.discovery.load_plugin(&discovered_plugin.path)?;
self.registry.register(plugin)?;
}
// Initialize all plugins
self.registry.initialize_all(context)?;
self.state = PluginSystemState::Running;
Ok(())
}
/// Stop the plugin system
pub fn stop(&mut self) -> Result<(), PluginError> {
if self.state != PluginSystemState::Running {
return Err(PluginError::InvalidState(self.state));
}
self.registry.shutdown_all()?;
self.state = PluginSystemState::Stopped;
Ok(())
}
/// Get current system state
pub fn state(&self) -> PluginSystemState {
self.state
}
}
Error Handling
Plugin Error Types
/// Plugin system error types
#[derive(Debug, thiserror::Error)]
pub enum PluginError {
#[error("Plugin '{0}' is already registered")]
AlreadyRegistered(String),
#[error("Plugin system is already initialized")]
AlreadyInitialized,
#[error("Plugin '{0}' failed to initialize: {1}")]
InitializationFailed(String, Box<dyn std::error::Error + Send + Sync>),
#[error("Plugin '{0}' failed to shutdown: {1}")]
ShutdownFailed(String, Box<dyn std::error::Error + Send + Sync>),
#[error("Plugin discovery failed: {0}")]
DiscoveryFailed(String),
#[error("Invalid plugin system state: {0:?}")]
InvalidState(PluginSystemState),
#[error("Multiple errors occurred: {0:?}")]
MultipleErrors(Vec<PluginError>),
#[error("Configuration error: {0}")]
ConfigurationError(String),
#[error("Plugin dependency error: {0}")]
DependencyError(String),
}
Plugin Development
Creating a Custom Plugin
/// Example custom plugin implementation
pub struct ExamplePlugin {
name: String,
version: String,
description: String,
}
impl ExamplePlugin {
/// Create a new example plugin
pub fn new() -> Self {
Self {
name: "example-plugin".to_string(),
version: "1.0.0".to_string(),
description: "An example plugin for demonstration".to_string(),
}
}
}
impl Plugin for ExamplePlugin {
fn name(&self) -> &str {
&self.name
}
fn version(&self) -> &str {
&self.version
}
fn description(&self) -> &str {
&self.description
}
fn initialize(&self, context: &PluginContext) -> Result<(), PluginError> {
context.logger().info("Example plugin initialized");
Ok(())
}
fn shutdown(&self) -> Result<(), PluginError> {
// Cleanup resources
Ok(())
}
fn metadata(&self) -> PluginMetadata {
PluginMetadata {
author: "Example Author".to_string(),
license: "MIT".to_string(),
dependencies: Vec::new(),
}
}
}
Plugin Dependencies
/// Manages plugin dependencies
pub struct DependencyManager {
dependencies: HashMap<String, DependencyInfo>,
}
impl DependencyManager {
/// Check if dependencies are satisfied
pub fn check_dependencies(
&self,
plugin: &dyn Plugin,
registry: &PluginRegistry,
) -> Result<(), PluginError> {
let metadata = plugin.metadata();
for dependency in &metadata.dependencies {
if !registry.get_plugin(&dependency.name).is_some() {
return Err(PluginError::DependencyError(
format!("Missing dependency: {}", dependency.name)
));
}
}
Ok(())
}
}
Integration Examples
Using Plugins in Applications
use nerve_plugin_system::{PluginRegistry, PluginContext, PluginLifecycleManager, PluginConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create plugin configuration
let plugin_config = PluginConfig {
plugin_dir: "plugins".into(),
auto_load: true,
plugins: HashMap::new(),
};
// Create plugin context
let context = PluginContext::new(
Arc::new(SystemConfig::default()),
Arc::new(EventBus::new()),
Arc::new(Logger::new()),
Arc::new(MetricsCollector::new()),
);
// Create and start plugin system
let mut plugin_manager = PluginLifecycleManager::new(plugin_config);
plugin_manager.start(&context)?;
// Use plugins in application
// ...
// Stop plugin system
plugin_manager.stop()?;
Ok(())
}
Plugin Configuration Example
# plugin-config.yaml
plugin_dir: "./plugins"
auto_load: true
plugins:
example-plugin:
enabled: true
config:
setting1: "value1"
setting2: 42
monitoring-plugin:
enabled: true
config:
metrics_interval: 5000
alert_threshold: 0.8
Performance Considerations
Plugin Performance
- Lazy Loading: Load plugins only when needed
- Resource Management: Properly manage plugin resources
- Concurrency: Ensure thread-safe plugin operations
- Memory Usage: Monitor plugin memory consumption
Optimization Tips
- Use efficient data structures in plugins
- Implement proper cleanup in shutdown methods
- Avoid blocking operations in plugin initialization
- Use async patterns for I/O operations
Security Considerations
Plugin Security
- Sandboxing: Consider running plugins in isolated environments
- Validation: Validate all plugin inputs and outputs
- Permissions: Implement fine-grained permission system
- Audit: Log all plugin activities for security auditing
Best Practices
- Verify plugin signatures before loading
- Use secure communication channels
- Implement proper error handling
- Regular security updates for plugins