use super::{Error, get_str_conf};
use dashmap::DashMap;
use pingap_config::PluginConf;
use pingap_core::Plugin;
use std::sync::Arc;
use std::sync::LazyLock;
type Result<T, E = Error> = std::result::Result<T, E>;
type NewPlugin = dyn Fn(&PluginConf) -> Result<Arc<dyn Plugin>> + Send + Sync;
pub struct PluginFactory {
plugins: DashMap<String, Arc<NewPlugin>>,
}
impl PluginFactory {
pub fn new() -> Self {
Self {
plugins: DashMap::new(),
}
}
pub fn supported_plugins(&self) -> Vec<String> {
let mut plugins = self
.plugins
.iter()
.map(|item| item.key().clone())
.collect::<Vec<String>>();
plugins.sort();
plugins
}
pub fn register<F>(&self, category: &str, creator: F)
where
F: Fn(&PluginConf) -> Result<Arc<dyn Plugin>> + Send + Sync + 'static,
{
self.plugins.insert(category.to_string(), Arc::new(creator));
}
pub fn create(&self, conf: &PluginConf) -> Result<Arc<dyn Plugin>> {
let category = get_str_conf(conf, "category");
if category.is_empty() {
return Err(Error::NotFound {
category: "unknown".to_string(),
});
}
self.plugins
.get(&category)
.ok_or(Error::NotFound {
category: category.to_string(),
})
.and_then(|creator| creator(conf))
}
}
impl Default for PluginFactory {
fn default() -> Self {
Self::new()
}
}
static PLUGIN_FACTORY: LazyLock<PluginFactory> =
LazyLock::new(PluginFactory::new);
pub fn get_plugin_factory() -> &'static PluginFactory {
&PLUGIN_FACTORY
}