From 67fb1a0a3c96fe9fc18bdc5a3a31d914217608e6 Mon Sep 17 00:00:00 2001 From: MedzikUser Date: Wed, 17 Aug 2022 21:44:06 +0200 Subject: [PATCH] feat(server): add `onCommand` event and handle errors in message processing Added `OnCommand` event e.g. to disable command for client. (BREAKING CHANGES IN EVENT PLUGINS) Added function for error handling in message process. --- plugin_test/src/lib.rs | 2 +- src/plugins/types.rs | 15 +++++++- src/server/client.rs | 13 +++++-- src/server/run.rs | 84 ++++++++++++++++++++++++++++-------------- 4 files changed, 81 insertions(+), 33 deletions(-) diff --git a/plugin_test/src/lib.rs b/plugin_test/src/lib.rs index ab1f4f7..520785d 100644 --- a/plugin_test/src/lib.rs +++ b/plugin_test/src/lib.rs @@ -42,7 +42,7 @@ impl Event for PluginTest { EventType::OnConnect } - async fn execute(&self, client: &Client) -> anyhow::Result<()> { + async fn execute(&self, client: &Client, _data: EventData) -> anyhow::Result<()> { client.send("Hello!") } } diff --git a/src/plugins/types.rs b/src/plugins/types.rs index 4014acc..cb05ebf 100644 --- a/src/plugins/types.rs +++ b/src/plugins/types.rs @@ -29,12 +29,23 @@ pub trait Command: Any + Send + Sync { } /// All possible to run events. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum EventType { /// On client connected. OnConnect, /// On client sent message. OnSend, + /// Event executed before command execute (e.g. for disable command). + OnCommand, +} + +/// All possible to run events. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum EventData { + /// for `onCommand` event + Command(String), + /// No data + None, } /// Add a event to the plugin. @@ -43,7 +54,7 @@ pub trait Event: Any + Send + Sync { /// Type of the event. fn event(&self) -> EventType; /// Event function. - async fn execute(&self, client: &Client) -> anyhow::Result<()>; + async fn execute(&self, client: &Client, data: EventData) -> anyhow::Result<()>; } pub trait Registrar { diff --git a/src/server/client.rs b/src/server/client.rs index 5f1480e..22db2dd 100644 --- a/src/server/client.rs +++ b/src/server/client.rs @@ -9,7 +9,10 @@ use std::{ use tungstenite::{accept, Message, WebSocket}; use super::run::PLUGINS_MANAGER; -use crate::plugins::{manager::PluginsManagerType, prelude::EventType}; +use crate::plugins::{ + manager::PluginsManagerType, + prelude::{EventData, EventType}, +}; /// Max length of a TCP and UDP packet pub const MAX_PACKET_LEN: usize = 65536; @@ -208,10 +211,14 @@ impl Client { self.map.lock().unwrap().remove(&key.to_string()) } - pub async fn run_events(&self, event_type: EventType) -> anyhow::Result<()> { + pub async fn run_events( + &self, + event_type: EventType, + event_data: EventData, + ) -> anyhow::Result<()> { for event in self.plugins_manager.events.iter() { if event.event() == event_type { - event.execute(self).await?; + event.execute(self, event_data.clone()).await?; } } diff --git a/src/server/run.rs b/src/server/run.rs index 8af8dde..57ecb50 100644 --- a/src/server/run.rs +++ b/src/server/run.rs @@ -6,7 +6,11 @@ use lazy_static::lazy_static; use tracing::{error, info, span, Level}; use crate::{ - plugins::{self, manager::PluginsManagerType, prelude::EventType}, + plugins::{ + self, + manager::PluginsManagerType, + prelude::{EventData, EventType}, + }, server::Client, CLIENTS, CLIENT_NEXT, }; @@ -47,40 +51,66 @@ async fn process(client: Client) -> anyhow::Result<()> { info!("Processing client connection: {}", client_addr); // run `onConnect` events - client.run_events(EventType::OnConnect).await?; + client + .run_events(EventType::OnConnect, EventData::None) + .await?; loop { let buf = client.read()?; - // run `onSend` events - client.run_events(EventType::OnSend).await?; + // functions for error handling see `if` below function + async fn handle(client: &Client, buf: String) -> anyhow::Result<()> { + // run `onSend` events + client + .run_events(EventType::OnSend, EventData::None) + .await?; - let mut args: Vec<&str> = buf.split_ascii_whitespace().collect(); + let mut args: Vec<&str> = buf.split_ascii_whitespace().collect(); - // if client sent an empty buffer - if args.is_empty() { - client.send("empty buffer")?; - continue; + // if client sent an empty buffer + if args.is_empty() { + client.send("empty buffer")?; + return Ok(()); + } + + let cmd = args[0]; + + // remove command name from args + args = args[1..args.len()].to_vec(); + + // find command + let command = client + .plugins_manager + .commands + .iter() + .enumerate() + .find(|&(_i, command)| command.name() == cmd || command.aliases().contains(&cmd)); + + // execute command, if command isn't blocked + // to block a command return error in the `onCommand` event + if let Some((_i, cmd)) = command { + // run `onCommand` events + if let Ok(_) = client + .run_events( + EventType::OnCommand, + EventData::Command(cmd.name().to_string()), + ) + .await + { + // execute command + cmd.execute(&client, args).await?; + } + } else { + client.send("unknown command")?; + } + + Ok(()) } - let cmd = args[0]; - - // remove command name from args - args = args[1..args.len()].to_vec(); - - // find command - let command = client - .plugins_manager - .commands - .iter() - .enumerate() - .find(|&(_i, command)| command.name() == cmd || command.aliases().contains(&cmd)); - - // execute command - if let Some((_i, cmd)) = command { - cmd.execute(&client, args).await?; - } else { - client.send("unknown command")?; + // handle errors from message processing + if let Err(err) = handle(&client, buf).await { + error!("Unexpected error in message handler: {}", err); + client.send("Unexpected error")?; } client.flush()?;