chore: some changes (more in the commit description)

- added `/disconnect` commands
- moved logger init function to other file
- updated command description
- the `/help` command has been accelerated
- re-export `async_trait` so that it doesn't have to be added to dependencies in plugins
This commit is contained in:
MedzikUser 2022-07-29 21:55:21 +02:00
parent 6ad4afb146
commit 3fb0a1132a
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
14 changed files with 103 additions and 42 deletions

1
Cargo.lock generated
View File

@ -474,7 +474,6 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
name = "plugin_test"
version = "0.1.0"
dependencies = [
"async-trait",
"servers",
]

View File

@ -7,5 +7,4 @@ edition = "2021"
crate-type = ["dylib"]
[dependencies]
async-trait = "0.1.56"
servers = { path = ".." }

View File

@ -1,7 +1,6 @@
use async_trait::async_trait;
use servers::{
plugins::{Command, Event, Plugin, PluginManagerType, Registrar, Result},
tcp::Client,
tcp::Client, async_trait,
};
struct PluginTest;
@ -29,7 +28,7 @@ impl Command for PluginTest {
/// Help message of the command
fn help(&self) -> &'static str {
"test command"
"Test command from plugin"
}
/// Command function
@ -55,7 +54,9 @@ impl Event for PluginTest {
/// Event function
async fn execute(&self, client: &mut Client) -> Result<()> {
client.send(&format!("Welcome {}", client.stream.peer_addr().unwrap())).await?;
client
.send(&format!("Welcome {}", client.stream.peer_addr().unwrap()))
.await?;
Ok(())
}

View File

@ -0,0 +1,32 @@
use async_trait::async_trait;
use tokio::io::AsyncWriteExt;
use crate::{
plugins::{Command, PluginManagerType, Result},
tcp::Client,
};
pub struct CommandDisconnect;
#[async_trait]
impl Command for CommandDisconnect {
fn name(&self) -> &'static str {
"/disconnect"
}
fn help(&self) -> &'static str {
"Disconnect from the server"
}
async fn execute(
&self,
client: &mut Client,
_args: Vec<&str>,
_plugin_manager: &PluginManagerType,
) -> Result<()> {
// close the connection
client.stream.shutdown().await?;
Ok(())
}
}

View File

@ -14,7 +14,7 @@ impl Command for CommandHelp {
}
fn help(&self) -> &'static str {
"show help"
"Display all available commands"
}
async fn execute(
@ -23,10 +23,17 @@ impl Command for CommandHelp {
_args: Vec<&str>,
plugin_manager: &PluginManagerType,
) -> Result<()> {
// Vector which will contain help messages of the commands
let mut help = Vec::new();
for command in plugin_manager.commands.iter() {
client.send(&format!("{} - {}", command.name(), command.help())).await?;
// add a help message for the command
help.push(format!("{} - {}", command.name(), command.help()));
}
// send help message to the client
client.send(help.join("\n\r")).await?;
Ok(())
}
}

View File

@ -1,5 +1,6 @@
//! Build-in commands
mod disconnect;
mod help;
use crate::plugins::Command;
@ -7,5 +8,8 @@ use crate::plugins::Command;
/// Register build-in commands
pub fn register_commands() -> Vec<Box<dyn Command>> {
// create array with build-in commands
vec![Box::new(help::CommandHelp)]
vec![
Box::new(help::CommandHelp),
Box::new(disconnect::CommandDisconnect),
]
}

View File

@ -20,9 +20,11 @@
//! Go to [plugins](plugins) module
#![doc(html_root_url = "https://servers.medzik.xyz")]
#![warn(missing_docs)]
pub mod commands;
pub mod logger;
mod macros;
pub mod plugins;
pub mod tcp;
mod macros;
pub use async_trait::async_trait;

9
src/logger.rs Normal file
View File

@ -0,0 +1,9 @@
use tracing::metadata::LevelFilter;
pub fn init() {
better_panic::install();
tracing_subscriber::fmt()
.with_max_level(LevelFilter::TRACE)
.init();
}

View File

