Skip to main content

pingap_plugin/
plugin.rs

1// Copyright 2024-2025 Tree xie.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::{Error, get_str_conf};
16use dashmap::DashMap;
17use pingap_config::PluginConf;
18use pingap_core::Plugin;
19use std::sync::Arc;
20use std::sync::LazyLock;
21
22type Result<T, E = Error> = std::result::Result<T, E>;
23
24type NewPlugin = dyn Fn(&PluginConf) -> Result<Arc<dyn Plugin>> + Send + Sync;
25
26/// Plugin factory for managing plugin creation and registration
27pub struct PluginFactory {
28    plugins: DashMap<String, Arc<NewPlugin>>,
29}
30
31impl PluginFactory {
32    pub fn new() -> Self {
33        Self {
34            plugins: DashMap::new(),
35        }
36    }
37
38    pub fn supported_plugins(&self) -> Vec<String> {
39        let mut plugins = self
40            .plugins
41            .iter()
42            .map(|item| item.key().clone())
43            .collect::<Vec<String>>();
44        plugins.sort();
45        plugins
46    }
47
48    /// Register a new plugin creator function
49    pub fn register<F>(&self, category: &str, creator: F)
50    where
51        F: Fn(&PluginConf) -> Result<Arc<dyn Plugin>> + Send + Sync + 'static,
52    {
53        self.plugins.insert(category.to_string(), Arc::new(creator));
54    }
55
56    /// Create a new plugin instance by name
57    pub fn create(&self, conf: &PluginConf) -> Result<Arc<dyn Plugin>> {
58        let category = get_str_conf(conf, "category");
59        if category.is_empty() {
60            return Err(Error::NotFound {
61                category: "unknown".to_string(),
62            });
63        }
64
65        self.plugins
66            .get(&category)
67            .ok_or(Error::NotFound {
68                category: category.to_string(),
69            })
70            .and_then(|creator| creator(conf))
71    }
72}
73
74impl Default for PluginFactory {
75    fn default() -> Self {
76        Self::new()
77    }
78}
79
80static PLUGIN_FACTORY: LazyLock<PluginFactory> =
81    LazyLock::new(PluginFactory::new);
82
83pub fn get_plugin_factory() -> &'static PluginFactory {
84    &PLUGIN_FACTORY
85}