1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use std::fs;
use libloading::{Library, Symbol};
use std::path::{Path, PathBuf};
use nostr_rs_plugin::Plugin;
use tracing::debug;

use nostr_rs_proto::nauthz_grpc::{EventReply, EventRequest};

fn get_plugin(path: PathBuf) -> ExtPlugin {
    unsafe {
        let lib = 
            Library::new(&path)
            .ok()
            .expect(format!("Can't load plugin at path: {}", path.display()).as_str());
        
        let func: Symbol<unsafe extern fn() -> Box<dyn Plugin + Send + Sync>> = 
            lib.get(b"get_plugin")
            .ok()
            .expect("Implement 'get_plugin' in plugin library (check example)");

        let plugin = func();

        let ext_plugin = ExtPlugin {
            lib,
            plugin
        };

        ext_plugin
    }
}

pub struct ExtPlugin {
    #[allow(dead_code)]
    // holds library reference
    pub lib: Library,
    pub plugin: Box<dyn Plugin + Send + Sync>,
}

impl Plugin for ExtPlugin {
    fn start(&self) {}

    fn name(&self) -> String {
        return self.plugin.name();
    }

    fn admit_event(&self, request: &EventRequest) -> EventReply {
        return self.plugin.admit_event(request);
    }

    fn stop(&self) {}
}

pub async fn load_plugins(plugins_folder: String) -> Vec<ExtPlugin> {
    let mut plugins: Vec<ExtPlugin> = Vec::new();

    if let Ok(paths) = fs::read_dir(&plugins_folder) {
        for dir in paths {
            let dir_path = dir.ok().unwrap().path().display().to_string();

            let path = Path::new(&dir_path).join("libplugin.so");

            let plugin = get_plugin(path);

            let n = plugin.name();

            debug!("Plugin: {} loaded", n);

            plugins.push(plugin);
        }
    }

    plugins
}