@ -1,6 +1,7 @@
use clap::Parser;
use cli::Cli;
use servers::{
logger,
plugins::loader,
tcp::{handle_connection, handle_websocket, Client},
};
@ -11,10 +12,7 @@ mod cli;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// init better panic
better_panic::install();
// init logger
tracing_subscriber::fmt().init();
logger::init();
// parse cli args
let args = Cli::parse();
@ -29,13 +27,13 @@ async fn main() -> anyhow::Result<()> {
}
// start tcp server
start_tcp_server(&args.host, &args.port).await?;
start_tcp_server(args.host, args.port).await?;
Ok(())
}
/// Start tcp server
async fn start_tcp_server(host: &str, port: &str) -> anyhow::Result<()> {
async fn start_tcp_server(host: String, port: String) -> anyhow::Result<()> {
// listen Tcp server
let listener = TcpListener::bind(format!("{host}:{port}")).await?;
@ -51,11 +49,14 @@ async fn start_tcp_server(host: &str, port: &str) -> anyhow::Result<()> {
// handle client connection in new thread
tokio::spawn(async move {
let ip = client.stream.peer_addr().unwrap();
// get ip address of the client
let ip = client
.stream
.peer_addr()
.expect("failed to get peer address");
match handle_connection(client, plugin_manager).await {
Ok(_) => (),
Err(err) => error!("Client {}, {}", ip, err),
if let Err(e) = handle_connection(client, plugin_manager).await {
error!("Client {ip}: {e}")
}
});
}
@ -75,11 +76,11 @@ async fn start_ws_server(host: String, port: String, tcp_port: String) -> anyhow
while let Ok((stream, _address)) = listener.accept().await {
let tcp_port = tcp_port.clone();
tokio::spawn(async {
let ip = stream.peer_addr().unwrap();
// get ip address of the client
let ip = stream.peer_addr().expect("failed to get peer address");
match handle_websocket(stream, tcp_port).await {
Ok(_) => (),
Err(err) => error!("Client {}, {}", ip, err),
if let Err(e) = handle_websocket(stream, tcp_port).await {
error!("Client {ip}: {e}")
}
});
}

View File

@ -1,7 +1,7 @@
use std::{fs, sync::Arc, path::Path};
use std::{fs, path::Path, sync::Arc};
use libloading::{Library, Symbol};
use tracing::{debug, trace};
use tracing::{info, trace};
use crate::{commands, plugins::Registrar};
@ -33,7 +33,7 @@ pub fn loader() -> anyhow::Result<PluginManagerType> {
let path = path?.path();
let plugin_path = path.to_str().unwrap();
debug!("Loading plugin `{}`", plugin_path);
info!("Loading plugin `{}`", plugin_path);
// loading library from .so is unsafe
unsafe {
@ -41,13 +41,16 @@ pub fn loader() -> anyhow::Result<PluginManagerType> {
// Box::new and Box::leak must be there because if it isn't there it throws a segmentation fault
let lib = Box::leak(Box::new(Library::new(&path)?));
// get `plugin_entry` from library
// get function `plugin_entry` from library
trace!("Finding symbol `plugin_entry` in `{}`", plugin_path);
let func: Symbol<unsafe extern "C" fn(&mut dyn Registrar) -> ()> =
lib.get(b"plugin_entry")?;
// execute initial plugin function
trace!("Running `plugin_entry(...)` in plugin `{}`", plugin_path);
trace!(
"Running function `plugin_entry` from plugin `{}`",
plugin_path
);
func(&mut plugin_manager);
}
}

View File

@ -15,15 +15,13 @@
//!
//! ```toml
//! [dependencies]
//! async-trait = "0.1.56"
//! servers = "0.1.0"
//! servers = { git = "https://github.com/MedzikUser/servers" }
//! ```
//!
//! In file `src/lib.rs`
//!
//! ```no_run
//! use async_trait::async_trait;
//! use servers::{plugins::{Plugin, Registrar}, tcp::Client};
//! use servers::{plugins::{Plugin, Registrar}, tcp::Client, async_trait};
//!
//! struct PluginTest;
//!
@ -50,9 +48,8 @@
//! ## Add command
//!
//! ```no_run
//! use async_trait::async_trait;
//! use servers::{
//! plugins::{Command, PluginManagerType, Registrar, Result},
//! plugins::{Command, PluginManagerType, Registrar, Result, async_trait},
//! tcp::Client,
//! };
//! #
@ -104,9 +101,8 @@
//! In file `src/lib.rs`
//!
//! ```no_run
//! use async_trait::async_trait;
//! use servers::{
//! plugins::{Event, Registrar, Result},
//! plugins::{Event, Registrar, Result, async_trait},
//! tcp::Client,
//! };
//! #

View File

@ -1,4 +1,9 @@
use tokio::{net::TcpStream, io::{self, AsyncWriteExt, AsyncReadExt}};
use core::fmt;
use tokio::{
io::{self, AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
/// Max size of a TCP packet
pub const MAX_PACKET_LEN: usize = 65536;
@ -33,7 +38,10 @@ impl Client {
}
/// Send message to the client
pub async fn send(&mut self, content: &str) -> io::Result<()> {
pub async fn send<S>(&mut self, content: S) -> io::Result<()>
where
S: ToString + fmt::Debug + fmt::Display,
{
// add a new line at the end of the content
let content = format!("{content}\n\r");

View File

@ -1,5 +1,5 @@
use tracing::{error, info, trace};
use tokio::io::AsyncWriteExt;
use tracing::{error, info, trace};
use crate::plugins::PluginManagerType;

View File

@ -4,7 +4,6 @@ use futures_util::{
stream::{SplitSink, SplitStream},
SinkExt, StreamExt,
};
use tracing::info;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::{
@ -13,6 +12,7 @@ use tokio::{
},
};
use tokio_tungstenite::WebSocketStream;
use tracing::info;
use tungstenite::Message;
use super::MAX_PACKET_LEN;