• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dariusbakunas / cogrs / 13484990103

23 Feb 2025 04:47PM UTC coverage: 37.129% (-0.1%) from 37.246%
13484990103

push

github

dariusbakunas
feat: get callback plugin path from configuration

0 of 12 new or added lines in 3 files covered. (0.0%)

1 existing line in 1 file now uncovered.

714 of 1923 relevant lines covered (37.13%)

1.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/cogrs-plugins/src/plugin_loader.rs
1
use crate::callback::CallbackPlugin;
2
use crate::plugin_type::PluginType;
3
use anyhow::{Context, Result};
4
use libloading::{Library, Symbol};
5
use once_cell::sync::Lazy;
6
use std::fs;
7
use std::path::{Path, PathBuf};
8
use std::sync::Arc;
9
use tokio::sync::Mutex;
10

11
pub struct PluginLoader {
12
    cached_callback_plugins: Mutex<Option<Vec<Arc<dyn CallbackPlugin>>>>,
13
}
14

15
impl PluginLoader {
16
    fn new() -> Self {
×
17
        PluginLoader {
18
            cached_callback_plugins: Mutex::new(None),
×
19
        }
20
    }
21

22
    /// Determines the platform-specific plugin file extension
23
    fn get_plugin_extension() -> &'static str {
24
        if cfg!(target_os = "windows") {
25
            "dll"
26
        } else if cfg!(target_os = "macos") {
27
            "dylib"
28
        } else {
29
            "so"
30
        }
31
    }
32

33
    /// Attempts to retrieve the plugin type
34
    unsafe fn get_plugin_type(&self, lib: &Library) -> Result<u64> {
×
35
        let plugin_type_fn: Symbol<unsafe extern "C" fn() -> u64> = lib
×
36
            .get(b"plugin_type")
37
            .with_context(|| "Failed to retrieve `plugin_type` function")?;
×
38
        Ok(plugin_type_fn())
×
39
    }
40

41
    /// Checks whether a given file path corresponds to a valid plugin file
42
    fn is_valid_plugin_file(&self, path: &Path, plugin_extension: &str) -> bool {
×
43
        path.extension()
×
44
            .and_then(|ext| ext.to_str())
×
45
            .map_or(false, |ext| ext == plugin_extension)
×
46
    }
47

48
    /// Attempts to create a callback plugin
49
    unsafe fn create_callback_plugin(
×
50
        &self,
51
        lib: &Library,
52
        path: &Path,
53
    ) -> Result<Arc<dyn CallbackPlugin>> {
54
        let create_plugin_fn: Symbol<fn() -> Arc<dyn CallbackPlugin>> =
×
55
            lib.get(b"create_plugin").with_context(|| {
56
                format!("Missing `create_plugin` function in plugin at {:?}", path)
×
57
            })?;
58
        Ok(create_plugin_fn())
×
59
    }
60

61
    /// Loads an individual plugin from a file path.
62
    unsafe fn load_callback_plugin(&self, path: &Path) -> Result<Option<Arc<dyn CallbackPlugin>>> {
×
63
        let lib = Library::new(path).with_context(|| "Failed to load plugin")?;
×
64

65
        let plugin_type_value = self.get_plugin_type(&lib)?;
×
66
        match PluginType::from_u64(plugin_type_value) {
×
67
            Some(PluginType::Callback) => {
68
                let plugin = self.create_callback_plugin(&lib, path)?;
×
69
                Ok(Some(plugin))
×
70
            }
71
            _ => {
72
                println!("Skipping unsupported plugin type at {:?}", path);
×
73
                Ok(None)
×
74
            }
75
        }
76
    }
77

NEW
78
    pub async fn get_callback_plugins(
×
79
        &self,
80
        path: &PathBuf,
81
    ) -> Result<Vec<Arc<dyn CallbackPlugin>>> {
82
        if let Some(cached) = self.get_cached_callback_plugins().await {
×
83
            return Ok(cached);
×
84
        }
85

86
        let mut plugins: Vec<Arc<dyn CallbackPlugin>> = Vec::new();
×
UNCOV
87
        let plugin_extension = Self::get_plugin_extension();
×
88

NEW
89
        let entries = fs::read_dir(path).with_context(|| "Failed to read plugin directory")?;
×
90

91
        for entry in entries {
×
92
            let path = entry
×
93
                .with_context(|| "Failed to read directory entry")?
×
94
                .path();
95
            if self.is_valid_plugin_file(&path, &plugin_extension) {
×
96
                // Load the plugin and register it if valid
97
                if let Some(plugin) = unsafe { self.load_callback_plugin(&path) }? {
×
98
                    plugins.push(plugin);
×
99
                }
100
            }
101
        }
102

103
        self.cache_callback_plugins(plugins.clone()).await;
×
104

105
        Ok(plugins)
×
106
    }
107

108
    /// Retrieves the cached plugins if available.
109
    async fn get_cached_callback_plugins(&self) -> Option<Vec<Arc<dyn CallbackPlugin>>> {
×
110
        let cache = self.cached_callback_plugins.lock().await;
×
111
        cache.as_ref().cloned()
×
112
    }
113

114
    /// Caches the provided plugins.
115
    async fn cache_callback_plugins(&self, plugins: Vec<Arc<dyn CallbackPlugin>>) {
×
116
        let mut cache = self.cached_callback_plugins.lock().await;
×
117
        *cache = Some(plugins);
×
118
    }
119
}
120

121
static PLUGIN_LOADER: Lazy<Mutex<PluginLoader>> = Lazy::new(|| Mutex::new(PluginLoader::new()));
×
122

123
impl PluginLoader {
124
    // Provide access to the singleton instance
125
    pub fn instance() -> &'static Mutex<PluginLoader> {
×
126
        &PLUGIN_LOADER
×
127
    }
128
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc