radar-g/src/plugin_system/mod.rs
2024-02-06 15:09:01 +08:00

96 lines
2.9 KiB
Rust

mod utils;
use crate::{config::Config, errors::PluginError};
use abi_stable::{
external_types::crossbeam_channel::{self, RReceiver, RSender},
library::{lib_header_from_path, LibraryError, LibrarySuffix, RawLibrary},
sabi_trait::prelude::TD_Opaque,
std_types::{RBox, RErr, ROk, RResult, RSome, RStr, RString, RVec},
};
use core_extensions::*;
use radarg_plugin_interface::{Plugin, PluginId, PluginMod_Ref, Plugin_TO};
use std::{
collections::{HashMap, VecDeque},
io, mem,
path::{Path, PathBuf},
sync::{Arc, Mutex},
};
fn compute_plugin_path(base_name: &str) -> io::Result<PathBuf> {
let debug_dir = "./etws_loader/target/debug"
.as_ref_::<Path>()
.into_::<PathBuf>();
let release_dir = "./etws_loader/target/release"
.as_ref_::<Path>()
.into_::<PathBuf>();
let debug_path = RawLibrary::path_in_directory(&debug_dir, base_name, LibrarySuffix::NoSuffix);
let release_path =
RawLibrary::path_in_directory(&release_dir, base_name, LibrarySuffix::NoSuffix);
match (debug_path.exists(), release_path.exists()) {
(false, false) => debug_path,
(true, false) => debug_path,
(false, true) => release_path,
(true, true) => {
if debug_path.metadata()?.modified()? < release_path.metadata()?.modified()? {
release_path
} else {
debug_path
}
}
}
.piped(Ok)
}
pub fn init_plugin(
base_name: impl AsRef<str>,
) -> Result<(PluginId, Plugin_TO<'static, RBox<()>>), PluginError> {
let library_path: PathBuf = compute_plugin_path(base_name.as_ref())?;
let res = (|| {
let header = lib_header_from_path(&library_path)?;
header.init_root_module::<PluginMod_Ref>()
})()?;
let plugin_constructor = res.new();
let new_id = PluginId {
named: base_name.as_ref().to_owned().into(),
instance: 0,
};
let plugin = plugin_constructor(new_id.clone()).unwrap();
Ok((new_id, plugin))
}
pub struct PluginManager {
registered_plugins: HashMap<PluginId, Plugin_TO<'static, RBox<()>>>,
}
impl PluginManager {
pub fn new() -> Result<Self, PluginError> {
use crate::CONFIG;
let mut this = Self {
registered_plugins: HashMap::new(),
};
for (plugin_name, config) in CONFIG.lock().unwrap().plugins.iter() {
if let Ok((id, p)) = init_plugin(plugin_name.to_owned()) {
println!("Loaded plugin: {}", plugin_name);
this.registered_plugins.insert(id, p);
}
}
Ok(this)
}
pub fn get_plugin(&self, id: &PluginId) -> Option<&Plugin_TO<'static, RBox<()>>> {
self.registered_plugins.get(id)
}
pub fn get_plugin_by_name(&self, name: &str) -> Option<&Plugin_TO<'static, RBox<()>>> {
self.registered_plugins
.iter()
.find(|(id, _)| id.named == name)
.map(|(_, p)| p)
}
}