extern crate libloading;
use std::{ffi::{c_void, c_int}, env};
use libloading::Symbol;
use crate::error::VPluginError;
use super::plugin::Plugin;
#[repr(C)]
pub struct PluginManager {
plugin : Vec<Plugin>,
entry : String,
running: bool,
errcode: u32
}
pub type VHook = unsafe extern "C" fn(*mut c_void) -> c_int;
impl PluginManager {
pub fn new() -> Self {
#[cfg(unix)]
if is_superuser::is_superuser() {
panic!("VPlugin may not be run")
}
Self {
plugin : Vec::new(),
entry : String::from("vplugin_init"),
running: false,
errcode: 0
}
}
pub fn load_plugin(&mut self, filename: &str) -> Result<Plugin, VPluginError> {
Plugin::load(filename)
}
pub fn register_plugin(&mut self, plugin: Plugin) -> Result<(), VPluginError> {
self.plugin.push(plugin);
Ok(())
}
pub fn set_entry_point(&mut self, entry_point: &str) {
let entry_point_with_null = &format!("{}\0", entry_point);
self.entry = String::from(entry_point_with_null)
}
pub fn get_hook(&mut self, plugin: &Plugin, hook: &str) -> Result<VHook, VPluginError> {
plugin.get_hook(hook)
}
pub fn get_custom_hook<P, T>(
&mut self,
plugin: &Plugin,
hook: &str
) -> Result<unsafe extern fn(P) -> T, VPluginError> {
plugin.get_custom_hook(hook)
}
pub fn begin_plugin(&mut self, plugin: &mut Plugin) -> Result<(), VPluginError>{
if !plugin.is_valid {
log::error!(
"Attempted to start plugin '{}', which is not marked as valid.",
plugin.get_metadata().as_ref().unwrap().name
);
return Err(VPluginError::InvalidPlugin);
}
if plugin.started {
log::error!(
"Plugin '{}' has already been initialized.",
plugin.get_metadata().as_ref().unwrap().name
);
return Err(VPluginError::FailedToInitialize);
}
let plugin_entry: Symbol<unsafe extern "C" fn() -> i32>;
unsafe {
plugin_entry = match plugin.raw
.as_ref()
.unwrap()
.get(self.entry.as_bytes())
{
Ok(fnc) => fnc,
Err(e) => {
log::error!(
"Couldn't initialize plugin: {}",
e.to_string()
);
return Err(VPluginError::FailedToInitialize)
}
};
let ___result = plugin_entry();
if ___result != 0 {
log::error!("Couldn't start plugin: Entry point '{}' did not return success", self.entry);
return Err(VPluginError::FailedToInitialize);
}
}
plugin.started = true;
Ok(())
}
pub extern fn shutdown(mut self) {
for plugin in self.plugin.iter_mut() {
plugin.terminate().unwrap_or_else(|_| log::warn!("Error occured while unloading plugin."));
}
}
}
impl Default for PluginManager {
fn default() -> Self {
Self::new()
}
}
impl Drop for PluginManager {
fn drop(&mut self) {
let vplugin_dir = env::temp_dir().join("vplugin");
for plug in &mut self.plugin {
plug
.terminate()
.unwrap_or_else(|e|
log::error!("Couldn't unload plugin (VPlugin Error): {}", e.to_string())
);
drop(plug);
}
match std::fs::remove_dir_all(&vplugin_dir) {
Ok(()) => log::trace!("Removed directory: {}", vplugin_dir.display()),
Err(e) => {
log::warn!(
"Couldn't remove VPlugin: {} (err {}). No cleanup will be performed.",
e.to_string(),
e.raw_os_error().unwrap()
)
}
}
}
}