use std::collections::HashMap;
use std::path::Path;
use std::sync::Arc;
use oxidite_core::{Result, Error};
use crate::{Plugin, PluginInfo, PluginHook, HookResult, PluginLoader, PluginConfig};
pub struct PluginManager {
plugins: HashMap<String, Arc<dyn Plugin>>,
config: PluginConfig,
}
impl PluginManager {
pub fn new(config: PluginConfig) -> Self {
Self {
plugins: HashMap::new(),
config,
}
}
pub async fn load_plugins_from_directory<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
let loader = PluginLoader::new();
let loaded_plugins = loader.load_from_directory(path).await?;
for plugin in loaded_plugins {
self.register_plugin(plugin)?;
}
if self.config.enabled_plugins.is_empty() {
return Ok(());
}
for plugin_id in self.config.enabled_plugins.clone() {
let _ = self.enable_plugin(&plugin_id).await;
}
Ok(())
}
pub fn register_plugin(&mut self, plugin: Arc<dyn Plugin>) -> Result<()> {
let info = plugin.info();
if self.plugins.contains_key(&info.id) {
return Err(Error::InternalServerError(
format!("Plugin with id '{}' already exists", info.id)
));
}
self.plugins.insert(info.id.clone(), plugin);
Ok(())
}
pub async fn enable_plugin(&mut self, plugin_id: &str) -> Result<()> {
if let Some(plugin) = self.plugins.get(plugin_id) {
plugin.on_enable().await?;
Ok(())
} else {
Err(Error::NotFound(format!("Plugin '{}' not found", plugin_id)))
}
}
pub async fn disable_plugin(&mut self, plugin_id: &str) -> Result<()> {
if let Some(plugin) = self.plugins.get(plugin_id) {
plugin.on_disable().await?;
Ok(())
} else {
Err(Error::NotFound(format!("Plugin '{}' not found", plugin_id)))
}
}
pub async fn execute_hook(&self, hook: PluginHook) -> Result<HookResult> {
let mut result = HookResult::Continue;
for plugin in self.plugins.values() {
if !plugin.info().enabled {
continue;
}
result = plugin.hook(hook.clone()).await;
match result {
HookResult::Stop => break,
HookResult::Response(_) => return Ok(result),
HookResult::Error(_) => return Ok(result),
_ => continue,
}
}
Ok(result)
}
pub fn list_plugins(&self) -> Vec<PluginInfo> {
self.plugins.values()
.map(|p| p.info())
.collect()
}
pub async fn initialize(&self) -> Result<()> {
for plugin in self.plugins.values() {
if plugin.info().enabled {
plugin.on_load().await?;
}
}
Ok(())
}
pub async fn shutdown(&self) -> Result<()> {
for plugin in self.plugins.values() {
plugin.on_unload().await?;
}
Ok(())
}
}
pub fn create_manager(config: PluginConfig) -> PluginManager {
PluginManager::new(config)
}