mirror of
https://github.com/MedzikUser/servers
synced 2024-08-14 23:57:48 +00:00
refactor code and add debug and trace logger
This commit is contained in:
parent
3975102736
commit
969be3498b
12 changed files with 122 additions and 95 deletions
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -87,6 +87,17 @@ dependencies = [
|
||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colored"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"lazy_static",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
|
@ -236,9 +247,22 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"libloading",
|
"libloading",
|
||||||
"log",
|
"log",
|
||||||
|
"simple_logger",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simple_logger"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75a9723083573ace81ad0cdfc50b858aa3c366c48636edb4109d73122a0c0ea"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"colored",
|
||||||
|
"log",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
|
@ -280,6 +304,18 @@ dependencies = [
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"tokio-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-macros"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -11,5 +11,6 @@ anyhow = "1.0.57"
|
||||||
async-trait = "0.1.56"
|
async-trait = "0.1.56"
|
||||||
clap = { version = "3.1.18", features = ["derive"] }
|
clap = { version = "3.1.18", features = ["derive"] }
|
||||||
libloading = "0.7.3"
|
libloading = "0.7.3"
|
||||||
log = "0.4.17"
|
log = { version = "0.4.17", features = ["release_max_level_info", "max_level_trace"] }
|
||||||
tokio = { version = "1.19.0", features = ["rt-multi-thread"] }
|
simple_logger = { version = "2.1.0", default-features = false, features = ["colors"] }
|
||||||
|
tokio = { version = "1.19.0", features = ["rt-multi-thread", "macros"] }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use servers::{
|
use servers::{
|
||||||
tcp::Client, Command, CommandManagerType, CommandRegistrar, Plugin, PluginRegistrar,
|
plugins::{Command, CommandManagerType, CommandRegistrar, Plugin, PluginRegistrar},
|
||||||
|
tcp::Client,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PluginTest;
|
struct PluginTest;
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
use std::{any::Any, sync::Arc};
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
|
|
||||||
use crate::tcp::Client;
|
|
||||||
|
|
||||||
#[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>, commands: &CommandManagerType);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CommandManager {
|
|
||||||
/// Vector with plugins
|
|
||||||
pub commands: Vec<Box<dyn Command>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandManager {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
commands: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for CommandManager {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type CommandManagerType = Arc<Vec<Box<dyn Command>>>;
|
|
|
@ -1,6 +1,9 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
use crate::{command_handler::Command, tcp::Client, CommandManagerType};
|
use crate::{
|
||||||
|
plugins::{Command, CommandManagerType},
|
||||||
|
tcp::Client,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct CommandHelp;
|
pub struct CommandHelp;
|
||||||
|
|
||||||
|
@ -14,8 +17,13 @@ impl Command for CommandHelp {
|
||||||
"show help"
|
"show help"
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, client: &mut Client, _args: Vec<&str>, commands: &CommandManagerType) {
|
async fn execute(
|
||||||
for command in commands.iter() {
|
&self,
|
||||||
|
client: &mut Client,
|
||||||
|
_args: Vec<&str>,
|
||||||
|
command_manager: &CommandManagerType,
|
||||||
|
) {
|
||||||
|
for command in command_manager.commands.iter() {
|
||||||
client
|
client
|
||||||
.send(&format!("{} - {}", command.name(), command.help()))
|
.send(&format!("{} - {}", command.name(), command.help()))
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
#![allow(clippy::vec_init_then_push)]
|
|
||||||
|
|
||||||
mod help;
|
mod help;
|
||||||
|
|
||||||
pub use help::*;
|
pub use help::*;
|
||||||
|
|
||||||
use crate::command_handler::Command;
|
use crate::plugins::Command;
|
||||||
|
|
||||||
pub fn register_commands() -> Vec<Box<dyn Command>> {
|
pub fn register_commands() -> Vec<Box<dyn Command>> {
|
||||||
let mut commands: Vec<Box<dyn Command>> = Vec::new();
|
vec![Box::new(CommandHelp)]
|
||||||
|
|
||||||
commands.push(Box::new(CommandHelp));
|
|
||||||
|
|
||||||
commands
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
mod command_handler;
|
pub mod commands;
|
||||||
mod commands;
|
pub mod plugins;
|
||||||
mod plugin_loader;
|
|
||||||
|
|
||||||
pub use command_handler::*;
|
|
||||||
pub use plugin_loader::*;
|
|
||||||
|
|
||||||
pub mod tcp;
|
pub mod tcp;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use servers::tcp;
|
use servers::tcp;
|
||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(
|
#[clap(
|
||||||
|
@ -26,6 +27,9 @@ struct Cli {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
SimpleLogger::new().init()?;
|
||||||
|
|
||||||
|
// parse cli args
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
// start tcp server
|
// start tcp server
|
||||||
|
|
|
@ -4,7 +4,7 @@ use async_trait::async_trait;
|
||||||
use libloading::{Library, Symbol};
|
use libloading::{Library, Symbol};
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
|
|
||||||
use crate::{commands, Command, CommandManager, CommandManagerType};
|
use crate::{commands, tcp::Client};
|
||||||
|
|
||||||
/// A plugin which allows you to add extra functionality.
|
/// A plugin which allows you to add extra functionality.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -20,7 +20,6 @@ pub trait Plugin: Any + Send + Sync {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PluginManager {
|
pub struct PluginManager {
|
||||||
/// Vector with loaded plugins
|
|
||||||
pub plugins: Vec<Box<dyn Plugin>>,
|
pub plugins: Vec<Box<dyn Plugin>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,17 +30,6 @@ impl PluginManager {
|
||||||
plugins: Vec::new(),
|
plugins: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unload all plugins and loaded plugin libraries, making sure to fire
|
|
||||||
/// their `on_plugin_unload()` methods so they can do any necessary cleanup.
|
|
||||||
pub async fn unload(&mut self) {
|
|
||||||
debug!("Unloading plugins");
|
|
||||||
|
|
||||||
for plugin in self.plugins.drain(..) {
|
|
||||||
trace!("Firing on_plugin_unload for {:?}", plugin.name());
|
|
||||||
plugin.on_plugin_unload().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PluginManager {
|
impl Default for PluginManager {
|
||||||
|
@ -60,6 +48,42 @@ impl PluginRegistrar for PluginManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CommandManager {
|
||||||
|
/// Vector with plugins
|
||||||
|
pub commands: Vec<Box<dyn Command>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandManager {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
commands: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type CommandManagerType = Arc<CommandManager>;
|
||||||
|
|
||||||
|
impl Default for CommandManager {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait CommandRegistrar {
|
pub trait CommandRegistrar {
|
||||||
fn register_plugin(&mut self, command: Box<dyn Command>);
|
fn register_plugin(&mut self, command: Box<dyn Command>);
|
||||||
}
|
}
|
||||||
|
@ -70,9 +94,7 @@ impl CommandRegistrar for CommandManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PluginManagerType = Arc<Vec<Box<dyn Plugin>>>;
|
pub fn loader() -> anyhow::Result<(Arc<CommandManager>, Arc<PluginManager>)> {
|
||||||
|
|
||||||
pub fn loader() -> anyhow::Result<(PluginManagerType, CommandManagerType)> {
|
|
||||||
// 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)?;
|
||||||
|
@ -93,33 +115,28 @@ pub fn loader() -> anyhow::Result<(PluginManagerType, CommandManagerType)> {
|
||||||
// get library file path
|
// get library file path
|
||||||
let path = path?.path();
|
let path = path?.path();
|
||||||
|
|
||||||
|
let plugin_path = path.to_str().unwrap_or("unknown");
|
||||||
|
|
||||||
|
// log debug info
|
||||||
|
debug!("Loading plugin `{}`", plugin_path);
|
||||||
|
|
||||||
// loading library with .so is unsafe
|
// loading library with .so is unsafe
|
||||||
unsafe {
|
unsafe {
|
||||||
// load library
|
// load library
|
||||||
// Box::new and Box::leak must be there because if it isn't there it throws a segmentation fault
|
// 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)?));
|
let lib = Box::leak(Box::new(Library::new(&path)?));
|
||||||
|
|
||||||
// get `plugin_entry` from library
|
// get `plugin_entry` from library
|
||||||
|
trace!("Finding symbol `plugin_entry` in `{}`", plugin_path);
|
||||||
let func: Symbol<
|
let func: Symbol<
|
||||||
unsafe extern "C" fn(&mut dyn PluginRegistrar, &mut dyn CommandRegistrar) -> (),
|
unsafe extern "C" fn(&mut dyn PluginRegistrar, &mut dyn CommandRegistrar) -> (),
|
||||||
> = lib.get(b"plugin_entry")?;
|
> = lib.get(b"plugin_entry")?;
|
||||||
|
|
||||||
// execute initial function
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Arc in Vector
|
Ok((Arc::new(command_manager), Arc::new(plugin_manager)))
|
||||||
let mut commands = Vec::new();
|
|
||||||
for command in command_manager.commands {
|
|
||||||
commands.push(command)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create Arc in Vector
|
|
||||||
let mut plugins = Vec::new();
|
|
||||||
for plugin in plugin_manager.plugins {
|
|
||||||
plugins.push(plugin)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((Arc::new(plugins), Arc::new(commands)))
|
|
||||||
}
|
}
|
3
src/plugins/mod.rs
Normal file
3
src/plugins/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mod loader;
|
||||||
|
|
||||||
|
pub use loader::*;
|
|
@ -1,6 +1,8 @@
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use crate::CommandManagerType;
|
use log::trace;
|
||||||
|
|
||||||
|
use crate::plugins::CommandManagerType;
|
||||||
|
|
||||||
use super::Client;
|
use super::Client;
|
||||||
|
|
||||||
|
@ -21,10 +23,11 @@ pub async fn handle_connection(
|
||||||
let cmd = args[0];
|
let cmd = args[0];
|
||||||
|
|
||||||
// search if a command exists
|
// search if a command exists
|
||||||
for command in commands.iter() {
|
for command in commands.commands.iter() {
|
||||||
// if this is the entered command
|
// if this is the entered command
|
||||||
if cmd == command.name() {
|
if cmd == command.name() {
|
||||||
// execute command
|
// execute command
|
||||||
|
trace!("Executing a command `{}`", command.name());
|
||||||
command
|
command
|
||||||
.execute(&mut client, args[1..args.len()].to_vec(), &commands)
|
.execute(&mut client, args[1..args.len()].to_vec(), &commands)
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
loader,
|
plugins::loader,
|
||||||
tcp::{handle_connection, Client},
|
tcp::{handle_connection, Client},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn start_server(host: &str, port: &str) -> anyhow::Result<()> {
|
#[tokio::main]
|
||||||
|
pub async fn start_server(host: &str, port: &str) -> anyhow::Result<()> {
|
||||||
// listen Tcp server
|
// listen Tcp server
|
||||||
let listener = TcpListener::bind(format!("{host}:{port}"))?;
|
let listener = TcpListener::bind(format!("{host}:{port}"))?;
|
||||||
|
|
||||||
println!("Tcp server started at: {}", listener.local_addr()?);
|
println!("Tcp server started at: {}", listener.local_addr()?);
|
||||||
|
|
||||||
// load plugins and commands
|
// load plugins and commands
|
||||||
let (_plugin_manager, commands_manager) = loader()?;
|
let (command_manager, _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);
|
||||||
|
|
||||||
let commands_manager = commands_manager.clone();
|
let command_manager = command_manager.clone();
|
||||||
|
|
||||||
// handle client connection in new thread
|
// handle client connection in new thread
|
||||||
tokio::spawn(handle_connection(client, commands_manager));
|
tokio::spawn(handle_connection(client, command_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue