Fixed plugin not functioning with tokio
This commit is contained in:
parent
41e9ae1056
commit
c3c7d2a381
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
pub mod plugin;
|
||||
pub mod plugin_entry;
|
||||
pub mod plugin_details;
|
||||
pub mod plugin_interface;
|
||||
mod plugin_permissions;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue