Skip to main content

oxidite_plugin/
manager.rs

1use std::collections::HashMap;
2use std::path::Path;
3use std::sync::Arc;
4use oxidite_core::{Result, Error};
5
6use crate::{Plugin, PluginInfo, PluginHook, HookResult, PluginLoader, PluginConfig};
7
8/// Main plugin manager
9pub struct PluginManager {
10    plugins: HashMap<String, Arc<dyn Plugin>>,
11    config: PluginConfig,
12}
13
14impl PluginManager {
15    pub fn new(config: PluginConfig) -> Self {
16        Self {
17            plugins: HashMap::new(),
18            config,
19        }
20    }
21    
22    /// Load plugins from a directory
23    pub async fn load_plugins_from_directory<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
24        let loader = PluginLoader::new();
25        let loaded_plugins = loader.load_from_directory(path).await?;
26        for plugin in loaded_plugins {
27            self.register_plugin(plugin)?;
28        }
29
30        if self.config.enabled_plugins.is_empty() {
31            return Ok(());
32        }
33
34        for plugin_id in self.config.enabled_plugins.clone() {
35            let _ = self.enable_plugin(&plugin_id).await;
36        }
37        Ok(())
38    }
39    
40    /// Register a plugin
41    pub fn register_plugin(&mut self, plugin: Arc<dyn Plugin>) -> Result<()> {
42        let info = plugin.info();
43        
44        if self.plugins.contains_key(&info.id) {
45            return Err(Error::InternalServerError(
46                format!("Plugin with id '{}' already exists", info.id)
47            ));
48        }
49        
50        self.plugins.insert(info.id.clone(), plugin);
51        
52        Ok(())
53    }
54    
55    /// Enable a plugin
56    pub async fn enable_plugin(&mut self, plugin_id: &str) -> Result<()> {
57        if let Some(plugin) = self.plugins.get(plugin_id) {
58            plugin.on_enable().await?;
59            
60            // Update plugin info to enabled
61            // Note: In a real implementation, we'd need mutable access to update the info
62            
63            Ok(())
64        } else {
65            Err(Error::NotFound(format!("Plugin '{}' not found", plugin_id)))
66        }
67    }
68    
69    /// Disable a plugin
70    pub async fn disable_plugin(&mut self, plugin_id: &str) -> Result<()> {
71        if let Some(plugin) = self.plugins.get(plugin_id) {
72            plugin.on_disable().await?;
73            Ok(())
74        } else {
75            Err(Error::NotFound(format!("Plugin '{}' not found", plugin_id)))
76        }
77    }
78    
79    /// Execute a hook across all registered plugins
80    pub async fn execute_hook(&self, hook: PluginHook) -> Result<HookResult> {
81        let mut result = HookResult::Continue;
82        
83        for plugin in self.plugins.values() {
84            if !plugin.info().enabled {
85                continue;
86            }
87            
88            result = plugin.hook(hook.clone()).await;
89            
90            match result {
91                HookResult::Stop => break,
92                HookResult::Response(_) => return Ok(result),
93                HookResult::Error(_) => return Ok(result),
94                _ => continue,
95            }
96        }
97        
98        Ok(result)
99    }
100    
101    /// Get a list of all plugins
102    pub fn list_plugins(&self) -> Vec<PluginInfo> {
103        self.plugins.values()
104            .map(|p| p.info())
105            .collect()
106    }
107    
108    /// Initialize all enabled plugins
109    pub async fn initialize(&self) -> Result<()> {
110        for plugin in self.plugins.values() {
111            if plugin.info().enabled {
112                plugin.on_load().await?;
113            }
114        }
115        
116        Ok(())
117    }
118    
119    /// Shutdown all plugins
120    pub async fn shutdown(&self) -> Result<()> {
121        for plugin in self.plugins.values() {
122            plugin.on_unload().await?;
123        }
124        
125        Ok(())
126    }
127}
128
129/// Helper function to create a plugin manager
130pub fn create_manager(config: PluginConfig) -> PluginManager {
131    PluginManager::new(config)
132}