122 lines
3.5 KiB
Rust
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()
|
|
}
|
|
}
|