radarmp/mp_core/src/plugin_system/mod.rs
2024-11-13 00:30:32 +08:00

122 lines
3.5 KiB
Rust

use super::data::Data;
use crate::errors::DataError;
use abi_stable::{
library::{lib_header_from_path, LibrarySuffix, RawLibrary},
std_types::{RBox, ROk, RStr},
};
use core_extensions::*;
use radarg_plugin_interface::{DataLoaderPlugin_TO, PluginId, PluginMod_Ref};
use std::{
collections::HashMap,
io,
path::{Path, PathBuf},
};
fn compute_plugin_path(base_dir: &Path, base_name: &str) -> io::Result<PathBuf> {
let debug_dir = base_dir.join("target/debug");
let release_dir = base_dir.join("target/release");
// let debug_dir = "./loaders/target/debug"
// .as_ref_::<Path>()
// .into_::<PathBuf>();
// let release_dir = "./loaders/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_dir: &Path,
base_name: impl AsRef<str>,
) -> Result<(PluginId, DataLoaderPlugin_TO<'static, RBox<()>>), DataError> {
let library_path: PathBuf = compute_plugin_path(base_dir, base_name.as_ref())?;
let res = (|| {
let header = lib_header_from_path(&library_path)?;
header.init_root_module::<PluginMod_Ref>()
})()
.unwrap();
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, DataLoaderPlugin_TO<'static, RBox<()>>>,
}
impl PluginManager {
pub fn new<P: AsRef<Path>>(plugin_dir: P) -> Result<Self, DataError> {
let mut this = Self {
registered_plugins: HashMap::new(),
};
let (id, plugin) = init_plugin(plugin_dir.as_ref(), "etws_loader")?;
this.registered_plugins.insert(id, plugin);
Ok(this)
}
pub fn get_plugin(&self, id: &PluginId) -> Option<&DataLoaderPlugin_TO<'static, RBox<()>>> {
self.registered_plugins.get(id)
}
pub fn get_plugin_by_name(
&self,
name: &str,
) -> Option<&DataLoaderPlugin_TO<'static, RBox<()>>> {
self.registered_plugins
.iter()
.find(|(id, _)| id.named == name)
.map(|(_, p)| p)
}
pub fn try_load_data<P: AsRef<Path>>(&self, path: P) -> Result<Vec<Data>, DataError> {
let path: &Path = path.as_ref();
let path_rstr = RStr::from(path.to_str().unwrap());
for plugin in self.registered_plugins.values() {
if let ROk(result) = plugin.load(path_rstr) {
return Ok(result.into_iter().map(|v| v.into()).collect());
}
}
Err(DataError::FormatError)
}
pub fn supported_extensions(&self) -> Vec<&str> {
let strs = self
.registered_plugins
.values()
.flat_map(|p| p.supported_extensions())
.collect::<Vec<_>>();
strs.into_iter().map(|s| s.as_str()).collect()
}
}