mirror of
https://github.com/MedzikUser/servers
synced 2024-08-14 23:57:48 +00:00
feat(plugins-loader): improve a plugin loader
This commit is contained in:
parent
369dd14cf2
commit
4f9baa4b76
7 changed files with 170 additions and 269 deletions
|
@ -1,46 +1,52 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use servers::{
|
use servers::{
|
||||||
plugins::{
|
plugins::{Command, Event, Plugin, PluginManagerType, Registrar},
|
||||||
Command, CommandManagerType, CommandRegistrar, Event, EventRegistrar, Plugin,
|
|
||||||
PluginRegistrar,
|
|
||||||
},
|
|
||||||
tcp::Client,
|
tcp::Client,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PluginTest;
|
struct PluginTest;
|
||||||
|
|
||||||
|
/// Create a new plugin.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Plugin for PluginTest {
|
impl Plugin for PluginTest {
|
||||||
|
/// Name of the plugin.
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"test"
|
"test"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A function will be executed when plugin loading.
|
||||||
|
/// Usally used for initialization.
|
||||||
async fn on_plugin_load(&self) {}
|
async fn on_plugin_load(&self) {}
|
||||||
|
|
||||||
async fn on_plugin_unload(&self) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new command.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Command for PluginTest {
|
impl Command for PluginTest {
|
||||||
|
/// Command name
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"/test"
|
"/test"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Help message of the command
|
||||||
fn help(&self) -> &'static str {
|
fn help(&self) -> &'static str {
|
||||||
"test command"
|
"test command"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, client: &mut Client, _args: Vec<&str>, _commands: &CommandManagerType) {
|
/// Command function
|
||||||
|
async fn execute(&self, client: &mut Client, _args: Vec<&str>, _commands: &PluginManagerType) {
|
||||||
client.send("content").expect("send message")
|
client.send("content").expect("send message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a new event
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Event for PluginTest {
|
impl Event for PluginTest {
|
||||||
|
/// Event name (onConnect or onSend)
|
||||||
fn name(&self) -> &'static str {
|
fn name(&self) -> &'static str {
|
||||||
"onConnect"
|
"onConnect"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Event function
|
||||||
async fn execute(&self, client: &mut Client) {
|
async fn execute(&self, client: &mut Client) {
|
||||||
client
|
client
|
||||||
.send(&format!("Welcome {}", client.stream.peer_addr().unwrap()))
|
.send(&format!("Welcome {}", client.stream.peer_addr().unwrap()))
|
||||||
|
@ -48,16 +54,10 @@ impl Event for PluginTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Regsiter plugin
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn plugin_entry(
|
pub fn plugin_entry(registrar: &mut dyn Registrar) {
|
||||||
plugin: &mut dyn PluginRegistrar,
|
registrar.register_plugin(Box::new(PluginTest));
|
||||||
command: &mut dyn CommandRegistrar,
|
registrar.register_command(Box::new(PluginTest));
|
||||||
event: &mut dyn EventRegistrar,
|
registrar.register_event(Box::new(PluginTest));
|
||||||
) {
|
|
||||||
// register plugin
|
|
||||||
plugin.register(Box::new(PluginTest));
|
|
||||||
// register command
|
|
||||||
command.register(Box::new(PluginTest));
|
|
||||||
// register plugin
|
|
||||||
event.register(Box::new(PluginTest));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
plugins::{Command, CommandManagerType},
|
plugins::{Command, PluginManagerType},
|
||||||
tcp::Client,
|
tcp::Client,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@ impl Command for CommandHelp {
|
||||||
&self,
|
&self,
|
||||||
client: &mut Client,
|
client: &mut Client,
|
||||||
_args: Vec<&str>,
|
_args: Vec<&str>,
|
||||||
command_manager: &CommandManagerType,
|
plugin_manager: &PluginManagerType,
|
||||||
) {
|
) {
|
||||||
for command in command_manager.commands.iter() {
|
for command in plugin_manager.commands.iter() {
|
||||||
client
|
client
|
||||||
.send(&format!("{} - {}", command.name(), command.help()))
|
.send(&format!("{} - {}", command.name(), command.help()))
|
||||||
.expect("send message");
|
.expect("send message");
|
||||||
|
|
|
@ -53,19 +53,14 @@ async fn start_server(host: &str, port: &str) -> anyhow::Result<()> {
|
||||||
println!("Tcp server started at: {}", listener.local_addr()?);
|
println!("Tcp server started at: {}", listener.local_addr()?);
|
||||||
|
|
||||||
// load plugins, commands and events
|
// load plugins, commands and events
|
||||||
let (command_manager, _plugin_manager, event_manager) = loader()?;
|
let plugin_manager = loader()?;
|
||||||
|
|
||||||
// Accepts a new incoming connection from this listener.
|
// Accepts a new incoming connection from this listener.
|
||||||
while let Ok((stream, _address)) = listener.accept() {
|
while let Ok((stream, _address)) = listener.accept() {
|
||||||
let client = Client::new(stream);
|
let client = Client::new(stream);
|
||||||
|
|
||||||
// clone `CommandManager`
|
|
||||||
let command_manager = command_manager.clone();
|
|
||||||
// clone `EventManager`
|
|
||||||
let event_manager = event_manager.clone();
|
|
||||||
|
|
||||||
// handle client connection in new thread
|
// handle client connection in new thread
|
||||||
tokio::spawn(handle_connection(client, command_manager, event_manager));
|
tokio::spawn(handle_connection(client, plugin_manager.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// server for a unexpectedly reason be terminated
|
// server for a unexpectedly reason be terminated
|
||||||
|
|
|
@ -1,174 +1,24 @@
|
||||||
use std::{any::Any, fs, sync::Arc};
|
use std::{fs, sync::Arc};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use libloading::{Library, Symbol};
|
use libloading::{Library, Symbol};
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
|
||||||
use crate::{commands, tcp::Client};
|
use crate::{commands, plugins::Registrar};
|
||||||
|
|
||||||
/// A plugin which allows you to add extra functionality.
|
use super::{PluginManager, PluginManagerType};
|
||||||
#[async_trait]
|
|
||||||
pub trait Plugin: Any + Send + Sync {
|
|
||||||
/// Get a name describing the `Plugin`.
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
/// A function that runs immediately after plugin loading.
|
|
||||||
/// Usually used for initialization.
|
|
||||||
async fn on_plugin_load(&self);
|
|
||||||
/// A function that runs immediately before the plugin is unloaded.
|
|
||||||
/// Use this if you want to do any cleanup.
|
|
||||||
async fn on_plugin_unload(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait with function to register plugin.
|
|
||||||
pub trait PluginRegistrar {
|
|
||||||
/// Function to register the plugin
|
|
||||||
fn register(&mut self, plugin: Box<dyn Plugin>);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PluginRegistrar for PluginManager {
|
|
||||||
fn register(&mut self, plugin: Box<dyn Plugin>) {
|
|
||||||
self.plugins.push(plugin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Plugin Manager
|
|
||||||
pub struct PluginManager {
|
|
||||||
/// Vector with all loaded plugins.
|
|
||||||
pub plugins: Vec<Box<dyn Plugin>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PluginManager {
|
|
||||||
/// Create empty `PluginManager`.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
plugins: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for PluginManager {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Plugin Manager Type
|
|
||||||
pub type PluginManagerType = Arc<PluginManager>;
|
|
||||||
|
|
||||||
/// Trait with command functions to implement on struct.
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Command: Any + Send + Sync {
|
|
||||||
/// Command name
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
/// Help message of this command
|
|
||||||
fn help(&self) -> &'static str;
|
|
||||||
/// Command function
|
|
||||||
async fn execute(
|
|
||||||
&self,
|
|
||||||
client: &mut Client,
|
|
||||||
args: Vec<&str>,
|
|
||||||
command_manager: &CommandManagerType,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Command Manager
|
|
||||||
pub struct CommandManager {
|
|
||||||
/// Vector with all commands.
|
|
||||||
pub commands: Vec<Box<dyn Command>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandManager {
|
|
||||||
/// Create empty `CommandManager`.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
commands: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CommandManager {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Command Manager Type
|
|
||||||
pub type CommandManagerType = Arc<CommandManager>;
|
|
||||||
|
|
||||||
/// Trait with function to register command.
|
|
||||||
pub trait CommandRegistrar {
|
|
||||||
/// Function to register the plugin and the commands in the plugin.
|
|
||||||
fn register(&mut self, command: Box<dyn Command>);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandRegistrar for CommandManager {
|
|
||||||
fn register(&mut self, command: Box<dyn Command>) {
|
|
||||||
self.commands.push(command)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trait with event functions to implement on struct.
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Event: Any + Send + Sync {
|
|
||||||
/// Event name (onConnect, onSend)
|
|
||||||
fn name(&self) -> &'static str;
|
|
||||||
/// Event function
|
|
||||||
async fn execute(&self, client: &mut Client);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Event Manager
|
|
||||||
pub struct EventManager {
|
|
||||||
/// Vector with all events loaded from plugins.
|
|
||||||
pub events: Vec<Box<dyn Event>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventManager {
|
|
||||||
/// Create empty `EventManager`
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { events: Vec::new() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for EventManager {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Event Manager Type
|
|
||||||
pub type EventManagerType = Arc<EventManager>;
|
|
||||||
|
|
||||||
/// Trait with function to register event.
|
|
||||||
pub trait EventRegistrar {
|
|
||||||
/// Function to register the plugin and the commands in the plugin.
|
|
||||||
fn register(&mut self, command: Box<dyn Event>);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventRegistrar for EventManager {
|
|
||||||
fn register(&mut self, command: Box<dyn Event>) {
|
|
||||||
self.events.push(command)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Plugins and Commands loader
|
/// Plugins and Commands loader
|
||||||
pub fn loader() -> anyhow::Result<(CommandManagerType, PluginManagerType, EventManagerType)> {
|
pub fn loader() -> anyhow::Result<PluginManagerType> {
|
||||||
// get path to .so lib from command argument
|
// get path to .so lib from command argument
|
||||||
let config_dir = "./plugins";
|
let config_dir = "./plugins";
|
||||||
let paths = fs::read_dir(config_dir)?;
|
let paths = fs::read_dir(config_dir)?;
|
||||||
|
|
||||||
// create a plugin manager where all loaded plugins will be located
|
// create a plugin manager
|
||||||
let mut plugin_manager = PluginManager::new();
|
let mut plugin_manager = PluginManager::new();
|
||||||
|
|
||||||
// create a command manager where located all commands
|
|
||||||
let mut command_manager = CommandManager::new();
|
|
||||||
|
|
||||||
// create a command manager where located all events from plugins
|
|
||||||
let mut event_manager = EventManager::new();
|
|
||||||
|
|
||||||
// register default commands
|
// register default commands
|
||||||
for command in commands::register_commands() {
|
for command in commands::register_commands() {
|
||||||
command_manager.commands.push(command)
|
plugin_manager.commands.push(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
// for all plugin in directory
|
// for all plugin in directory
|
||||||
|
@ -189,28 +39,15 @@ pub fn loader() -> anyhow::Result<(CommandManagerType, PluginManagerType, EventM
|
||||||
|
|
||||||
// get `plugin_entry` from library
|
// get `plugin_entry` from library
|
||||||
trace!("Finding symbol `plugin_entry` in `{}`", plugin_path);
|
trace!("Finding symbol `plugin_entry` in `{}`", plugin_path);
|
||||||
let func: Symbol<
|
let func: Symbol<unsafe extern "C" fn(&mut dyn Registrar) -> ()> =
|
||||||
unsafe extern "C" fn(
|
lib.get(b"plugin_entry")?;
|
||||||
&mut dyn PluginRegistrar,
|
|
||||||
&mut dyn CommandRegistrar,
|
|
||||||
&mut dyn EventRegistrar,
|
|
||||||
) -> (),
|
|
||||||
> = lib.get(b"plugin_entry")?;
|
|
||||||
|
|
||||||
// execute initial plugin function
|
// execute initial plugin function
|
||||||
trace!("Running `plugin_entry(...)` in plugin `{}`", plugin_path);
|
trace!("Running `plugin_entry(...)` in plugin `{}`", plugin_path);
|
||||||
func(
|
func(&mut plugin_manager);
|
||||||
&mut plugin_manager,
|
|
||||||
&mut command_manager,
|
|
||||||
&mut event_manager,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return CommandManager, PluginManager and EventManager
|
// return a `PluginManager`
|
||||||
Ok((
|
Ok(Arc::new(plugin_manager))
|
||||||
Arc::new(command_manager),
|
|
||||||
Arc::new(plugin_manager),
|
|
||||||
Arc::new(event_manager),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,18 +23,16 @@
|
||||||
//!
|
//!
|
||||||
//! In file `src/lib.rs`
|
//! In file `src/lib.rs`
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```no_run
|
||||||
//! use async_trait::async_trait;
|
//! use async_trait::async_trait;
|
||||||
//! use servers::{
|
//! use servers::{
|
||||||
//! plugins::{
|
//! plugins::{Command, Plugin, PluginManagerType, Registrar},
|
||||||
//! Command, CommandManagerType, CommandRegistrar, EventRegistrar, Plugin,
|
|
||||||
//! PluginRegistrar,
|
|
||||||
//! },
|
|
||||||
//! tcp::Client,
|
//! tcp::Client,
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! struct PluginTest;
|
//! struct PluginTest;
|
||||||
//!
|
//!
|
||||||
|
//! /// Create a new plugin.
|
||||||
//! #[async_trait]
|
//! #[async_trait]
|
||||||
//! impl Plugin for PluginTest {
|
//! impl Plugin for PluginTest {
|
||||||
//! /// Name of the plugin.
|
//! /// Name of the plugin.
|
||||||
|
@ -42,17 +40,12 @@
|
||||||
//! "test"
|
//! "test"
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! /// Function will be executed when plugin loading.
|
//! /// A function will be executed when plugin loading.
|
||||||
//! async fn on_plugin_load(&self) {
|
//! /// Usally used for initialization.
|
||||||
//! println!("Loading plugin `test`...")
|
//! async fn on_plugin_load(&self) {}
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! /// Function will be executed when plugin unloading.
|
|
||||||
//! async fn on_plugin_unload(&self) {
|
|
||||||
//! println!("Unloading plugin `test`...")
|
|
||||||
//! }
|
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
|
//! /// Create a new command.
|
||||||
//! #[async_trait]
|
//! #[async_trait]
|
||||||
//! impl Command for PluginTest {
|
//! impl Command for PluginTest {
|
||||||
//! /// Command name
|
//! /// Command name
|
||||||
|
@ -60,28 +53,22 @@
|
||||||
//! "/test"
|
//! "/test"
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! /// Command help message
|
//! /// Help message of the command
|
||||||
//! fn help(&self) -> &'static str {
|
//! fn help(&self) -> &'static str {
|
||||||
//! "test command"
|
//! "test command"
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! /// Function will be executed when client send command `/test`
|
//! /// Command function
|
||||||
//! async fn execute(&self, client: &mut Client, _args: Vec<&str>, _commands: &CommandManagerType) {
|
//! async fn execute(&self, client: &mut Client, _args: Vec<&str>, _commands: &PluginManagerType) {
|
||||||
//! client.send("Message sended by `test` plugin").expect("send message")
|
//! client.send("content").expect("send message")
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! /// Register plugin and event
|
//! /// Regsiter plugin
|
||||||
//! #[no_mangle]
|
//! #[no_mangle]
|
||||||
//! pub fn plugin_entry(
|
//! pub fn plugin_entry(registrar: &mut dyn Registrar) {
|
||||||
//! plugin: &mut dyn PluginRegistrar,
|
//! registrar.register_plugin(Box::new(PluginTest));
|
||||||
//! command: &mut dyn CommandRegistrar,
|
//! registrar.register_command(Box::new(PluginTest));
|
||||||
//! _event: &mut dyn EventRegistrar,
|
|
||||||
//! ) {
|
|
||||||
//! // register plugin
|
|
||||||
//! plugin.register(Box::new(PluginTest));
|
|
||||||
//! // register command
|
|
||||||
//! command.register(Box::new(PluginTest));
|
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -89,18 +76,16 @@
|
||||||
//!
|
//!
|
||||||
//! In file `src/lib.rs`
|
//! In file `src/lib.rs`
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```no_run
|
||||||
//! use async_trait::async_trait;
|
//! use async_trait::async_trait;
|
||||||
//! use servers::{
|
//! use servers::{
|
||||||
//! plugins::{
|
//! plugins::{Event, Plugin, PluginManagerType, Registrar},
|
||||||
//! CommandManagerType, CommandRegistrar, Event, EventRegistrar, Plugin,
|
|
||||||
//! PluginRegistrar,
|
|
||||||
//! },
|
|
||||||
//! tcp::Client,
|
//! tcp::Client,
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! struct PluginTest;
|
//! struct PluginTest;
|
||||||
//!
|
//!
|
||||||
|
//! /// Create a new plugin.
|
||||||
//! #[async_trait]
|
//! #[async_trait]
|
||||||
//! impl Plugin for PluginTest {
|
//! impl Plugin for PluginTest {
|
||||||
//! /// Name of the plugin.
|
//! /// Name of the plugin.
|
||||||
|
@ -108,25 +93,20 @@
|
||||||
//! "test"
|
//! "test"
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! /// Function will be executed when plugin loading.
|
//! /// A function will be executed when plugin loading.
|
||||||
//! async fn on_plugin_load(&self) {
|
//! /// Usally used for initialization.
|
||||||
//! println!("Loading plugin `test`...")
|
//! async fn on_plugin_load(&self) {}
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! /// Function will be executed when plugin unloading.
|
|
||||||
//! async fn on_plugin_unload(&self) {
|
|
||||||
//! println!("Unloading plugin `test`...")
|
|
||||||
//! }
|
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
|
//! /// Create a new event
|
||||||
//! #[async_trait]
|
//! #[async_trait]
|
||||||
//! impl Event for PluginTest {
|
//! impl Event for PluginTest {
|
||||||
//! /// Event name (onConnect, onSend)
|
//! /// Event name (onConnect or onSend)
|
||||||
//! fn name(&self) -> &'static str {
|
//! fn name(&self) -> &'static str {
|
||||||
//! "onConnect"
|
//! "onConnect"
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! /// Function will be executed when client connected
|
//! /// Event function
|
||||||
//! async fn execute(&self, client: &mut Client) {
|
//! async fn execute(&self, client: &mut Client) {
|
||||||
//! client
|
//! client
|
||||||
//! .send(&format!("Welcome {}", client.stream.peer_addr().unwrap()))
|
//! .send(&format!("Welcome {}", client.stream.peer_addr().unwrap()))
|
||||||
|
@ -134,17 +114,11 @@
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! /// Register plugin and command
|
//! /// Regsiter plugin
|
||||||
//! #[no_mangle]
|
//! #[no_mangle]
|
||||||
//! pub fn plugin_entry(
|
//! pub fn plugin_entry(registrar: &mut dyn Registrar) {
|
||||||
//! plugin: &mut dyn PluginRegistrar,
|
//! registrar.register_plugin(Box::new(PluginTest));
|
||||||
//! _command: &mut dyn CommandRegistrar,
|
//! registrar.register_event(Box::new(PluginTest));
|
||||||
//! event: &mut dyn EventRegistrar,
|
|
||||||
//! ) {
|
|
||||||
//! // register plugin
|
|
||||||
//! plugin.register(Box::new(PluginTest));
|
|
||||||
//! // register event
|
|
||||||
//! event.register(Box::new(PluginTest));
|
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -157,5 +131,7 @@
|
||||||
//! Move compiled plugin to the `plugin` directory where servers is located
|
//! Move compiled plugin to the `plugin` directory where servers is located
|
||||||
|
|
||||||
mod loader;
|
mod loader;
|
||||||
|
mod types;
|
||||||
|
|
||||||
pub use loader::*;
|
pub use loader::*;
|
||||||
|
pub use types::*;
|
||||||
|
|
94
src/plugins/types.rs
Normal file
94
src/plugins/types.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use std::{any::Any, sync::Arc};
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use crate::tcp::Client;
|
||||||
|
|
||||||
|
/// A plugin wich allows you to add extra functionality.
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Plugin: Any + Send + Sync {
|
||||||
|
/// Name of the plugin.
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
/// A function will be executed when plugin loading.
|
||||||
|
/// Usally used for initialization.
|
||||||
|
async fn on_plugin_load(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new command
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Command: Any + Send + Sync {
|
||||||
|
/// Name of the command.
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
/// Help message of the command.
|
||||||
|
fn help(&self) -> &'static str;
|
||||||
|
/// Command function
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
client: &mut Client,
|
||||||
|
args: Vec<&str>,
|
||||||
|
plugin_manager: &PluginManagerType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new function that will be executed when the event occurs
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Event: Any + Send + Sync {
|
||||||
|
/// Event name (onConnect or onSend)
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
/// Event function
|
||||||
|
async fn execute(&self, client: &mut Client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Plugin Manager
|
||||||
|
pub struct PluginManager {
|
||||||
|
/// Vector with loaded plugins.
|
||||||
|
pub plugins: Vec<Box<dyn Plugin>>,
|
||||||
|
/// Vector with all commands.
|
||||||
|
pub commands: Vec<Box<dyn Command>>,
|
||||||
|
/// Vector with all events.
|
||||||
|
pub events: Vec<Box<dyn Event>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginManager {
|
||||||
|
/// Create an empty [PluginManager]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
plugins: Vec::new(),
|
||||||
|
commands: Vec::new(),
|
||||||
|
events: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PluginManager {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type of the [PluginManager]
|
||||||
|
pub type PluginManagerType = Arc<PluginManager>;
|
||||||
|
|
||||||
|
/// Plugin Registrar
|
||||||
|
pub trait Registrar {
|
||||||
|
/// Function to register the plugin
|
||||||
|
fn register_plugin(&mut self, plugin: Box<dyn Plugin>);
|
||||||
|
/// Function to register the command
|
||||||
|
fn register_command(&mut self, command: Box<dyn Command>);
|
||||||
|
/// Function to register the event
|
||||||
|
fn register_event(&mut self, event: Box<dyn Event>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registrar for PluginManager {
|
||||||
|
fn register_plugin(&mut self, plugin: Box<dyn Plugin>) {
|
||||||
|
self.plugins.push(plugin)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_command(&mut self, command: Box<dyn Command>) {
|
||||||
|
self.commands.push(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_event(&mut self, event: Box<dyn Event>) {
|
||||||
|
self.events.push(event)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,27 +2,26 @@ use std::io::Write;
|
||||||
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
|
||||||
use crate::plugins::{CommandManagerType, EventManagerType};
|
use crate::plugins::PluginManagerType;
|
||||||
|
|
||||||
use super::Client;
|
use super::Client;
|
||||||
|
|
||||||
/// Handle Client connection
|
/// Handle Client connection
|
||||||
pub async fn handle_connection(
|
pub async fn handle_connection(
|
||||||
mut client: Client,
|
mut client: Client,
|
||||||
commands: CommandManagerType,
|
plugin_manager: PluginManagerType,
|
||||||
events: EventManagerType,
|
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
println!("New Client: {:?}", client.stream.peer_addr()?);
|
println!("New Client: {:?}", client.stream.peer_addr()?);
|
||||||
|
|
||||||
// run `onConnect` events from plugins
|
// run `onConnect` events from plugins
|
||||||
check_event(&mut client, &events, "onConnect").await;
|
check_event(&mut client, &plugin_manager, "onConnect").await;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// read client message/buffer
|
// read client message/buffer
|
||||||
let buf = client.read()?;
|
let buf = client.read()?;
|
||||||
|
|
||||||
// run `onSend` events from plugins
|
// run `onSend` events from plugins
|
||||||
check_event(&mut client, &events, "onSend").await;
|
check_event(&mut client, &plugin_manager, "onSend").await;
|
||||||
|
|
||||||
// split message by whitespaces
|
// split message by whitespaces
|
||||||
let args: Vec<&str> = buf.split_ascii_whitespace().collect();
|
let args: Vec<&str> = buf.split_ascii_whitespace().collect();
|
||||||
|
@ -32,21 +31,21 @@ pub async fn handle_connection(
|
||||||
client.send("empty buffer").expect("send message");
|
client.send("empty buffer").expect("send message");
|
||||||
|
|
||||||
// don't execute the following commands because it causes panic
|
// don't execute the following commands because it causes panic
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get command from args
|
// get command from args
|
||||||
let cmd = args[0];
|
let cmd = args[0];
|
||||||
|
|
||||||
// search if a command exists
|
// search if a command exists
|
||||||
for command in commands.commands.iter() {
|
for command in plugin_manager.commands.iter() {
|
||||||
// if this is the entered command
|
// if this is the entered command
|
||||||
if cmd == command.name() {
|
if cmd == command.name() {
|
||||||
trace!("Executing a command `{}`", command.name());
|
trace!("Executing a command `{}`", command.name());
|
||||||
|
|
||||||
// execute command
|
// execute command
|
||||||
command
|
command
|
||||||
.execute(&mut client, args[1..args.len()].to_vec(), &commands)
|
.execute(&mut client, args[1..args.len()].to_vec(), &plugin_manager)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// don't search for more commands
|
// don't search for more commands
|
||||||
|
@ -65,7 +64,7 @@ pub async fn handle_connection(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for a events and execute it
|
/// Search for a events and execute it
|
||||||
async fn check_event(client: &mut Client, events: &EventManagerType, event_name: &str) {
|
async fn check_event(client: &mut Client, events: &PluginManagerType, event_name: &str) {
|
||||||
for event in events.events.iter() {
|
for event in events.events.iter() {
|
||||||
// check if this event should be started
|
// check if this event should be started
|
||||||
if event.name() == event_name {
|
if event.name() == event_name {
|
||||||
|
|
Loading…
Reference in a new issue