Delete src/plugins/bad-mod.rs
This commit is contained in:
parent
de119b9b15
commit
c5ec1d432b
@ -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<PluginHook>,
|
||||
pub lua_sandbox: Option<Arc<RwLock<LuaSandbox>>>,
|
||||
}
|
||||
|
||||
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<RwLock<Vec<Arc<Plugin>>>>,
|
||||
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<Value, PluginError> {
|
||||
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<String, PluginError> {
|
||||
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<Vec<PluginInfo>, 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<Option<PluginInfo>, 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<Vec<String>, 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<Vec<Arc<dyn PluginData>>, 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<Arc<dyn PluginData>> = plugins
|
||||
.iter()
|
||||
.map(|p| p.clone() as Arc<dyn PluginData>)
|
||||
.collect();
|
||||
|
||||
Ok(result)
|
||||
})
|
||||
}
|
||||
|
||||
fn load_plugin(&mut self, path: &str) -> Result<Arc<dyn PluginData>, 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<dyn PluginData>)
|
||||
.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<Arc<dyn PluginData>> {
|
||||
let plugins = self.plugins.read();
|
||||
plugins.iter()
|
||||
.map(|p| p.clone() as Arc<dyn PluginData>)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_plugin(&self, plugin_id: &str) -> Option<Arc<dyn PluginData>> {
|
||||
let plugins = self.plugins.read();
|
||||
plugins.iter()
|
||||
.find(|p| p.id == plugin_id)
|
||||
.map(|p| p.clone() as Arc<dyn PluginData>)
|
||||
}
|
||||
|
||||
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<Value, String> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user