mirror of https://github.com/MedzikUser/servers
initial commit
This commit is contained in:
commit
a91b0cb788
|
@ -0,0 +1 @@
|
||||||
|
/target
|
|
@ -0,0 +1,262 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.126"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pin-project-lite"
|
||||||
|
version = "0.2.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "servers"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"libloading",
|
||||||
|
"log",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.96"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f392c8f16bda3456c0b00c6de39cb100449b98de55ac41c6cdd2bfcf53a1245"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"libc",
|
||||||
|
"memchr",
|
||||||
|
"mio",
|
||||||
|
"num_cpus",
|
||||||
|
"once_cell",
|
||||||
|
"pin-project-lite",
|
||||||
|
"socket2",
|
||||||
|
"tokio-macros",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "servers"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.57"
|
||||||
|
async-trait = "0.1.56"
|
||||||
|
libloading = "0.7.3"
|
||||||
|
log = "0.4.17"
|
||||||
|
tokio = { version = "1.19.0", features = ["rt-multi-thread", "macros", "net", "io-std", "io-util"] }
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Medzik
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,34 @@
|
||||||
|
#![allow(clippy::unused_io_amount)]
|
||||||
|
|
||||||
|
use tokio::{
|
||||||
|
io::{AsyncReadExt, AsyncWriteExt},
|
||||||
|
net::TcpStream,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Client {
|
||||||
|
pub stream: TcpStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
/// Create new Client
|
||||||
|
pub fn new(stream: TcpStream) -> Self {
|
||||||
|
Self { stream }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read message/buffer from Client
|
||||||
|
pub async fn read(&mut self) -> anyhow::Result<String> {
|
||||||
|
let mut buf = [0; 1024];
|
||||||
|
|
||||||
|
self.stream.read(&mut buf).await?;
|
||||||
|
|
||||||
|
let encoded = String::from_utf8(buf.to_vec())?.replace('\0', "");
|
||||||
|
|
||||||
|
Ok(encoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send message to Client
|
||||||
|
pub async fn send(&mut self, content: &str) -> anyhow::Result<()> {
|
||||||
|
self.stream.write_all(format!("{content}\n\r").as_bytes()).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
use std::{any::Any, sync::Arc};
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use crate::{Client, commands};
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Command: Any + Send + Sync {
|
||||||
|
/// Command name
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
/// Command help message
|
||||||
|
fn help(&self) -> &'static str;
|
||||||
|
/// Command function
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
client: &mut Client,
|
||||||
|
args: Vec<&str>,
|
||||||
|
plugins: &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 = Vec<Arc<Box<dyn Command>>>;
|
||||||
|
|
||||||
|
pub fn register_commands() -> CommandManagerType {
|
||||||
|
let mut command_manager = CommandManager::new();
|
||||||
|
|
||||||
|
for command in commands::register_commands() {
|
||||||
|
command_manager.commands.push(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create Arc in Vector
|
||||||
|
let mut commands: CommandManagerType = Vec::new();
|
||||||
|
for command in command_manager.commands {
|
||||||
|
commands.push(Arc::new(command))
|
||||||
|
}
|
||||||
|
|
||||||
|
commands
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use crate::{command_handler::Command, CommandManagerType};
|
||||||
|
|
||||||
|
pub struct CommandHelp;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Command for CommandHelp {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"/help"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help(&self) -> &'static str {
|
||||||
|
"show help"
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
client: &mut crate::Client,
|
||||||
|
_args: Vec<&str>,
|
||||||
|
commands: &CommandManagerType,
|
||||||
|
) {
|
||||||
|
for command in commands {
|
||||||
|
client
|
||||||
|
.send(&format!("{} - {}", command.name(), command.help()))
|
||||||
|
.await
|
||||||
|
.expect("send message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
mod help;
|
||||||
|
|
||||||
|
pub use help::*;
|
||||||
|
|
||||||
|
use crate::command_handler::Command;
|
||||||
|
|
||||||
|
pub fn register_commands() -> Vec<Box<dyn Command>> {
|
||||||
|
let mut commands: Vec<Box<dyn Command>> = Vec::new();
|
||||||
|
|
||||||
|
commands.push(Box::new(CommandHelp));
|
||||||
|
|
||||||
|
commands
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
mod client;
|
||||||
|
mod command_handler;
|
||||||
|
mod commands;
|
||||||
|
mod plugin_loader;
|
||||||
|
|
||||||
|
pub use client::*;
|
||||||
|
pub use command_handler::*;
|
||||||
|
pub use plugin_loader::*;
|
|
@ -0,0 +1,64 @@
|
||||||
|
use servers::{loader, Client, PluginManagerType, register_commands, CommandManagerType};
|
||||||
|
use tokio::{io::AsyncWriteExt, net::TcpListener};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
// listen Tcp server
|
||||||
|
let listener = TcpListener::bind("0.0.0.0:9999").await?;
|
||||||
|
|
||||||
|
// load plugins
|
||||||
|
let plugin_manager = loader()?;
|
||||||
|
|
||||||
|
// load command
|
||||||
|
let commands_manager = register_commands();
|
||||||
|
|
||||||
|
// Accepts a new incoming connection from this listener.
|
||||||
|
while let Ok((stream, _address)) = listener.accept().await {
|
||||||
|
let client = Client::new(stream);
|
||||||
|
|
||||||
|
// handle client connection in new thread
|
||||||
|
tokio::spawn(handle_connection(client, (*plugin_manager).to_vec(), (*commands_manager).to_vec()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_connection(mut client: Client, plugins: PluginManagerType, commands: CommandManagerType) -> anyhow::Result<()> {
|
||||||
|
println!("New Client: {:?}", client.stream.peer_addr()?);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// read client message/buffer
|
||||||
|
let buf = client.read().await?;
|
||||||
|
|
||||||
|
// split message by whitespace
|
||||||
|
let args: &Vec<&str> = &buf.split_ascii_whitespace().collect();
|
||||||
|
|
||||||
|
// get command from args
|
||||||
|
let cmd = args[0];
|
||||||
|
|
||||||
|
println!("{:?}", &args);
|
||||||
|
|
||||||
|
for command in &commands {
|
||||||
|
if cmd == command.name() {
|
||||||
|
println!("s");
|
||||||
|
command.execute(&mut client, args[1..args.len()].to_vec(), &commands).await;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// search command in plugins
|
||||||
|
for plugin in &plugins {
|
||||||
|
// if command found execute plugin
|
||||||
|
if cmd == plugin.command() {
|
||||||
|
plugin.execute(&mut client, args[1..args.len()].to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if an I/O or EOF error, abort the connection
|
||||||
|
if client.stream.flush().await.is_err() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
use std::{any::Any, fs, sync::Arc};
|
||||||
|
|
||||||
|
use libloading::{Library, Symbol};
|
||||||
|
use log::{debug, trace};
|
||||||
|
|
||||||
|
use crate::Client;
|
||||||
|
|
||||||
|
/// A plugin which allows you to add extra functionality.
|
||||||
|
pub trait Plugin: Any + Send + Sync {
|
||||||
|
/// Get a name describing the `Plugin`.
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
/// A function that runs immediately after plugin loading.
|
||||||
|
/// Usually used for initialization.
|
||||||
|
fn on_plugin_load(&self);
|
||||||
|
/// A function that runs immediately before the plugin is unloaded.
|
||||||
|
/// Use this if you want to do any cleanup.
|
||||||
|
fn on_plugin_unload(&self);
|
||||||
|
/// Plugin command.
|
||||||
|
/// For example: `/command`
|
||||||
|
fn command(&self) -> &'static str;
|
||||||
|
/// Help message of this command.
|
||||||
|
fn help(&self) -> &'static str;
|
||||||
|
/// The function will be executed, when sending plugin command.
|
||||||
|
fn execute(&self, client: &mut Client, args: Vec<&str>);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PluginManager {
|
||||||
|
/// Vector with loaded plugins
|
||||||
|
pub plugins: Vec<Box<dyn Plugin>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginManager {
|
||||||
|
/// Create empty `PluginManager`
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
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 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PluginManager {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PluginRegistrar {
|
||||||
|
fn register_plugin(&mut self, plugin: Box<dyn Plugin>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginRegistrar for PluginManager {
|
||||||
|
fn register_plugin(&mut self, plugin: Box<dyn Plugin>) {
|
||||||
|
self.plugins.push(plugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PluginManagerType = Vec<Arc<Box<dyn Plugin>>>;
|
||||||
|
|
||||||
|
pub fn loader() -> anyhow::Result<PluginManagerType> {
|
||||||
|
// get path to .so lib from command argument
|
||||||
|
let config_dir = "./plugins";
|
||||||
|
let paths = fs::read_dir(config_dir)?;
|
||||||
|
|
||||||
|
// create a plugin manager where all loaded plugins will be located
|
||||||
|
let mut plugin_manager = PluginManager::new();
|
||||||
|
|
||||||
|
// for all plugin in directory
|
||||||
|
for path in paths {
|
||||||
|
// get library file path
|
||||||
|
let path = path?.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)?));
|
||||||
|
|
||||||
|
// get `plugin_entry` from library
|
||||||
|
let func: Symbol<unsafe extern "C" fn(&mut dyn PluginRegistrar) -> ()> =
|
||||||
|
lib.get(b"plugin_entry")?;
|
||||||
|
|
||||||
|
// execute initial function
|
||||||
|
func(&mut plugin_manager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create Arc in Vector
|
||||||
|
let mut plugins: PluginManagerType = Vec::new();
|
||||||
|
for plugin in plugin_manager.plugins {
|
||||||
|
plugins.push(Arc::new(plugin))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(plugins)
|
||||||
|
}
|
Loading…
Reference in New Issue