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.
This commit is contained in:
MedzikUser 2022-08-17 21:44:06 +02:00
parent 56e16145f6
commit 67fb1a0a3c
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
4 changed files with 81 additions and 33 deletions

View File

@ -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!")
}
}

View File

@ -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 {

View File

@ -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?;
}
}

View File

@ -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()?;