Skip to content

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