add event manager

This commit is contained in:
MedzikUser 2022-06-16 19:31:09 +02:00
parent 01f6ed8ad8
commit f0fd1b1d2a
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
5 changed files with 120 additions and 21 deletions

View File

@ -1,6 +1,9 @@
use async_trait::async_trait;
use servers::{
plugins::{Command, CommandManagerType, CommandRegistrar, Plugin, PluginRegistrar},
plugins::{
Command, CommandManagerType, CommandRegistrar, Event, EventRegistrar, Plugin,
PluginRegistrar,
},
tcp::Client,
};
@ -32,8 +35,29 @@ impl Command for PluginTest {
}
}
#[no_mangle]
pub fn plugin_entry(registrar: &mut dyn PluginRegistrar, command: &mut dyn CommandRegistrar) {
registrar.register_plugin(Box::new(PluginTest));
command.register_command(Box::new(PluginTest));
#[async_trait]
impl Event for PluginTest {
fn name(&self) -> &'static str {
"onConnect"
}
async fn execute(&self, client: &mut Client) {
client
.send(&format!("Welcome {}", client.stream.peer_addr().unwrap()))
.expect("send message")
}
}
#[no_mangle]
pub fn plugin_entry(
plugin: &mut dyn PluginRegistrar,
command: &mut dyn CommandRegistrar,
event: &mut dyn EventRegistrar,
) {
// register plugin
plugin.register(Box::new(PluginTest));
// register command
command.register(Box::new(PluginTest));
// register plugin
event.register(Box::new(PluginTest));
}

View File

@ -1,11 +1,9 @@
mod help;
pub use help::*;
use crate::plugins::Command;
/// Register default commands
pub fn register_commands() -> Vec<Box<dyn Command>> {
// create Vector with Commands
vec![Box::new(CommandHelp)]
vec![Box::new(help::CommandHelp)]
}

View File

@ -21,11 +21,11 @@ pub trait Plugin: Any + Send + Sync {
pub trait PluginRegistrar {
/// Function to register the plugin
fn register_plugin(&mut self, plugin: Box<dyn Plugin>);
fn register(&mut self, plugin: Box<dyn Plugin>);
}
impl PluginRegistrar for PluginManager {
fn register_plugin(&mut self, plugin: Box<dyn Plugin>) {
fn register(&mut self, plugin: Box<dyn Plugin>) {
self.plugins.push(plugin)
}
}
@ -91,17 +91,56 @@ pub type CommandManagerType = Arc<CommandManager>;
pub trait CommandRegistrar {
/// Function to register the plugin and the commands in the plugin
fn register_command(&mut self, command: Box<dyn Command>);
fn register(&mut self, command: Box<dyn Command>);
}
impl CommandRegistrar for CommandManager {
fn register_command(&mut self, command: Box<dyn Command>) {
fn register(&mut self, command: Box<dyn Command>) {
self.commands.push(command)
}
}
#[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 {
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()
}
}
pub type EventManagerType = Arc<EventManager>;
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
pub fn loader() -> anyhow::Result<(CommandManagerType, PluginManagerType)> {
pub fn loader() -> anyhow::Result<(CommandManagerType, PluginManagerType, EventManagerType)> {
// get path to .so lib from command argument
let config_dir = "./plugins";
let paths = fs::read_dir(config_dir)?;
@ -112,6 +151,9 @@ pub fn loader() -> anyhow::Result<(CommandManagerType, PluginManagerType)> {
// 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
for command in commands::register_commands() {
command_manager.commands.push(command)
@ -136,15 +178,27 @@ pub fn loader() -> anyhow::Result<(CommandManagerType, PluginManagerType)> {
// get `plugin_entry` from library
trace!("Finding symbol `plugin_entry` in `{}`", plugin_path);
let func: Symbol<
unsafe extern "C" fn(&mut dyn PluginRegistrar, &mut dyn CommandRegistrar) -> (),
unsafe extern "C" fn(
&mut dyn PluginRegistrar,
&mut dyn CommandRegistrar,
&mut dyn EventRegistrar,
) -> (),
> = lib.get(b"plugin_entry")?;
// execute initial plugin function
trace!("Running `plugin_entry(...)` in plugin `{}`", plugin_path);
func(&mut plugin_manager, &mut command_manager);
func(
&mut plugin_manager,
&mut command_manager,
&mut event_manager,
);
}
}
// return CommandManager and PluginManager
Ok((Arc::new(command_manager), Arc::new(plugin_manager)))
// return CommandManager, PluginManager and EventManager
Ok((
Arc::new(command_manager),
Arc::new(plugin_manager),
Arc::new(event_manager),
))
}

View File

@ -2,7 +2,7 @@ use std::io::Write;
use log::trace;
use crate::plugins::CommandManagerType;
use crate::plugins::{CommandManagerType, EventManagerType};
use super::Client;
@ -10,13 +10,20 @@ use super::Client;
pub async fn handle_connection(
mut client: Client,
commands: CommandManagerType,
events: EventManagerType,
) -> anyhow::Result<()> {
println!("New Client: {:?}", client.stream.peer_addr()?);
// run `onConnect` events from plugins
check_event(&mut client, &events, "onConnect").await;
loop {
// read client message/buffer
let buf = client.read()?;
// run `onSend` events from plugins
check_event(&mut client, &events, "onSend").await;
// split message by whitespace
let args: &Vec<&str> = &buf.split_ascii_whitespace().collect();
@ -27,8 +34,9 @@ pub async fn handle_connection(
for command in commands.commands.iter() {
// if this is the entered command
if cmd == command.name() {
// execute command
trace!("Executing a command `{}`", command.name());
// execute command
command
.execute(&mut client, args[1..args.len()].to_vec(), &commands)
.await;
@ -47,3 +55,15 @@ pub async fn handle_connection(
Ok(())
}
async fn check_event(client: &mut Client, events: &EventManagerType, event_name: &str) {
for event in events.events.iter() {
// check if this event should be started
if event.name() == event_name {
trace!("Executing a event `{}`", event.name());
// execute event
event.execute(client).await;
}
}
}

View File

@ -13,16 +13,19 @@ pub async fn start_server(host: &str, port: &str) -> anyhow::Result<()> {
println!("Tcp server started at: {}", listener.local_addr()?);
// load plugins and commands
let (command_manager, _plugin_manager) = loader()?;
let (command_manager, _plugin_manager, event_manager) = loader()?;
// Accepts a new incoming connection from this listener.
while let Ok((stream, _address)) = listener.accept() {
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
tokio::spawn(handle_connection(client, command_manager));
tokio::spawn(handle_connection(client, command_manager, event_manager));
}
Ok(())