Compare commits

...

25 Commits
v0.4.1 ... main

Author SHA1 Message Date
renovate[bot] d5b238f153 fix(deps): update rust crate async-trait to 0.1.63 2023-01-23 04:59:48 +00:00
renovate[bot] 91ab6cb607 fix(deps): update rust crate async-trait to 0.1.61 2023-01-09 04:20:42 +00:00
renovate[bot] de5e26bbf2 fix(deps): update all non-major dependencies 2022-12-19 03:30:40 +00:00
renovate[bot] 09f7d14bcc fix(deps): update all non-major dependencies 2022-12-12 03:57:24 +00:00
renovate[bot] ce546a0c69 fix(deps): update rust crate libloading to 0.7.4 2022-11-07 05:40:58 +00:00
renovate[bot] 619ed0b41d fix(deps): update rust crate clap to 3.2.23 2022-10-31 05:13:52 +00:00
renovate[bot] 5a103de793 fix(deps): update all non-major dependencies 2022-10-24 04:12:45 +00:00
renovate[bot] 0d4ff8041b fix(deps): update all non-major dependencies 2022-10-10 05:19:25 +00:00
renovate[bot] eb462622eb fix(deps): update all non-major dependencies 2022-09-19 03:37:23 +00:00
MedzikUser b56357c085
fix(server): change from task::spawn to thread::spawn
Changed to thread::spawn due to task::spawn spawn max 2 tasks (accept max 2 clients) if your cpu has 2 cores.
2022-09-14 21:03:49 +02:00
renovate[bot] fd4121b0d2 fix(deps): update all non-major dependencies 2022-09-05 05:42:10 +00:00
MedzikUser 032ec88ed6
chore: add some comments in code
Moved `PluginsManager` and `PluginsManagerType` from `servers::plugin::manager` to the `servers::plugin` module.
Added some comments in code.
Implemented function `into()` to the `PluginsManager` struct.
2022-08-22 13:23:08 +02:00
MedzikUser 501cbc74b7
fix(clippy): change `< 1` to .is_empty()
Replaced `args.len() < 1` with `args.is_empty()`.
2022-08-20 15:01:48 +02:00
MedzikUser db6e068926
chore(plugin): change to cdylib
Probably better.
2022-08-20 14:58:32 +02:00
MedzikUser 212223c568
ci(release): build binaries for gnu instead of musl
Musl currently doesn't support dylib.
2022-08-20 14:48:41 +02:00
MedzikUser d15ec0c93e
feat(command): add /broadcast
The `/broadcast` command has been added, which can send a message to all connected clients.
2022-08-19 22:27:42 +02:00
MedzikUser 9f66c2b9d2
fix(cli): update long arguments
Changed clap long attributes from --host to host and --port to port.
2022-08-19 12:16:02 +02:00
MedzikUser 95d0e15786
chore(release): v0.6.0 2022-08-17 22:07:12 +02:00
MedzikUser d31e0fff2f
fix(plugin): execute `on_load` function
Now function `on_load` will be executed if the plugin is loads.
Added span to the logger on TRACE level in plugin loader.
Fixed clippy warning from previous commit.
2022-08-17 22:05:27 +02:00
MedzikUser 67fb1a0a3c
feat(server): add `onCommand` event and handle errors in message processing
Added `OnCommand` event e.g. to disable command for client. (BREAKING CHANGES IN EVENT PLUGINS)
Added function for error handling in message process.
2022-08-17 21:44:06 +02:00
MedzikUser 56e16145f6
chore(release): v0.5.0 2022-08-17 15:45:36 +02:00
MedzikUser 7da5daf522
feat(client): HashMap add Mutex and functions
Changed map type in Client struct to Arc<Mutex<HashMap<String, ClientMapValue>>>.
Implemented functions insert_key, get_value and delete_key to the Client type.
Re-export servers::server::ClientMapValue in servers::plugins::prelude.
2022-08-17 15:40:11 +02:00
MedzikUser bf1c3c4092
chore(release): v0.4.2
- **fix**: update anyhow to v1.0.62
2022-08-17 11:56:29 +02:00
MedzikUser 5d2afe3719
ci(release): delete compress binaries 2022-08-17 11:47:26 +02:00
MedzikUser 83f2961aee
chore(release): v0.4.1 2022-08-16 23:35:31 +02:00
16 changed files with 348 additions and 173 deletions

