diff --git a/src/plugins/bad-mod.rs b/src/plugins/bad-mod.rs deleted file mode 100644 index 21ae8cc..0000000 --- a/src/plugins/bad-mod.rs +++ /dev/null @@ -1,340 +0,0 @@ -//! Система плагинов для flusql с lock-free архитектурой -//! -//! Основные возможности: -//! - Lock-free обработка событий через каналы -//! - Песочница для плагинов Lua -//! - Поддержка хуков и событий -//! - Горячая перезагрузка плагинов -//! - Безопасная обработка ошибок -//! - Асинхронное выполнение задач - -mod traits; -mod channel; -mod sandbox; -mod worker; - -pub use traits::{ - PluginData, PluginState, EventHandler, HookHandler, - PluginEvent, EventType, PluginHook, PluginManagerTrait -}; -pub use channel::{ - PluginMessage, PluginChannels, HookResponse, LoadPluginResponse, - UnloadPluginResponse, ListPluginsResponse, GetPluginResponse, PluginInfo -}; -pub use sandbox::LuaSandbox; -pub use worker::PluginWorker; - -use std::sync::Arc; -use parking_lot::RwLock; -use mlua::Lua; -use serde_json::Value; - -/// Ошибки плагинов -#[derive(Debug, thiserror::Error)] -pub enum PluginError { - #[error("IO error: {0}")] - IoError(#[from] std::io::Error), - - #[error("Lua error: {0}")] - LuaError(String), - - #[error("Serialization error: {0}")] - SerializationError(#[from] serde_json::Error), - - #[error("Channel error: {0}")] - ChannelError(String), - - #[error("Plugin not found: {0}")] - PluginNotFound(String), - - #[error("Plugin already loaded: {0}")] - PluginAlreadyLoaded(String), - - #[error("Invalid plugin: {0}")] - InvalidPlugin(String), -} - -/// Реализация данных плагина -pub struct Plugin { - pub id: String, - pub name: String, - pub version: String, - pub description: String, - pub author: String, - pub path: String, - pub state: PluginState, - pub hooks: Vec, - pub lua_sandbox: Option>>, -} - -impl PluginData for Plugin { - fn id(&self) -> &str { - &self.id - } - - fn name(&self) -> &str { - &self.name - } - - fn version(&self) -> &str { - &self.version - } - - fn description(&self) -> &str { - &self.description - } - - fn author(&self) -> &str { - &self.author - } - - fn path(&self) -> &str { - &self.path - } - - fn state(&self) -> PluginState { - self.state - } -} - -/// Менеджер плагинов с lock-free архитектурой -pub struct PluginManager { - plugins: Arc>>>, - channels: PluginChannels, - worker: PluginWorker, -} - -impl PluginManager { - /// Создать новый менеджер плагинов - pub fn new() -> Self { - let channels = PluginChannels::new(); - let plugins = Arc::new(RwLock::new(Vec::new())); - - let worker = PluginWorker::new( - channels.clone(), - Arc::clone(&plugins), - ); - - // Запустить worker в фоновом потоке - worker.start(); - - Self { - plugins, - channels, - worker, - } - } - - /// Отправить событие (lock-free, через канал) - pub async fn emit_event(&self, event: PluginEvent) -> Result<(), PluginError> { - self.channels.send(PluginMessage::Event(event)) - .map_err(|e| PluginError::ChannelError(e)) - } - - /// Выполнить хук (lock-free, через канал) - pub async fn execute_hook(&self, hook_name: &str, data: Value) -> Result { - let (sender, receiver) = crossbeam::channel::bounded(1); - - self.channels.send(PluginMessage::HookRequest { - hook_name: hook_name.to_string(), - data, - response_sender: sender, - }).map_err(|e| PluginError::ChannelError(e))?; - - match receiver.recv() { - Ok(HookResponse::Success(result)) => Ok(result), - Ok(HookResponse::Error(err)) => Err(PluginError::LuaError(err)), - Ok(HookResponse::NoHandler) => Err(PluginError::InvalidPlugin("No handler found".to_string())), - Err(e) => Err(PluginError::ChannelError(format!("Failed to receive hook response: {}", e))), - } - } - - /// Загрузить плагин (lock-free, через канал) - pub async fn load_plugin(&self, path: &str) -> Result { - let (sender, receiver) = crossbeam::channel::bounded(1); - - self.channels.send(PluginMessage::LoadPlugin { - path: path.to_string(), - response_sender: sender, - }).map_err(|e| PluginError::ChannelError(e))?; - - match receiver.recv() { - Ok(LoadPluginResponse::Success(plugin_id)) => Ok(plugin_id), - Ok(LoadPluginResponse::Error(err)) => Err(PluginError::InvalidPlugin(err)), - Err(e) => Err(PluginError::ChannelError(format!("Failed to receive load response: {}", e))), - } - } - - /// Выгрузить плагин (lock-free, через канал) - pub async fn unload_plugin(&self, plugin_id: &str) -> Result<(), PluginError> { - let (sender, receiver) = crossbeam::channel::bounded(1); - - self.channels.send(PluginMessage::UnloadPlugin { - plugin_id: plugin_id.to_string(), - response_sender: sender, - }).map_err(|e| PluginError::ChannelError(e))?; - - match receiver.recv() { - Ok(UnloadPluginResponse::Success) => Ok(()), - Ok(UnloadPluginResponse::Error(err)) => Err(PluginError::InvalidPlugin(err)), - Err(e) => Err(PluginError::ChannelError(format!("Failed to receive unload response: {}", e))), - } - } - - /// Получить список плагинов (lock-free, через канал) - pub async fn list_plugins(&self) -> Result, PluginError> { - let (sender, receiver) = crossbeam::channel::bounded(1); - - self.channels.send(PluginMessage::ListPlugins { - response_sender: sender, - }).map_err(|e| PluginError::ChannelError(e))?; - - match receiver.recv() { - Ok(response) => Ok(response.plugins), - Err(e) => Err(PluginError::ChannelError(format!("Failed to receive list response: {}", e))), - } - } - - /// Получить информацию о плагине (lock-free, через канал) - pub async fn get_plugin(&self, plugin_id: &str) -> Result, PluginError> { - let (sender, receiver) = crossbeam::channel::bounded(1); - - self.channels.send(PluginMessage::GetPlugin { - plugin_id: plugin_id.to_string(), - response_sender: sender, - }).map_err(|e| PluginError::ChannelError(e))?; - - match receiver.recv() { - Ok(GetPluginResponse::Found(info)) => Ok(Some(info)), - Ok(GetPluginResponse::NotFound) => Ok(None), - Ok(GetPluginResponse::Error(err)) => Err(PluginError::InvalidPlugin(err)), - Err(e) => Err(PluginError::ChannelError(format!("Failed to receive get response: {}", e))), - } - } - - /// Загрузить все плагины из директории - pub async fn load_all_plugins(&self) -> Result, PluginError> { - use std::fs; - use std::path::Path; - - let plugins_dir = Path::new("./plugins"); - if !plugins_dir.exists() { - fs::create_dir_all(plugins_dir) - .map_err(PluginError::IoError)?; - return Ok(Vec::new()); - } - - let mut loaded = Vec::new(); - - for entry in fs::read_dir(plugins_dir) - .map_err(PluginError::IoError)? - { - let entry = entry.map_err(PluginError::IoError)?; - let path = entry.path(); - - if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("lua") { - if let Ok(plugin_id) = self.load_plugin(path.to_str().unwrap()).await { - loaded.push(plugin_id); - } - } - } - - Ok(loaded) - } - - /// Остановить менеджер плагинов - pub fn shutdown(&self) { - self.channels.send(PluginMessage::Shutdown) - .unwrap_or_else(|e| log::error!("Failed to send shutdown message: {}", e)); - - // Дожидаемся остановки worker - self.worker.shutdown(); - } -} - -impl PluginManagerTrait for PluginManager { - fn load_all_plugins(&mut self) -> Result>, String> { - // Для синхронного вызова используем tokio runtime - let rt = tokio::runtime::Runtime::new() - .map_err(|e| format!("Failed to create runtime: {}", e))?; - - rt.block_on(async { - self.load_all_plugins().await - .map_err(|e| e.to_string())?; - - let plugins = self.plugins.read(); - let result: Vec> = plugins - .iter() - .map(|p| p.clone() as Arc) - .collect(); - - Ok(result) - }) - } - - fn load_plugin(&mut self, path: &str) -> Result, String> { - let rt = tokio::runtime::Runtime::new() - .map_err(|e| format!("Failed to create runtime: {}", e))?; - - rt.block_on(async { - let plugin_id = self.load_plugin(path).await - .map_err(|e| e.to_string())?; - - let plugins = self.plugins.read(); - plugins.iter() - .find(|p| p.id == plugin_id) - .map(|p| p.clone() as Arc) - .ok_or_else(|| format!("Plugin not found after loading: {}", plugin_id)) - }) - } - - fn unload_plugin(&mut self, plugin_id: &str) -> Result<(), String> { - let rt = tokio::runtime::Runtime::new() - .map_err(|e| format!("Failed to create runtime: {}", e))?; - - rt.block_on(async { - self.unload_plugin(plugin_id).await - .map_err(|e| e.to_string()) - }) - } - - fn list_plugins(&self) -> Vec> { - let plugins = self.plugins.read(); - plugins.iter() - .map(|p| p.clone() as Arc) - .collect() - } - - fn get_plugin(&self, plugin_id: &str) -> Option> { - let plugins = self.plugins.read(); - plugins.iter() - .find(|p| p.id == plugin_id) - .map(|p| p.clone() as Arc) - } - - fn emit_event(&self, event: PluginEvent) -> Result<(), String> { - let rt = tokio::runtime::Runtime::new() - .map_err(|e| format!("Failed to create runtime: {}", e))?; - - rt.block_on(async { - self.emit_event(event).await - .map_err(|e| e.to_string()) - }) - } - - fn execute_hook(&self, hook_name: &str, data: Value) -> Result { - let rt = tokio::runtime::Runtime::new() - .map_err(|e| format!("Failed to create runtime: {}", e))?; - - rt.block_on(async { - self.execute_hook(hook_name, data).await - .map_err(|e| e.to_string()) - }) - } -} - -impl Drop for PluginManager { - fn drop(&mut self) { - self.shutdown(); - } -}