Fixed plugin not functioning with tokio

This commit is contained in:
michael-bailey 2022-04-10 00:13:16 +01:00
parent 41e9ae1056
commit c3c7d2a381
11 changed files with 209 additions and 73 deletions

View File

@ -17,7 +17,6 @@ uuid = {version = "0.8", features = ["serde", "v4"]}
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
zeroize = "1.1.0"
tokio = { version = "1.9.0", features = ["full"] }
futures = "0.3.16"
async-trait = "0.1.52"

View File

@ -1,9 +1,12 @@
use serverlib::plugin::plugin::Plugin;
use serverlib::plugin::plugin_details::PluginDetails;
use futures::lock::Mutex;
use std::thread::sleep;
use std::time::Duration;
use tokio::sync::Mutex;
use tokio::time::sleep;
use serverlib::plugin::{plugin::Plugin, plugin_details::PluginDetails};
// use tokio::{sync::Mutex, time::sleep};
use serverlib::plugin::plugin::IPlugin;
#[derive(Debug)]
pub struct ExamplePlugin {
number: Mutex<u8>,
}
@ -17,7 +20,7 @@ impl Default for ExamplePlugin {
}
#[async_trait::async_trait]
impl Plugin for ExamplePlugin {
impl IPlugin for ExamplePlugin {
fn details(&self) -> PluginDetails {
PluginDetails {
display_name: "ExamplePlugin",
@ -32,10 +35,19 @@ impl Plugin for ExamplePlugin {
}
async fn run(&self) {
sleep(Duration::new(1, 0)).await;
println!("Example!!!");
sleep(Duration::new(1, 0));
if let mut a = self.number.lock().await {
*a += 1;
println!("[ExamplePlugin]: example run");
println!("[ExamplePlugin]: example run {}", *a);
}
}
fn deinit(&self) {
todo!()
}
async fn event(&self) {
todo!()
}
}

View File

@ -1,10 +1,10 @@
mod example;
use std::sync::Arc;
use serverlib::plugin::plugin::Plugin;
use crate::example::ExamplePlugin;
use serverlib::plugin::plugin::Plugin;
use std::sync::Arc;
#[no_mangle]
extern fn get_plugin() -> Arc<dyn Plugin> {
pub extern "C" fn get_plugin() -> Plugin {
Arc::new(ExamplePlugin::default())
}
}

View File

@ -1,20 +1,31 @@
use std::fmt::Debug;
use std::sync::Arc;
use crate::plugin::plugin_details::PluginDetails;
use std::sync::Arc;
/// # Plugin
/// Type alias for plugin objects.
pub type Plugin = Arc<dyn IPlugin>;
/// # GetPluginFn
/// This defines the type for getting the plugin struct from a
pub type GetPluginFn = fn() -> Arc<dyn Plugin>;
pub type GetPluginFn = fn() -> Plugin;
/// # Plugin
/// This trait defines an interface for plugins to implement.
///
/// ## Methods
/// - details: This returns the details about the plugin.
/// - init: This defines the initialisation routine for the.
/// - run: defines a routine to be ran like a thread.
/// - init: Defines the initialisation routine for the plugin.
/// - run: defines a routine to be ran like a thread by the plugin manager.
/// - deinit: Defines the deinitalisation routine for the plugin
#[async_trait::async_trait]
pub trait Plugin: Send + Sync {
pub trait IPlugin: Send + Sync + Debug {
fn details(&self) -> PluginDetails;
async fn event(&self);
fn init(&self);
async fn run(&self);
fn deinit(&self);
}

View File

@ -1,3 +1,5 @@
pub mod plugin;
pub mod plugin_entry;
pub mod plugin_details;
pub mod plugin_interface;
mod plugin_permissions;

View File

@ -1,20 +1,31 @@
use std::fmt::Debug;
use std::sync::Arc;
use crate::plugin::plugin_details::PluginDetails;
use std::sync::Arc;
/// # Plugin
/// Type alias for plugin objects.
pub type Plugin = Arc<dyn IPlugin>;
/// # GetPluginFn
/// This defines the type for getting the plugin struct from a
pub type GetPluginFn = fn() -> Arc<dyn Plugin>;
pub type GetPluginFn = fn() -> Plugin;
/// # Plugin
/// This trait defines an interface for plugins to implement.
///
/// ## Methods
/// - details: This returns the details about the plugin.
/// - init: This defines the initialisation routine for the.
/// - run: defines a routine to be ran like a thread.
/// - init: Defines the initialisation routine for the plugin.
/// - run: defines a routine to be ran like a thread by the plugin manager.
/// - deinit: Defines the deinitalisation routine for the plugin
#[async_trait::async_trait]
pub trait Plugin: Send + Sync {
pub trait IPlugin: Send + Sync + Debug {
fn details(&self) -> PluginDetails;
async fn event(&self);
fn init(&self);
async fn run(&self);
fn deinit(&self);
}

View File

@ -0,0 +1,63 @@
use serde::{Deserialize, Serialize};
use tokio::{
fs::File,
io::{AsyncReadExt, AsyncSeekExt, AsyncWrite},
};
use std::io::{SeekFrom, ErrorKind};
use std::sync::Arc;
use crate::plugin::plugin::Plugin;
pub type PluginEntryObj = Arc<PluginEntry>;
#[derive(Serialize, Deserialize, Debug)]
pub enum PluginPermission {
Read,
Write,
ReadWrite,
None
}
/// # PluginEntry
/// a wrapper for plugins loaded into the server.
/// Used to provide an api for the plugin to use.
/// Also acts as gatekeeper to server data with permissions.
#[derive(Debug)]
pub struct PluginEntry {
server_permission: PluginPermission,
network_permission: PluginPermission,
client_manager_permission: PluginPermission,
client_permission: PluginPermission,
plugin: Plugin
}
impl PluginEntry {
pub fn new(plugin: Plugin) -> Arc<PluginEntry> {
Arc::new(PluginEntry {
server_permission: PluginPermission::None,
network_permission: PluginPermission::None,
client_manager_permission: PluginPermission::None,
client_permission: PluginPermission::None,
plugin
})
}
pub fn start(&self) {
let cont = self.plugin.clone();
tokio::spawn(async move {
println!("[PluginEntry:start] starting plugin: {:?}", cont.details().id);
cont.init();
loop {
// Todo: Add code to stop loop once finished
cont.run().await;
}
cont.deinit();
});
}
}

View File

@ -1,7 +1,4 @@
use std::sync::Arc;
use crate::client::Client;
use crate::client_manager::ClientMgrMessage;
pub struct PluginInterface {
new_connection_callback: Box<dyn FnMut(&mut PluginInterface) -> ()>,
}
#[async_trait::async_trait]
pub trait IPluginInterface {
fn get_string<T: Into<String>>() -> T;
}

View File

View File

@ -1,26 +1,47 @@
use crate::plugin::plugin::{GetPluginFn, Plugin};
use std::{collections::HashMap, io::Error, mem, sync::Arc};
use std::fs::Metadata;
use libloading::Library;
use tokio::fs::{create_dir, DirEntry, read_dir};
use tokio::sync::mpsc::Sender;
use tokio::sync::{Mutex, MutexGuard};
use serde::{Serialize, Deserialize};
use serde_json::StreamDeserializer;
use std::collections::HashMap;
use std::io::Error;
use std::sync::Arc;
use tokio::fs::{create_dir, read_dir};
use futures::future::join_all;
use futures::TryFutureExt;
use mlua::require_module_feature;
use crate::plugin::plugin::{GetPluginFn, Plugin};
use crate::plugin::plugin_entry::{PluginEntry, PluginEntryObj};
pub enum PluginManagerMessage {
None,
}
/// # PluginManager
/// This struct handles the loading and unloading of plugins in the server
///
/// ## Attributes
/// - plugins: A [HashMap] of all loaded plugins
pub struct PluginManager {
/// - plugins: A [Vec] of all loaded plugins
/// - server_channel: A [Sender]
pub struct PluginManager<Out: 'static>
where
Out: From<PluginManagerMessage> + Send, {
#[allow(dead_code)]
plugins: HashMap<String, Arc<dyn Plugin>>,
plugins: Mutex<Vec<PluginEntryObj>>,
#[allow(dead_code)]
server_channel: Mutex<Sender<Out>>,
}
impl PluginManager {
pub fn new() -> Arc<Self> {
impl<Out: 'static> PluginManager<Out>
where
Out: From<PluginManagerMessage> + Send, {
pub fn new(channel: Sender<Out>) -> Arc<Self> {
Arc::new(Self {
plugins: HashMap::new(),
plugins: Mutex::new(Vec::new()),
server_channel: Mutex::new(channel),
})
}
@ -32,35 +53,49 @@ impl PluginManager {
);
if let Ok(mut plugins) = read_dir("./plugins").await {
while let Some(child) = plugins.next_entry().await? {
let metadata = child.metadata().await?;
if metadata.is_file() && child.path().extension().unwrap() == "dylib" {
println!(
"[PluginManager]: Library at:{}",
child.path().to_string_lossy()
);
unsafe {
let lib = Library::new(child.path()).unwrap();
let plugin_fn = lib.get::<GetPluginFn>("get_plugin".as_ref()).unwrap();
let plugin: Arc<dyn Plugin> = plugin_fn();
plugin.init();
let cont = plugin.clone();
tokio::spawn(async move {
loop {
cont.run().await;
}
});
println!("[PluginManager]: got details: {}", plugin.details());
};
}
// Todo: - make this concurrent
let mut plugin_vec = vec![];
while let Some(next) = plugins.next_entry().await? {
println!("{:?}", next);
plugin_vec.push(next)
}
// get all entries by extension
let entries: Vec<DirEntry> = plugin_vec.into_iter()
.filter(|item| item.path().extension().unwrap_or_default() == "dylib")
.collect();
// get entry metadata
let metadata: Vec<Metadata> = join_all(entries.iter()
.map(|item| item.metadata())).await
.into_iter()
.filter_map(|item| item.ok())
.collect();
// convert correct ones to plugins
let mut plugins: Vec<PluginEntryObj> = entries.into_iter().zip(metadata.into_iter())
.filter(|(item, meta)| meta.is_file())
.map(|item| item.0)
.map(|item| unsafe {
let lib = Library::new(item.path()).unwrap();
let plugin_fn = lib.get::<GetPluginFn>("get_plugin".as_ref()).unwrap();
PluginEntry::new(plugin_fn())
})
.collect();
println!("[PluginManager:load] got plugins: {:?}", plugins);
let mut self_vec = self.plugins.lock().await;
let _ = mem::replace(&mut *self_vec, plugins);
} else {
create_dir("./plugins").await?;
}
Ok(())
for i in self.plugins.lock().await.iter() {
i.start()
}
Ok(())
}
}

View File

@ -8,13 +8,12 @@ use tokio::sync::{
Mutex,
};
use foundation::connection::Connection;
use foundation::prelude::IManager;
use crate::client_manager::{ClientManager, ClientMgrMessage};
use crate::network_manager::{NetworkManager, NetworkManagerMessage};
use crate::plugin_manager::PluginManager;
use crate::plugin_manager::PluginManagerMessage;
use crate::{
client_manager::{ClientManager, ClientMgrMessage},
network_manager::{NetworkManager, NetworkManagerMessage},
plugin_manager::PluginManager,
};
#[derive(Debug, Clone)]
pub enum ServerMessage {
@ -65,6 +64,12 @@ impl From<ClientMgrMessage> for ServerMessage {
}
}
impl From<PluginManagerMessage> for ServerMessage {
fn from(_: PluginManagerMessage) -> Self {
todo!()
}
}
/// # Server
/// authors: @michael-bailey, @Mitch161
/// This Represents a server instance.
@ -79,7 +84,7 @@ impl From<ClientMgrMessage> for ServerMessage {
pub struct Server {
pub client_manager: Arc<ClientManager<ServerMessage>>,
network_manager: Arc<NetworkManager<ServerMessage>>,
plugin_manager: Arc<PluginManager>,
plugin_manager: Arc<PluginManager<ServerMessage>>,
receiver: Mutex<Receiver<ServerMessage>>,
}
@ -90,8 +95,8 @@ impl Server {
let server = Arc::new(Server {
client_manager: ClientManager::new(sender.clone()),
network_manager: NetworkManager::new("0.0.0.0:5600", sender).await?,
plugin_manager: PluginManager::new(),
network_manager: NetworkManager::new("0.0.0.0:5600", sender.clone()).await?,
plugin_manager: PluginManager::new(sender),
receiver: Mutex::new(receiver),
});
@ -101,6 +106,7 @@ impl Server {
pub async fn port(self: &Arc<Server>) -> u16 {
self.network_manager.port().await
}
pub async fn start(self: &Arc<Server>) {
// start client manager and network manager
self.network_manager.clone().start();