View File

@ -17,8 +17,8 @@ jobs:
matrix:
target:
- x86_64-unknown-linux-musl
- aarch64-unknown-linux-musl
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-pc-windows-msvc
- x86_64-apple-darwin
- aarch64-apple-darwin
@ -26,21 +26,17 @@ jobs:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
artifact_name: target/x86_64-unknown-linux-musl/release/servers
release_name: x86_64-unknown-linux-musl
target: x86_64-unknown-linux-gnu
artifact_name: target/x86_64-unknown-linux-gnu/release/servers
release_name: x86_64-unknown-linux-gnu
cross: true
strip: true
compress: true
cargo_flags: ""
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
artifact_name: target/aarch64-unknown-linux-musl/release/servers
release_name: aarch64-unknown-linux-musl
target: aarch64-unknown-linux-gnu
artifact_name: target/aarch64-unknown-linux-gnu/release/servers
release_name: aarch64-unknown-linux-gnu
cross: true
strip: false
compress: true
cargo_flags: ""
- os: windows-latest
@ -48,8 +44,6 @@ jobs:
artifact_name: target/x86_64-pc-windows-msvc/release/servers.exe
release_name: x86_64-pc-windows-msvc.exe
cross: false
strip: true
compress: true
cargo_flags: ""
- os: macos-latest
@ -57,8 +51,6 @@ jobs:
artifact_name: target/x86_64-apple-darwin/release/servers
release_name: x86_64-apple-darwin
cross: false
strip: true
compress: true
cargo_flags: ""
- os: macos-latest
@ -66,8 +58,6 @@ jobs:
artifact_name: target/aarch64-apple-darwin/release/servers
release_name: aarch64-apple-darwin
cross: false
strip: true
compress: true
cargo_flags: ""
- os: ubuntu-latest
@ -75,8 +65,6 @@ jobs:
artifact_name: target/x86_64-unknown-freebsd/release/servers
release_name: x86_64-unknown-freebsd
cross: true
strip: false
compress: false
cargo_flags: ""
name: ${{ matrix.os }} for ${{ matrix.target }}
@ -99,24 +87,12 @@ jobs:
args: --release --target=${{ matrix.target }} ${{ matrix.cargo_flags }}
use-cross: ${{ matrix.cross }}
- name: Compress binaries
uses: svenstaro/upx-action@v2
with:
file: ${{ matrix.artifact_name }}
args: --lzma
strip: ${{ matrix.strip }}
if: ${{ matrix.compress }}
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.target }}
path: ${{ matrix.artifact_name }}
###
# Below this line, steps will only be ran if a tag was pushed.
###
- name: Get tag name
id: tag_name
run: |

133
Cargo.lock generated
View File

@ -2,20 +2,11 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "anyhow"
version = "1.0.61"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "508b352bb5c066aac251f6daf6b36eccd03e8a88e8081cd44959ea277a3af9a8"
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]]
name = "async-attributes"
@ -131,9 +122,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
[[package]]
name = "async-trait"
version = "0.1.57"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1"
dependencies = [
"proc-macro2",
"quote",
@ -236,9 +227,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.2.17"
version = "3.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29e724a68d9319343bb3328c9cc2dfde263f4b3142ee1059a9980580171c954b"
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
dependencies = [
"atty",
"bitflags",
@ -253,9 +244,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "3.2.17"
version = "3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa"
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
dependencies = [
"heck",
"proc-macro-error",
@ -323,9 +314,9 @@ dependencies = [
[[package]]
name = "digest"
version = "0.10.3"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
@ -364,9 +355,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab30e97ab6aacfe635fad58f22c2bb06c8b685f7421eb1e064a729e2a5f481fa"
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
dependencies = [
"futures-channel",
"futures-core",
@ -379,9 +370,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bfc52cbddcfd745bf1740338492bb0bd83d76c67b445f91c5fb29fae29ecaa1"
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
dependencies = [
"futures-core",
"futures-sink",
@ -389,15 +380,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
[[package]]
name = "futures-executor"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d11aa21b5b587a64682c0094c2bdd4df0076c5324961a40cc3abd7f37930528"
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
dependencies = [
"futures-core",
"futures-task",
@ -406,9 +397,9 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5"
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
[[package]]
name = "futures-lite"
@ -427,9 +418,9 @@ dependencies = [
[[package]]
name = "futures-macro"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0db9cce532b0eae2ccf2766ab246f114b56b9cf6d445e00c2549fbc100ca045d"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
dependencies = [
"proc-macro2",
"quote",
@ -438,21 +429,21 @@ dependencies = [
[[package]]
name = "futures-sink"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca0bae1fe9752cf7fd9b0064c674ae63f97b37bc714d745cbde0afb7ec4e6765"
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
[[package]]
name = "futures-task"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "842fc63b931f4056a24d59de13fb1272134ce261816e063e634ad0c15cdc5306"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
[[package]]
name = "futures-util"
version = "0.3.23"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
dependencies = [
"futures-channel",
"futures-core",
@ -599,15 +590,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.131"
version = "0.2.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40"
checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
[[package]]
name = "libloading"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
@ -635,6 +626,16 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
@ -647,15 +648,21 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.13.0"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
[[package]]
name = "os_str_bytes"
version = "6.2.0"
version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "parking"
@ -781,7 +788,7 @@ dependencies = [
[[package]]
name = "servers"
version = "0.4.0"
version = "0.6.0"
dependencies = [
"anyhow",
"async-std",
@ -796,10 +803,10 @@ dependencies = [
]
[[package]]
name = "sha-1"
version = "0.10.0"
name = "sha1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if",
"cpufeatures",
@ -868,9 +875,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.15.0"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
@ -918,9 +925,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tracing"
version = "0.1.36"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
@ -930,9 +937,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
version = "0.1.22"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [
"proc-macro2",
"quote",
@ -941,9 +948,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.29"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
"valuable",
@ -962,11 +969,11 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.15"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
dependencies = [
"ansi_term",
"nu-ansi-term",
"sharded-slab",
"smallvec",
"thread_local",
@ -976,9 +983,9 @@ dependencies = [
[[package]]
name = "tungstenite"
version = "0.17.3"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0"
checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
dependencies = [
"base64",
"byteorder",
@ -987,7 +994,7 @@ dependencies = [
"httparse",
"log",
"rand",
"sha-1",
"sha1",
"thiserror",
"url",
"utf-8",

View File

@ -4,7 +4,7 @@ resolver = "2"
[package]
name = "servers"
version = "0.4.0"
version = "0.6.0"
description = "TCP and WebSocket server for Clients written in Rust"
homepage = "https://github.com/MedzikUser/servers"
repository = "https://github.com/MedzikUser/servers.git"
@ -12,13 +12,13 @@ license = "MIT"
edition = "2021"
[dependencies]
anyhow = "1.0.61"
anyhow = "1.0.68"
async-std = { version = "1.12.0", features = ["attributes"] }
async-trait = "0.1.57"
clap = { version = "3.2.17", features = ["derive"] }
libloading = "0.7.3"
tracing = "0.1.36"
tracing-subscriber = "0.3.15"
tungstenite = "0.17.3"
futures = "0.3.23"
async-trait = "0.1.63"
clap = { version = "3.2.23", features = ["derive"] }
libloading = "0.7.4"
tracing = "0.1.37"
tracing-subscriber = "0.3.16"
tungstenite = "0.18.0"
futures = "0.3.25"
lazy_static = "1.4.0"

View File

@ -3,10 +3,8 @@ name = "plugin_test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["dylib"]
crate-type = ["cdylib"]
[dependencies]
servers = { path = ".." }

View File

@ -42,7 +42,7 @@ impl Event for PluginTest {
EventType::OnConnect
}
async fn execute(&self, client: &Client) -> anyhow::Result<()> {
async fn execute(&self, client: &Client, _data: EventData) -> anyhow::Result<()> {
client.send("Hello!")
}
}

View File

@ -17,7 +17,7 @@ use servers::server::MAX_PACKET_LEN;
struct Cli {
#[clap(
short = 'i',
long = "--host",
long = "host",
help = "Server host",
default_value = "0.0.0.0",
display_order = 1
@ -26,7 +26,7 @@ struct Cli {
#[clap(
short = 'p',
long = "--port",
long = "port",
help = "Server port",
default_value = "9999",
display_order = 2

54
src/commands/broadcast.rs Normal file
View File

@ -0,0 +1,54 @@
use async_std::task;
use crate::{plugins::prelude::*, CLIENTS};
pub struct Broadcast;
#[async_trait]
impl Command for Broadcast {
fn name(&self) -> &'static str {
"/broadcast"
}
fn aliases(&self) -> Vec<&'static str> {
vec![]
}
fn help(&self) -> &'static str {
"Send message to all connected clients"
}
fn usage(&self) -> &'static str {
"/broadcast <message>"
}
async fn execute(&self, client: &Client, args: Vec<&str>) -> anyhow::Result<()> {
if args.is_empty() || args.join(" ").is_empty() {
client.send("Missing message")?;
return Ok(());
}
let msg = args.join(" ");
let mut children = Vec::new();
// send message to all connected clients
for (_i, client) in CLIENTS.lock().unwrap().clone() {
let msg = msg.clone();
let child = task::spawn(async move {
client
.send(msg)
.expect("failed to send broadcast message to client")
});
children.push(child);
}
// wait for all task to complete
for child in children {
child.await;
}
Ok(())
}
}

View File

@ -1,9 +1,9 @@
use crate::plugins::prelude::*;
pub struct ID;
pub struct Id;
#[async_trait]
impl Command for ID {
impl Command for Id {
fn name(&self) -> &'static str {
"/id"
}

View File

@ -1,11 +1,25 @@
//! Default servers commands.
//!
//! List of commands:
//! - /broadcast
//! - /disconnect
//! - /help
//! - /id
mod broadcast;
mod disconnect;
mod help;
mod id;
use self::{disconnect::Disconnect, help::Help, id::ID};
use self::{broadcast::Broadcast, disconnect::Disconnect, help::Help, id::Id};
use crate::plugins::prelude::*;
/// Register default commands
pub fn register_commands() -> Vec<Box<dyn Command>> {
vec![Box::new(Help), Box::new(Disconnect), Box::new(ID)]
vec![
Box::new(Broadcast),
Box::new(Disconnect),
Box::new(Help),
Box::new(Id),
]
}

View File

@ -1,7 +1,8 @@
use std::{fs, path::Path, sync::Arc};
use std::{fs, path::Path};
use async_std::task;
use libloading::{Library, Symbol};
use tracing::{info, trace};
use tracing::{info, span, trace, Level};
use crate::{
commands,
@ -11,6 +12,7 @@ use crate::{
},
};
/// Load all plugins, commands and events.
pub fn loader(plugins_dir: &str) -> anyhow::Result<PluginsManagerType> {
// if plugins directory doesn't exists, create it
if !Path::new(plugins_dir).exists() {
@ -23,13 +25,17 @@ pub fn loader(plugins_dir: &str) -> anyhow::Result<PluginsManagerType> {
// init a plugins manager
let mut plugins_manager = PluginsManager::new();
// add default commands
// register default commands
plugins_manager.commands = commands::register_commands();
for plugin_path in plugins_files {
let path = plugin_path?.path();
let path_str = path.to_str().unwrap();
// add span to logger
let span = span!(Level::TRACE, "", plugin_path = path_str);
let _enter = span.enter();
info!("Loading plugin {}", path_str);
// loading library from .so is unsafe
@ -48,5 +54,11 @@ pub fn loader(plugins_dir: &str) -> anyhow::Result<PluginsManagerType> {
}
}
Ok(Arc::new(plugins_manager))
for plugin in plugins_manager.plugins.iter() {
// execute the `on_load` function from the plugin
task::block_on(async { plugin.on_load().await });
info!("Loaded plugin {}.", plugin.name());
}
Ok(plugins_manager.into())
}

View File

@ -3,6 +3,10 @@ use std::sync::Arc;
use crate::plugins::prelude::*;
/// Plugins manager struct with Clone derive added by Arc.
pub type PluginsManagerType = Arc<PluginsManager>;
/// A plugins manager that stores all plugins, commands and events.
#[derive(Default)]
pub struct PluginsManager {
/// Vector with all loaded plugins.
@ -14,14 +18,19 @@ pub struct PluginsManager {
}
impl PluginsManager {
/// Returns an empty PluginsManager
pub fn new() -> PluginsManager {
/// Returns an empty instance of [PluginsManager]
pub fn new() -> Self {
Self {
plugins: Vec::new(),
commands: Vec::new(),
events: Vec::new(),
}
}
/// Returns the instance in [PluginsManagerType].
pub fn into(self) -> PluginsManagerType {
Arc::new(self)
}
}
impl fmt::Debug for PluginsManager {
@ -33,5 +42,3 @@ impl fmt::Debug for PluginsManager {
.finish()
}
}
pub type PluginsManagerType = Arc<PluginsManager>;

View File

@ -1,9 +1,13 @@
//! Plugin infrastructure.
mod load;
pub mod manager;
mod manager;
pub mod types;
pub use load::*;
pub use manager::*;
/// Crates and types required in plugins.
pub mod prelude {
use super::*;
@ -12,5 +16,5 @@ pub mod prelude {
pub use async_trait::async_trait;
pub use self::types::*;
pub use crate::server::Client;
pub use crate::server::{Client, ClientMapValue};
}

View File

@ -1,10 +1,12 @@
//! Types used for creating plugins.
use std::any::Any;
use async_trait::async_trait;
use crate::{plugins::manager::PluginsManager, server::Client};
// A main plugin trait.
/// A main plugin trait.
#[async_trait]
pub trait Plugin: Any + Send + Sync {
/// Name of the plugin.
@ -29,12 +31,23 @@ pub trait Command: Any + Send + Sync {
}
/// All possible to run events.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventType {
/// On client connected.
OnConnect,
/// On client sent message.
OnSend,
/// Event executed before command execute (e.g. for disable command).
OnCommand,
}
/// All possible to run events.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventData {
/// for `onCommand` event
Command(String),
/// No data
None,
}
/// Add a event to the plugin.
@ -43,9 +56,10 @@ pub trait Event: Any + Send + Sync {
/// Type of the event.
fn event(&self) -> EventType;
/// Event function.
async fn execute(&self, client: &Client) -> anyhow::Result<()>;
async fn execute(&self, client: &Client, data: EventData) -> anyhow::Result<()>;
}
/// A plugin registrar trait.
pub trait Registrar {
/// Function to register plugins.
fn register_plugins(&mut self, plugin: Box<dyn Plugin>);

View File

@ -6,10 +6,14 @@ use std::{
sync::{Arc, Mutex},
};
use tracing::info;
use tungstenite::{accept, Message, WebSocket};
use super::run::PLUGINS_MANAGER;
use crate::plugins::{manager::PluginsManagerType, prelude::EventType};
use crate::plugins::{
prelude::{EventData, EventType},
PluginsManagerType,
};
/// Max length of a TCP and UDP packet
pub const MAX_PACKET_LEN: usize = 65536;
@ -22,7 +26,7 @@ pub struct Client {
/// Connection stream of the client
pub stream: ClientStream,
/// Custom Client Map
pub map: HashMap<String, ClientMapValue>,
pub map: Arc<Mutex<HashMap<String, ClientMapValue>>>,
/// Plugins Manager
pub plugins_manager: PluginsManagerType,
}
@ -38,15 +42,10 @@ pub struct Client {
/// Value type of the client map entry
#[derive(Debug, Clone)]
pub enum ClientMapValue {
/// String type
String(String),
/// Vector with String type
Array(Vec<String>),
/// bool type
Bool(bool),
/// isize type
Int(isize),
/// usize type
UInt(usize),
}
@ -64,7 +63,7 @@ impl From<TcpStream> for Client {
Self {
id: 0,
stream: ClientStream::TCP(Arc::new(stream)),
map: HashMap::new(),
map: Arc::new(Mutex::new(HashMap::new())),
plugins_manager: PLUGINS_MANAGER.clone(),
}
}
@ -75,7 +74,7 @@ impl From<WebSocket<TcpStream>> for Client {
Self {
id: 0,
stream: ClientStream::WebSocket(Arc::new(Mutex::new(stream))),
map: HashMap::new(),
map: Arc::new(Mutex::new(HashMap::new())),
plugins_manager: PLUGINS_MANAGER.clone(),
}
}
@ -133,6 +132,8 @@ impl Client {
msg.pop();
}
info!("[Recieved]: {}", msg);
Ok(msg)
}
@ -152,10 +153,12 @@ impl Client {
match &self.stream {
ClientStream::TCP(stream) => stream.as_ref().write_all(buf)?,
ClientStream::WebSocket(stream) => {
stream.lock().unwrap().write_message(Message::from(msg))?
stream.lock().unwrap().write_message(Message::from(buf))?
},
}
info!("[Sent]: {}", msg);
Ok(())
}
@ -189,10 +192,38 @@ impl Client {
Ok(())
}
pub async fn run_events(&self, event_type: EventType) -> anyhow::Result<()> {
/// Inserts a key-value pair into the map.
pub fn insert_key<S>(&self, key: S, value: ClientMapValue) -> Option<ClientMapValue>
where
S: ToString,
{
self.map.lock().unwrap().insert(key.to_string(), value)
}
/// Returns the value from the key.
pub fn get_value<S>(&self, key: S) -> Option<ClientMapValue>
where
S: ToString,
{
self.map.lock().unwrap().get(&key.to_string()).cloned()
}
/// Delete key from the map.
pub fn delete_key<S>(&self, key: S) -> Option<ClientMapValue>
where
S: ToString,
{
self.map.lock().unwrap().remove(&key.to_string())
}
pub async fn run_events(
&self,
event_type: EventType,
event_data: EventData,
) -> anyhow::Result<()> {
for event in self.plugins_manager.events.iter() {
if event.event() == event_type {
event.execute(self).await?;
event.execute(self, event_data.clone()).await?;
}
}

View File

@ -1,3 +1,5 @@
//! Server infrastructure.
mod client;
mod run;

View File

@ -1,16 +1,22 @@
use std::net::TcpListener;
use std::{net::TcpListener, thread};
use anyhow::anyhow;
use async_std::task;
use futures::join;
use lazy_static::lazy_static;
use tracing::{error, info, span, Level};
use crate::{
plugins::{self, manager::PluginsManagerType, prelude::EventType},
plugins::{
self,
prelude::{EventData, EventType},
PluginsManagerType,
},
server::Client,
CLIENTS, CLIENT_NEXT,
};
/// Plugins directory.
pub const PLUGINS_DIR: &str = "plugins";
lazy_static! {
@ -47,40 +53,74 @@ async fn process(client: Client) -> anyhow::Result<()> {
info!("Processing client connection: {}", client_addr);
// run `onConnect` events
client.run_events(EventType::OnConnect).await?;
client
.run_events(EventType::OnConnect, EventData::None)
.await?;
loop {
let buf = client.read()?;
// run `onSend` events
client.run_events(EventType::OnSend).await?;
// functions for error handling see `if` below function
async fn handle(client: &Client, buf: String) -> anyhow::Result<()> {
// run `onSend` events
client
.run_events(EventType::OnSend, EventData::None)
.await?;
let mut args: Vec<&str> = buf.split_ascii_whitespace().collect();
let mut args: Vec<&str> = buf.split_ascii_whitespace().collect();
// if client sent an empty buffer
if args.is_empty() {
client.send("empty buffer")?;
continue;
// if client sent an empty buffer
if args.is_empty() {
client.send("empty buffer")?;
return Ok(());
}
let cmd = args[0];
// remove command name from args
args = args[1..args.len()].to_vec();
// find command
let command = client
.plugins_manager
.commands
.iter()
.enumerate()
.find(|&(_i, command)| command.name() == cmd || command.aliases().contains(&cmd));
// execute command, if command isn't blocked
// to block a command return error in the `onCommand` event
if let Some((_i, cmd)) = command {
// run `onCommand` events
if client
.run_events(
EventType::OnCommand,
EventData::Command(cmd.name().to_string()),
)
.await
.is_ok()
{
// execute command
cmd.execute(client, args).await?;
}
} else {
client.send("unknown command")?;
}
Ok(())
}
let cmd = args[0];
// handle errors from message processing
if let Err(err) = handle(&client, buf).await {
let err = err.to_string();
// remove command name from args
args = args[1..args.len()].to_vec();
// find command
let command = client
.plugins_manager
.commands
.iter()
.enumerate()
.find(|&(_i, command)| command.name() == cmd || command.aliases().contains(&cmd));
// execute command
if let Some((_i, cmd)) = command {
cmd.execute(&client, args).await?;
} else {
client.send("unknown command")?;
// client disconnect e.g. using ctrl + c
if err.contains("Broken pipe") {
return Err(anyhow!("disconnected"));
} else {
error!("Unexpected error in message handler: {}", err);
client.send("Unexpected error")?;
}
}
client.flush()?;
@ -101,7 +141,7 @@ async fn start_tcp(host: String) -> anyhow::Result<()> {
// add one to next id
*CLIENT_NEXT.lock().unwrap() += 1;
task::spawn(async move {
thread::spawn(move || {
// get id for the client and add one to next id
let client = Client::new_tcp(stream, id);
@ -112,8 +152,15 @@ async fn start_tcp(host: String) -> anyhow::Result<()> {
let span = span!(Level::ERROR, "TCP", id = client.id);
let _enter = span.enter();
if let Err(err) = process(client).await {
error!("{}", err);
if let Err(err) = task::block_on(process(client)) {
let err = err.to_string();
// client disconnect e.g. using ctrl + c
if err == "disconnected" {
info!("Client disconnected")
} else {
error!("{}", err);
}
}
// delete the client from CLIENTS map
@ -138,18 +185,27 @@ async fn start_websocket(host: String) -> anyhow::Result<()> {
// add one to next id
*CLIENT_NEXT.lock().unwrap() += 1;
task::spawn(async move {
thread::spawn(move || {
let client = Client::new_websocket(stream, id).unwrap();
// insert the cloned client to CLIENTS
CLIENTS.lock().unwrap().insert(id, client.clone());
// add span to logger
let span = span!(Level::ERROR, "UDP", id = client.id);
let span = span!(Level::ERROR, "WS", id = client.id);
let _enter = span.enter();
if let Err(err) = process(client).await {
error!("{}", err);
if let Err(err) = task::block_on(process(client)) {
let err = err.to_string();
// client disconnect e.g. using ctrl + c
if err == "disconnected"
|| err.contains("Connection reset without closing handshake")
{
info!("Client disconnected")
} else {
error!("{}", err);
}
}
// delete the client from CLIENTS map