mirror of
https://github.com/MedzikUser/servers
synced 2024-08-14 23:57:48 +00:00
doc: update documentation
This commit is contained in:
parent
e75514a70e
commit
51440c98f9
8 changed files with 225 additions and 39 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
//! Build-in commands
|
||||||
|
|
||||||
mod help;
|
mod help;
|
||||||
|
|
||||||
use crate::plugins::Command;
|
use crate::plugins::Command;
|
||||||
|
|
21
src/lib.rs
21
src/lib.rs
|
@ -1,3 +1,24 @@
|
||||||
|
//! # Servers - Simple TCP server
|
||||||
|
//!
|
||||||
|
//! [image]: https://socialify.git.ci/MedzikUser/servers/image?description=1&font=KoHo&language=1&owner=1&pattern=Circuit%20Board&theme=Light
|
||||||
|
//!
|
||||||
|
//! [![image]](https://github.com/MedzikUser/servers)
|
||||||
|
//!
|
||||||
|
//! ## 👨💻 Building
|
||||||
|
//!
|
||||||
|
//! First clone the repository: `git clone https://github.com/MedzikUser/servers.git`
|
||||||
|
//!
|
||||||
|
//! ### Requirements
|
||||||
|
//! - Rust
|
||||||
|
//!
|
||||||
|
//! To build run the command: `cargo build --release`
|
||||||
|
//!
|
||||||
|
//! The compiled binary can be found in `./target/release/servers`
|
||||||
|
//!
|
||||||
|
//! ## Writing plugins
|
||||||
|
//!
|
||||||
|
//! Go to [plugins](plugins) module
|
||||||
|
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod plugins;
|
pub mod plugins;
|
||||||
pub mod tcp;
|
pub mod tcp;
|
||||||
|
|
39
src/main.rs
39
src/main.rs
|
@ -1,11 +1,16 @@
|
||||||
|
use std::net::TcpListener;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use servers::tcp;
|
use servers::{
|
||||||
|
plugins::loader,
|
||||||
|
tcp::{handle_connection, Client},
|
||||||
|
};
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[clap(
|
#[clap(
|
||||||
name = "servers",
|
name = "servers",
|
||||||
about = "Simple Tcp server that supports expansion via plugins"
|
about = "A simple TCP server for client which can be extended with plugins."
|
||||||
)]
|
)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[clap(
|
#[clap(
|
||||||
|
@ -34,7 +39,35 @@ fn main() -> anyhow::Result<()> {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
// start tcp server
|
// start tcp server
|
||||||
tcp::start_server(&cli.host, &cli.port)?;
|
start_server(&cli.host, &cli.port)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start tcp server
|
||||||
|
#[tokio::main]
|
||||||
|
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, commands and events
|
||||||
|
let (command_manager, _plugin_manager, event_manager) = loader()?;
|
||||||
|
|
||||||
|
// Accepts a new incoming connection from this listener.
|
||||||
|
while let Ok((stream, _address)) = listener.accept() {
|
||||||
|
let client = Client::new(stream);
|
||||||
|
|
||||||
|
// clone `CommandManager`
|
||||||
|
let command_manager = command_manager.clone();
|
||||||
|
// clone `EventManager`
|
||||||
|
let event_manager = event_manager.clone();
|
||||||
|
|
||||||
|
// handle client connection in new thread
|
||||||
|
tokio::spawn(handle_connection(client, command_manager, event_manager));
|
||||||
|
}
|
||||||
|
|
||||||
|
// server for a unexpectedly reason be terminated
|
||||||
|
panic!("Server unexpectedly terminated!")
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,161 @@
|
||||||
|
//! Plugins loader
|
||||||
|
//!
|
||||||
|
//! ## Writing plugins
|
||||||
|
//!
|
||||||
|
//! Create a new project `cargo new --lib plugin`
|
||||||
|
//!
|
||||||
|
//! Set a `crate-type` in Cargo.toml (to build a `.so` plugin)
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [lib]
|
||||||
|
//! crate-type = ["dylib"]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Add a `servers` and `async-trait` dependencies to Cargo.toml
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [dependencies]
|
||||||
|
//! async-trait = "0.1.56"
|
||||||
|
//! servers = { path = ".." }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Command plugin
|
||||||
|
//!
|
||||||
|
//! In file `src/lib.rs`
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use async_trait::async_trait;
|
||||||
|
//! use servers::{
|
||||||
|
//! plugins::{
|
||||||
|
//! Command, CommandManagerType, CommandRegistrar, EventRegistrar, Plugin,
|
||||||
|
//! PluginRegistrar,
|
||||||
|
//! },
|
||||||
|
//! tcp::Client,
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! struct PluginTest;
|
||||||
|
//!
|
||||||
|
//! #[async_trait]
|
||||||
|
//! impl Plugin for PluginTest {
|
||||||
|
//! /// Name of the plugin.
|
||||||
|
//! fn name(&self) -> &'static str {
|
||||||
|
//! "test"
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Function will be executed when plugin loading.
|
||||||
|
//! async fn on_plugin_load(&self) {
|
||||||
|
//! println!("Loading plugin `test`...")
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Function will be executed when plugin unloading.
|
||||||
|
//! async fn on_plugin_unload(&self) {
|
||||||
|
//! println!("Unloading plugin `test`...")
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[async_trait]
|
||||||
|
//! impl Command for PluginTest {
|
||||||
|
//! /// Command name
|
||||||
|
//! fn name(&self) -> &'static str {
|
||||||
|
//! "/test"
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Command help message
|
||||||
|
//! fn help(&self) -> &'static str {
|
||||||
|
//! "test command"
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Function will be executed when client send command `/test`
|
||||||
|
//! async fn execute(&self, client: &mut Client, _args: Vec<&str>, _commands: &CommandManagerType) {
|
||||||
|
//! client.send("Message sended by `test` plugin").expect("send message")
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Register plugin and command
|
||||||
|
//! #[no_mangle]
|
||||||
|
//! pub fn plugin_entry(
|
||||||
|
//! plugin: &mut dyn PluginRegistrar,
|
||||||
|
//! command: &mut dyn CommandRegistrar,
|
||||||
|
//! _event: &mut dyn EventRegistrar,
|
||||||
|
//! ) {
|
||||||
|
//! // register plugin
|
||||||
|
//! plugin.register(Box::new(PluginTest));
|
||||||
|
//! // register command
|
||||||
|
//! command.register(Box::new(PluginTest));
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ### Event plugin
|
||||||
|
//!
|
||||||
|
//! In file `src/lib.rs`
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use async_trait::async_trait;
|
||||||
|
//! use servers::{
|
||||||
|
//! plugins::{
|
||||||
|
//! CommandManagerType, CommandRegistrar, Event, EventRegistrar, Plugin,
|
||||||
|
//! PluginRegistrar,
|
||||||
|
//! },
|
||||||
|
//! tcp::Client,
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! struct PluginTest;
|
||||||
|
//!
|
||||||
|
//! #[async_trait]
|
||||||
|
//! impl Plugin for PluginTest {
|
||||||
|
//! /// Name of the plugin.
|
||||||
|
//! fn name(&self) -> &'static str {
|
||||||
|
//! "test"
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Function will be executed when plugin loading.
|
||||||
|
//! async fn on_plugin_load(&self) {
|
||||||
|
//! println!("Loading plugin `test`...")
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Function will be executed when plugin unloading.
|
||||||
|
//! async fn on_plugin_unload(&self) {
|
||||||
|
//! println!("Unloading plugin `test`...")
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[async_trait]
|
||||||
|
//! impl Event for PluginTest {
|
||||||
|
//! /// Event name (onConnect, onSend)
|
||||||
|
//! fn name(&self) -> &'static str {
|
||||||
|
//! "onConnect"
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Function will be executed when client connected
|
||||||
|
//! async fn execute(&self, client: &mut Client) {
|
||||||
|
//! client
|
||||||
|
//! .send(&format!("Welcome {}", client.stream.peer_addr().unwrap()))
|
||||||
|
//! .expect("send message")
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// Register plugin and command
|
||||||
|
//! #[no_mangle]
|
||||||
|
//! pub fn plugin_entry(
|
||||||
|
//! plugin: &mut dyn PluginRegistrar,
|
||||||
|
//! _command: &mut dyn CommandRegistrar,
|
||||||
|
//! event: &mut dyn EventRegistrar,
|
||||||
|
//! ) {
|
||||||
|
//! // register plugin
|
||||||
|
//! plugin.register(Box::new(PluginTest));
|
||||||
|
//! // register event
|
||||||
|
//! event.register(Box::new(PluginTest));
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## Build plugin
|
||||||
|
//!
|
||||||
|
//! To build plugin run command: `cargo build --release`
|
||||||
|
//!
|
||||||
|
//! The compiled plugin can be found in `./target/release/libplugin.so`
|
||||||
|
//!
|
||||||
|
//! Move compiled plugin to the `plugin` directory where servers is located
|
||||||
|
|
||||||
mod loader;
|
mod loader;
|
||||||
|
|
||||||
pub use loader::*;
|
pub use loader::*;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#![allow(clippy::unused_io_amount)]
|
#![allow(clippy::unused_io_amount)]
|
||||||
|
|
||||||
|
pub const MAX_PACKET_LEN: usize = 65536;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Read, Write},
|
io::{self, Read, Write},
|
||||||
net::TcpStream,
|
net::TcpStream,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// TCP Client stream
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
pub stream: TcpStream,
|
pub stream: TcpStream,
|
||||||
}
|
}
|
||||||
|
@ -17,8 +20,8 @@ impl Client {
|
||||||
|
|
||||||
/// Read message/buffer from Client
|
/// Read message/buffer from Client
|
||||||
pub fn read(&mut self) -> anyhow::Result<String> {
|
pub fn read(&mut self) -> anyhow::Result<String> {
|
||||||
// allocate an empty buffer of length 1024 bytes
|
// allocate an empty buffer
|
||||||
let mut buf = [0; 1024];
|
let mut buf = [0; MAX_PACKET_LEN];
|
||||||
|
|
||||||
// read buffer from stream
|
// read buffer from stream
|
||||||
self.stream.read(&mut buf)?;
|
self.stream.read(&mut buf)?;
|
||||||
|
|
|
@ -56,6 +56,7 @@ pub async fn handle_connection(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Search for a events and execute it
|
||||||
async fn check_event(client: &mut Client, events: &EventManagerType, event_name: &str) {
|
async fn check_event(client: &mut Client, events: &EventManagerType, event_name: &str) {
|
||||||
for event in events.events.iter() {
|
for event in events.events.iter() {
|
||||||
// check if this event should be started
|
// check if this event should be started
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
//! TCP connection utils
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod handle_connection;
|
mod handle_connection;
|
||||||
mod start;
|
|
||||||
|
|
||||||
pub use client::*;
|
pub use client::*;
|
||||||
pub use handle_connection::*;
|
pub use handle_connection::*;
|
||||||
pub use start::*;
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
use std::net::TcpListener;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
plugins::loader,
|
|
||||||
tcp::{handle_connection, Client},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[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 (command_manager, _plugin_manager, event_manager) = loader()?;
|
|
||||||
|
|
||||||
// Accepts a new incoming connection from this listener.
|
|
||||||
while let Ok((stream, _address)) = listener.accept() {
|
|
||||||
let client = Client::new(stream);
|
|
||||||
|
|
||||||
// clone `CommandManager`
|
|
||||||
let command_manager = command_manager.clone();
|
|
||||||
// clone `EventManager`
|
|
||||||
let event_manager = event_manager.clone();
|
|
||||||
|
|
||||||
// handle client connection in new thread
|
|
||||||
tokio::spawn(handle_connection(client, command_manager, event_manager));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
Loading…
Reference in a new issue