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",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
|
@ -236,9 +247,22 @@ dependencies = [
|
|||
"clap",
|
||||
"libloading",
|
||||
"log",
|
||||
"simple_logger",
|
||||
"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]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
|
@ -280,6 +304,18 @@ dependencies = [
|
|||
"num_cpus",
|
||||
"once_cell",
|
||||
"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]]
|
||||
|
|
|
@ -11,5 +11,6 @@ anyhow = "1.0.57"
|
|||
async-trait = "0.1.56"
|
||||
clap = { version = "3.1.18", features = ["derive"] }
|
||||
libloading = "0.7.3"
|
||||
log = "0.4.17"
|
||||
tokio = { version = "1.19.0", features = ["rt-multi-thread"] }
|
||||
log = { version = "0.4.17", features = ["release_max_level_info", "max_level_trace"] }
|
||||
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 servers::{
|
||||
tcp::Client, Command, CommandManagerType, CommandRegistrar, Plugin, PluginRegistrar,
|
||||
plugins::{Command, CommandManagerType, CommandRegistrar, Plugin, PluginRegistrar},
|
||||
tcp::Client,
|
||||
};
|
||||
|
||||
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 crate::{command_handler::Command, tcp::Client, CommandManagerType};
|
||||
use crate::{
|
||||
plugins::{Command, CommandManagerType},
|
||||
tcp::Client,
|
||||
};
|
||||
|
||||
pub struct CommandHelp;
|
||||
|
||||
|
@ -14,8 +17,13 @@ impl Command for CommandHelp {
|
|||
"show help"
|
||||
}
|
||||
|
||||
async fn execute(&self, client: &mut Client, _args: Vec<&str>, commands: &CommandManagerType) {
|
||||
for command in commands.iter() {
|
||||
async fn execute(
|
||||
&self,
|
||||
client: &mut Client,
|
||||
_args: Vec<&str>,
|
||||
command_manager: &CommandManagerType,
|
||||
) {
|
||||
for command in command_manager.commands.iter() {
|
||||
client
|
||||
.send(&format!("{} - {}", command.name(), command.help()))
|
||||
.await
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
#![allow(clippy::vec_init_then_push)]
|
||||
|
||||
mod help;
|
||||
|
||||
pub use help::*;
|
||||
|
||||
use crate::command_handler::Command;
|
||||
use crate::plugins::Command;
|
||||
|
||||
pub fn register_commands() -> Vec<Box<dyn Command>> {
|
||||
let mut commands: Vec<Box<dyn Command>> = Vec::new();
|
||||
|
||||
commands.push(Box::new(CommandHelp));
|
||||
|
||||
commands
|
||||
vec![Box::new(CommandHelp)]
|
||||
}
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
mod command_handler;
|
||||
mod commands;
|
||||
mod plugin_loader;
|
||||
|
||||
pub use command_handler::*;
|
||||
pub use plugin_loader::*;
|
||||
|
||||
pub mod commands;
|
||||
pub mod plugins;
|
||||
pub mod tcp;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use clap::Parser;
|
||||
use servers::tcp;
|
||||
use simple_logger::SimpleLogger;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(
|
||||
|
@ -26,6 +27,9 @@ struct Cli {
|
|||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
SimpleLogger::new().init()?;
|
||||
|
||||
// parse cli args
|
||||
let cli = Cli::parse();
|
||||
|
||||
// start tcp server
|
||||
|
|
|
@ -4,7 +4,7 @@ use async_trait::async_trait;
|
|||
use libloading::{Library, Symbol};
|
||||
use log::{debug, trace};
|
||||
|
||||
use crate::{commands, Command, CommandManager, CommandManagerType};
|
||||
use crate::{commands, tcp::Client};
|
||||
|
||||
/// A plugin which allows you to add extra functionality.
|
||||
#[async_trait]
|
||||
|
@ -20,7 +20,6 @@ pub trait Plugin: Any + Send + Sync {
|
|||
}
|
||||
|
||||
pub struct PluginManager {
|
||||
/// Vector with loaded plugins
|
||||
pub plugins: Vec<Box<dyn Plugin>>,
|
||||
}
|
||||
|
||||
|
@ -31,17 +30,6 @@ impl PluginManager {
|
|||
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 {
|
||||
|
@ -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 {
|
||||
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<(PluginManagerType, CommandManagerType)> {
|
||||
pub fn loader() -> anyhow::Result<(Arc<CommandManager>, Arc<PluginManager>)> {
|
||||
// get path to .so lib from command argument
|
||||
let config_dir = "./plugins";
|
||||
let paths = fs::read_dir(config_dir)?;
|
||||
|
@ -93,33 +115,28 @@ pub fn loader() -> anyhow::Result<(PluginManagerType, CommandManagerType)> {
|
|||
// get library file 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
|
||||
unsafe {
|
||||
// load library
|
||||
// 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
|
||||
trace!("Finding symbol `plugin_entry` in `{}`", plugin_path);
|
||||
let func: Symbol<
|
||||
unsafe extern "C" fn(&mut dyn PluginRegistrar, &mut dyn CommandRegistrar) -> (),
|
||||
> = 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);
|
||||
}
|
||||
}
|
||||
|
||||
// create Arc in Vector
|
||||
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)))
|
||||
Ok((Arc::new(command_manager), Arc::new(plugin_manager)))
|
||||
}
|
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 crate::CommandManagerType;
|
||||
use log::trace;
|
||||
|
||||
use crate::plugins::CommandManagerType;
|
||||
|
||||
use super::Client;
|
||||
|
||||
|
@ -21,10 +23,11 @@ pub async fn handle_connection(
|
|||
let cmd = args[0];
|
||||
|
||||
// search if a command exists
|
||||
for command in commands.iter() {
|
||||
for command in commands.commands.iter() {
|
||||
// if this is the entered command
|
||||
if cmd == command.name() {
|
||||
// execute command
|
||||
trace!("Executing a command `{}`", command.name());
|
||||
command
|
||||
.execute(&mut client, args[1..args.len()].to_vec(), &commands)
|
||||
.await;
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
use std::net::TcpListener;
|
||||
|
||||
use crate::{
|
||||
loader,
|
||||
plugins::loader,
|
||||
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
|
||||
let listener = TcpListener::bind(format!("{host}:{port}"))?;
|
||||
|
||||
println!("Tcp server started at: {}", listener.local_addr()?);
|
||||
|
||||
// load plugins and commands
|
||||
let (_plugin_manager, commands_manager) = loader()?;
|
||||
let (command_manager, _plugin_manager) = loader()?;
|
||||
|
||||
// Accepts a new incoming connection from this listener.
|
||||
while let Ok((stream, _address)) = listener.accept() {
|
||||
let client = Client::new(stream);
|
||||
|
||||
let commands_manager = commands_manager.clone();
|
||||
let command_manager = command_manager.clone();
|
||||
|
||||
// handle client connection in new thread
|
||||
tokio::spawn(handle_connection(client, commands_manager));
|
||||
tokio::spawn(handle_connection(client, command_manager));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue