use std::sync::Arc;
use dashmap::DashMap;
use tokio::sync::Mutex;
use crate::{
error::{ClawDBError, ClawDBResult},
events::types::ClawEvent,
plugins::{
interface::{ClawPlugin, PluginContext, PluginManifest},
sandbox::PluginSandbox,
},
};
pub struct PluginRegistry {
plugins: DashMap<String, Arc<Mutex<Box<dyn ClawPlugin>>>>,
manifests: DashMap<String, PluginManifest>,
sandbox: Arc<PluginSandbox>,
}
impl PluginRegistry {
pub fn new(sandbox: Arc<PluginSandbox>) -> Self {
Self {
plugins: DashMap::new(),
manifests: DashMap::new(),
sandbox,
}
}
pub async fn register(
&self,
manifest: PluginManifest,
mut plugin: Box<dyn ClawPlugin>,
ctx: PluginContext,
) -> ClawDBResult<()> {
self.sandbox.validate_capabilities(&manifest)?;
if self.plugins.contains_key(&manifest.name) {
self.unregister(&manifest.name).await?;
}
plugin.on_load(ctx).await.map_err(|e| ClawDBError::PluginLoad {
name: manifest.name.clone(),
reason: e.to_string(),
})?;
let name = manifest.name.clone();
self.plugins
.insert(name.clone(), Arc::new(Mutex::new(plugin)));
self.manifests.insert(name, manifest);
Ok(())
}
pub async fn unregister(&self, name: &str) -> ClawDBResult<()> {
let (_, handle) = self.plugins.remove(name).ok_or_else(|| {
ClawDBError::PluginLoad {
name: name.to_string(),
reason: "plugin not found".to_string(),
}
})?;
self.manifests.remove(name);
let mut plugin = handle.lock().await;
plugin.on_unload().await.map_err(|e| ClawDBError::PluginExecution {
name: name.to_string(),
hook: "on_unload".to_string(),
reason: e.to_string(),
})?;
Ok(())
}
pub fn get(&self, name: &str) -> Option<Arc<Mutex<Box<dyn ClawPlugin>>>> {
self.plugins.get(name).map(|r| Arc::clone(&r))
}
pub fn list(&self) -> Vec<PluginManifest> {
self.manifests.iter().map(|r| r.clone()).collect()
}
pub fn count(&self) -> usize {
self.plugins.len()
}
pub async fn dispatch_event(&self, event: &ClawEvent) {
let handles: Vec<(String, Arc<Mutex<Box<dyn ClawPlugin>>>)> = self
.plugins
.iter()
.map(|r| (r.key().clone(), Arc::clone(&r)))
.collect();
for (name, handle) in handles {
let plugin = handle.lock().await;
if let Err(e) = plugin.on_event(event).await {
tracing::warn!(plugin = %name, hook = "on_event", err = %e, "plugin hook error");
}
}
}
pub fn for_each_sync<F>(&self, mut f: F)
where
F: FnMut(&dyn crate::plugins::traits::ClawPlugin),
{
let _ = f; }
}