doc: update documentation

This commit is contained in:
MedzikUser 2022-06-17 13:43:23 +02:00
parent e75514a70e
commit 51440c98f9
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
8 changed files with 225 additions and 39 deletions

View File

@ -1,3 +1,5 @@
//! Build-in commands
mod help;
use crate::plugins::Command;

View File

@ -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 plugins;
pub mod tcp;

View File

@ -1,11 +1,16 @@
use std::net::TcpListener;
use clap::Parser;
use servers::tcp;
use servers::{
plugins::loader,
tcp::{handle_connection, Client},
};
use simple_logger::SimpleLogger;
#[derive(Parser)]
#[clap(
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 {
#[clap(
@ -34,7 +39,35 @@ fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
// start tcp server
tcp::start_server(&cli.host, &cli.port)?;
start_server(&cli.host, &cli.port)?;
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!")
}

View File

@ -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;
pub use loader::*;

View File

@ -1,10 +1,13 @@
#![allow(clippy::unused_io_amount)]
pub const MAX_PACKET_LEN: usize = 65536;
use std::{
io::{self, Read, Write},
net::TcpStream,
};
/// TCP Client stream
pub struct Client {
pub stream: TcpStream,
}
@ -17,8 +20,8 @@ impl Client {
/// Read message/buffer from Client
pub fn read(&mut self) -> anyhow::Result<String> {
// allocate an empty buffer of length 1024 bytes
let mut buf = [0; 1024];
// allocate an empty buffer
let mut buf = [0; MAX_PACKET_LEN];
// read buffer from stream
self.stream.read(&mut buf)?;

View File

@ -56,6 +56,7 @@ pub async fn handle_connection(
Ok(())
}
/// Search for a events and execute it
async fn check_event(client: &mut Client, events: &EventManagerType, event_name: &str) {
for event in events.events.iter() {
// check if this event should be started

View File

@ -1,7 +1,7 @@
//! TCP connection utils
mod client;
mod handle_connection;
mod start;
pub use client::*;
pub use handle_connection::*;
pub use start::*;

View File

@ -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(())
}