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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// libs/core/src/crate_installer.rs
use log::debug;
use nodium_events::EventBus;
use serde_json::Value;
use std::process::Command;
use std::sync::{Arc, Mutex, Weak};

use dirs_next::document_dir;
use std::fs;

use libloading::{Library, Symbol};
use std::collections::HashMap;
use std::path::Path;

pub struct PluginManager {
    install_location: String,
    event_bus: Arc<EventBus>,
    shared_self: Weak<Mutex<Self>>,
    libraries: HashMap<String, Library>,
}

impl PluginManager {
    pub fn new(event_bus: Arc<EventBus>) -> Arc<Mutex<Self>> {
        let doc_dir = document_dir().expect("Unable to get user's document directory");
        let install_location = doc_dir.join("nodium").join("plugins");
        if !install_location.exists() {
            fs::create_dir_all(&install_location).expect("Unable to create plugin directory");
        }

        let installer = Arc::new(Mutex::new(PluginManager {
            install_location: String::from(install_location.to_str().unwrap()),
            event_bus: event_bus.clone(),
            shared_self: Weak::new(),
            libraries: HashMap::new(),
        }));
        let weak_installer = Arc::downgrade(&installer);
        installer.lock().unwrap().shared_self = weak_installer;
        installer
    }

    pub async fn register_event_handlers(&self) {
        let weak_installer = self.shared_self.clone();
        self.event_bus
            .register(
                "CrateInstall",
                Box::new(move |payload| {
                    if let Some(installer) = weak_installer.upgrade() {
                        let mut installer = installer.lock().unwrap();
                        installer.handle_event(payload);
                        debug!("CrateInstall event handler called");
                    }
                }),
            )
            .await;
    }

    fn handle_event(&mut self, payload: String) {
        let data: Value = serde_json::from_str(&payload).unwrap();
        if let Some(crate_name) = data.get("crate_name").and_then(Value::as_str) {
            debug!("Handling CrateInstall event for {}", crate_name);
            self.install_crate(crate_name);
        }
        // Handle other event types as needed
    }

    fn install_crate(&mut self, crate_name: &str) {
        debug!("Installing crate {} to {}", crate_name, self.install_location);
        
        let mut cmd = Command::new("cargo");

        cmd.arg("install")
            .arg("--root")
            .arg(&self.install_location)
            .arg(crate_name);

        let output = cmd.output().expect("Failed to execute cargo install command");

        if output.status.success() {
          debug!("Crate {} installed successfully", crate_name);
          self.load_library(crate_name);
      } else {
          debug!("Crate {} failed to install", crate_name);
      }

        debug!("Cargo install output: {}", String::from_utf8_lossy(&output.stdout));
    }

    fn load_library(&mut self, crate_name: &str) {
      let lib_path = Path::new(&self.install_location).join("bin").join(crate_name);
      debug!("Loading library from {}", lib_path.to_str().unwrap());
      //  let ext = if cfg!(windows) { "dll" } else if cfg!(unix) { "so" } else { panic!("Unsupported platform"); };


      let lib = unsafe { Library::new(&lib_path) }.expect("Unable to load library");
      debug!("Library loaded successfully");

      // let func: Symbol<unsafe extern "C" fn()> = lib.get(b"function_name").unwrap();

      self.libraries.insert(String::from(crate_name), lib);
      debug!("Library added to libraries map");
  }
}