rustchain/core/
plugin.rs

1use crate::core::{RuntimeContext, Result};
2use std::collections::{HashMap, HashSet};
3
4/// Enterprise plugin trait for runtime feature extension
5/// This enables clean separation between community and enterprise features
6pub trait EnterprisePlugin: Send + Sync {
7    /// Plugin identification
8    fn name(&self) -> &str;
9    
10    /// Initialize plugin with the runtime context
11    fn initialize(&mut self, context: &mut RuntimeContext) -> Result<()>;
12    
13    /// List of features this plugin provides
14    fn features(&self) -> Vec<String>;
15    
16    /// Cleanup when plugin is unloaded
17    fn shutdown(&mut self) -> Result<()>;
18    
19    /// Plugin version for compatibility checking
20    fn version(&self) -> &str {
21        "1.0.0"
22    }
23    
24    /// Check if plugin is compatible with runtime version
25    fn is_compatible(&self, runtime_version: &str) -> bool {
26        // Simple compatibility check - can be enhanced
27        runtime_version.starts_with("0.1") || runtime_version.starts_with("1.")
28    }
29}
30
31/// Plugin manager for loading and managing enterprise plugins
32pub struct PluginManager {
33    plugins: HashMap<String, Box<dyn EnterprisePlugin>>,
34    enabled_features: HashSet<String>,
35    runtime_version: String,
36}
37
38impl PluginManager {
39    pub fn new() -> Self {
40        Self {
41            plugins: HashMap::new(),
42            enabled_features: HashSet::new(),
43            runtime_version: "0.1.0".to_string(),
44        }
45    }
46    
47    /// Register a plugin with the manager
48    pub fn register(&mut self, plugin: Box<dyn EnterprisePlugin>) -> Result<()> {
49        let name = plugin.name().to_string();
50        
51        // Check compatibility
52        if !plugin.is_compatible(&self.runtime_version) {
53            return Err(crate::core::error::RustChainError::Config(
54                crate::core::error::ConfigError::PluginError {
55                    message: format!("Plugin {} is not compatible with runtime version {}", 
56                                   name, self.runtime_version)
57                }
58            ));
59        }
60        
61        // Add features to enabled set
62        let features = plugin.features();
63        for feature in features {
64            self.enabled_features.insert(feature);
65        }
66        
67        self.plugins.insert(name, plugin);
68        Ok(())
69    }
70    
71    /// Initialize all registered plugins
72    pub fn initialize_all(&mut self, context: &mut RuntimeContext) -> Result<()> {
73        for (name, plugin) in self.plugins.iter_mut() {
74            plugin.initialize(context)
75                .map_err(|e| crate::core::error::RustChainError::Config(
76                    crate::core::error::ConfigError::PluginError {
77                        message: format!("Failed to initialize plugin {}: {}", name, e)
78                    }
79                ))?;
80        }
81        Ok(())
82    }
83    
84    /// Check if a feature is enabled through plugins
85    pub fn has_feature(&self, feature: &str) -> bool {
86        self.enabled_features.contains(feature)
87    }
88    
89    /// Get list of all enabled features
90    pub fn enabled_features(&self) -> Vec<String> {
91        self.enabled_features.iter().cloned().collect()
92    }
93    
94    /// Get list of loaded plugin names
95    pub fn loaded_plugins(&self) -> Vec<String> {
96        self.plugins.keys().cloned().collect()
97    }
98    
99    /// Shutdown all plugins
100    pub fn shutdown_all(&mut self) -> Result<()> {
101        let mut errors = Vec::new();
102        
103        for (name, plugin) in self.plugins.iter_mut() {
104            if let Err(e) = plugin.shutdown() {
105                errors.push(format!("Plugin {} shutdown error: {}", name, e));
106            }
107        }
108        
109        if !errors.is_empty() {
110            return Err(crate::core::error::RustChainError::Config(
111                crate::core::error::ConfigError::PluginError {
112                    message: format!("Plugin shutdown errors: {}", errors.join("; "))
113                }
114            ));
115        }
116        
117        self.plugins.clear();
118        self.enabled_features.clear();
119        Ok(())
120    }
121}
122
123impl Default for PluginManager {
124    fn default() -> Self {
125        Self::new()
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use crate::core::RuntimeContext;
133
134    struct MockPlugin {
135        name: String,
136        features: Vec<String>,
137        initialized: bool,
138    }
139    
140    impl MockPlugin {
141        fn new(name: &str, features: Vec<&str>) -> Self {
142            Self {
143                name: name.to_string(),
144                features: features.into_iter().map(|s| s.to_string()).collect(),
145                initialized: false,
146            }
147        }
148    }
149    
150    impl EnterprisePlugin for MockPlugin {
151        fn name(&self) -> &str {
152            &self.name
153        }
154        
155        fn initialize(&mut self, _context: &mut RuntimeContext) -> Result<()> {
156            self.initialized = true;
157            Ok(())
158        }
159        
160        fn features(&self) -> Vec<String> {
161            self.features.clone()
162        }
163        
164        fn shutdown(&mut self) -> Result<()> {
165            self.initialized = false;
166            Ok(())
167        }
168    }
169
170    #[test]
171    fn test_plugin_manager_creation() {
172        let manager = PluginManager::new();
173        assert_eq!(manager.loaded_plugins().len(), 0);
174        assert_eq!(manager.enabled_features().len(), 0);
175    }
176    
177    #[test]
178    fn test_plugin_registration() {
179        let mut manager = PluginManager::new();
180        let plugin = Box::new(MockPlugin::new("test", vec!["feature1", "feature2"]));
181        
182        assert!(manager.register(plugin).is_ok());
183        assert_eq!(manager.loaded_plugins().len(), 1);
184        assert_eq!(manager.enabled_features().len(), 2);
185        assert!(manager.has_feature("feature1"));
186        assert!(manager.has_feature("feature2"));
187        assert!(!manager.has_feature("feature3"));
188    }
189    
190    #[test]
191    fn test_plugin_initialization() {
192        let mut manager = PluginManager::new();
193        let plugin = Box::new(MockPlugin::new("test", vec!["feature1"]));
194        
195        manager.register(plugin).unwrap();
196        
197        let mut context = RuntimeContext::new();
198        assert!(manager.initialize_all(&mut context).is_ok());
199    }
200    
201    #[test]
202    fn test_plugin_shutdown() {
203        let mut manager = PluginManager::new();
204        let plugin = Box::new(MockPlugin::new("test", vec!["feature1"]));
205        
206        manager.register(plugin).unwrap();
207        assert_eq!(manager.loaded_plugins().len(), 1);
208        
209        assert!(manager.shutdown_all().is_ok());
210        assert_eq!(manager.loaded_plugins().len(), 0);
211        assert_eq!(manager.enabled_features().len(), 0);
212    }
213}