mirror of https://github.com/MedzikUser/servers
refactor: rewrite
- Better Client struct (TCP and WebSocket in one type) - WebSocket is now not a proxy to tcp - Use async-std instead a tokio - Use Arc and Client type now have a Clone derive - Add global CLIENTS list
This commit is contained in:
parent
868671848b
commit
d0120a0703
47
CHANGELOG.md
47
CHANGELOG.md
|
@ -1,47 +0,0 @@
|
|||
# Changelog
|
||||
|
||||
<!-- next-header -->
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.3.0] - 2022-08-04
|
||||
## **Breaking**
|
||||
- **tcp**: use tcp from tokio instead of std
|
||||
|
||||
## Features
|
||||
- **client**: added `peer_addr` function
|
||||
- **server**: added `/help` command
|
||||
- **api**: re-export `async_trait` so that it doesn't have to be added to dependencies in plugins
|
||||
|
||||
## Changed
|
||||
- **server**: the `/help` command has been accelerated
|
||||
- **cli**: moved to the `cli.rs` file
|
||||
- **logger**: changed `log` to `tracing`
|
||||
- **dependencies**: updated
|
||||
- **cli**: deleted option `--disable-websocket` and added `--enable-websocket`
|
||||
|
||||
## [0.2.0] - 2022-06-26
|
||||
### Features
|
||||
- **plugins**: add `Result<()>` in `fn execute()` (Event and Command traits)
|
||||
- **websocket**: WS Client <-> TCP Proxy (default port 9998) <-> TCP (default port 9999)
|
||||
|
||||
### Chore
|
||||
- **deps**: upgrade
|
||||
|
||||
## [0.1.0] - 2022-06-17
|
||||
### Default commands
|
||||
- help
|
||||
|
||||
### Dynamic plugins loader
|
||||
You can create custom commands and events (events executed if client connected or send message)
|
||||
|
||||
### Cli
|
||||
You set custom host and port `./servers --host 0.0.0.0 --port 9999`
|
||||
|
||||
Show cli help `./servers --help`
|
||||
|
||||
<!-- next-url -->
|
||||
[Unreleased]: https://github.com/MedzikUser/servers/compare/v0.3.0...HEAD
|
||||
[0.3.0]: https://github.com/MedzikUser/servers/commits/v0.3.0
|
||||
[0.2.0]: https://github.com/MedzikUser/servers/commits/v0.2.0
|
||||
[0.1.0]: https://github.com/MedzikUser/servers/commits/v0.1.0
|
|
@ -2,21 +2,6 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
|
@ -28,9 +13,121 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.60"
|
||||
version = "1.0.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
|
||||
checksum = "508b352bb5c066aac251f6daf6b36eccd03e8a88e8081cd44959ea277a3af9a8"
|
||||
|
||||
[[package]]
|
||||
name = "async-attributes"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"concurrent-queue",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5262ed948da60dd8956c6c5aca4d4163593dddb7b32d73267c93dab7b2e98940"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"log",
|
||||
"once_cell",
|
||||
"parking",
|
||||
"polling",
|
||||
"slab",
|
||||
"socket2",
|
||||
"waker-fn",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-lock"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6"
|
||||
dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-std"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
|
||||
dependencies = [
|
||||
"async-attributes",
|
||||
"async-channel",
|
||||
"async-global-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"crossbeam-utils",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"gloo-timers",
|
||||
"kv-log-macro",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
"wasm-bindgen-futures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
|
@ -43,6 +140,12 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
@ -60,37 +163,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "better-panic"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fa9e1d11a268684cbd90ed36370d7577afb6c62d912ddff5c15fc34343e5036"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"console",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -106,6 +184,26 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-task",
|
||||
"atomic-waker",
|
||||
"fastrand",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
|
@ -114,9 +212,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.1.0"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
|
||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
||||
|
||||
[[package]]
|
||||
name = "cache-padded"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
|
@ -132,9 +236,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.16"
|
||||
version = "3.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9"
|
||||
checksum = "29e724a68d9319343bb3328c9cc2dfde263f4b3142ee1059a9980580171c954b"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
|
@ -149,9 +253,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.15"
|
||||
version = "3.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ba52acd3b0a5c33aeada5cdaa3267cdc7c594a98731d4268cdc1532f4264cb4"
|
||||
checksum = "13547f7012c01ab4a0e8f8967730ada8f9fdf419e8b6c792788f39cf4e46eefa"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
|
@ -162,24 +266,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87eba3c8c7f42ef17f6c659fc7416d0f4758cd3e58861ee63c5fa4a4dde649e4"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.0"
|
||||
name = "concurrent-queue"
|
||||
version = "1.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31"
|
||||
checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"terminal_size",
|
||||
"winapi",
|
||||
"cache-padded",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -192,15 +292,35 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.3"
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
|
||||
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.3"
|
||||
|
@ -212,10 +332,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
|
@ -233,12 +362,80 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.21"
|
||||
|
@ -257,9 +454,13 @@ version = "0.3.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
|
@ -267,9 +468,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.5"
|
||||
version = "0.14.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
|
@ -287,16 +488,22 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.1"
|
||||
name = "gloo-timers"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.1"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
|
@ -352,10 +559,37 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.2"
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kv-log-macro"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
|
@ -365,9 +599,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
version = "0.2.131"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
@ -386,6 +620,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -400,27 +635,6 @@ version = "2.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.1"
|
||||
|
@ -431,15 +645,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.28.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.0"
|
||||
|
@ -448,9 +653,15 @@ checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
|||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.1.0"
|
||||
version = "6.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
|
||||
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
|
@ -477,6 +688,19 @@ dependencies = [
|
|||
"servers",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"log",
|
||||
"wepoll-ffi",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
|
@ -509,18 +733,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.40"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.20"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -555,25 +779,17 @@ dependencies = [
|
|||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "servers"
|
||||
version = "0.3.0"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
"async-trait",
|
||||
"better-panic",
|
||||
"clap",
|
||||
"futures-util",
|
||||
"futures",
|
||||
"lazy_static",
|
||||
"libloading",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tungstenite",
|
||||
|
@ -601,9 +817,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
|
||||
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
|
@ -629,9 +848,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.98"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||
checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -647,16 +866,6 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
|
@ -665,18 +874,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.31"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -707,48 +916,6 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.36"
|
||||
|
@ -840,15 +1007,15 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.1"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c"
|
||||
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.20"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd"
|
||||
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
@ -877,18 +1044,119 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "value-bag"
|
||||
version = "1.0.0-alpha.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
|
||||
dependencies = [
|
||||
"ctor",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-ffi"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -919,46 +1187,3 @@ 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"
|
||||
|
|
22
Cargo.toml
22
Cargo.toml
|
@ -4,29 +4,19 @@ resolver = "2"
|
|||
|
||||
[package]
|
||||
name = "servers"
|
||||
description = "Simple TCP server for clients written in Rust with plugins support."
|
||||
version = "0.3.0"
|
||||
license = "MIT"
|
||||
authors = ["MedzikUser <medzik@duck.com>"]
|
||||
homepage = "https://github.com/MedzikUser/servers"
|
||||
repository = "https://github.com/MedzikUser/servers.git"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
opt-level = 'z'
|
||||
codegen-units = 1
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.60"
|
||||
async-std = { version = "1.12.0", features = ["attributes"] }
|
||||
async-trait = "0.1.57"
|
||||
better-panic = "0.3.0"
|
||||
lazy_static = "1.4.0"
|
||||
clap = { version = "3.2.17", features = ["derive"] }
|
||||
libloading = "0.7.3"
|
||||
tokio-tungstenite = "0.17.2"
|
||||
tracing = "0.1.36"
|
||||
tracing-subscriber = "0.3.15"
|
||||
tungstenite = "0.17.3"
|
||||
clap = { version = "3.2.16", features = ["derive"] }
|
||||
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
|
||||
tokio = { version = "1.20.1", features = ["rt-multi-thread", "macros", "net"] }
|
||||
futures = "0.3.21"
|
||||
lazy_static = "1.4.0"
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# NOTE: Custom image specification for freebsd is required until new version of cross is released.
|
||||
[target.x86_64-unknown-freebsd]
|
||||
image = "svenstaro/cross-x86_64-unknown-freebsd:latest"
|
31
README.md
31
README.md
|
@ -1,31 +0,0 @@
|
|||
# Servers - Simple TCP and WebSocket server
|
||||
|
||||
[docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
|
||||
[total-lines]: https://img.shields.io/tokei/lines/github/MedzikUser/servers?style=for-the-badge&logo=github&color=fede00
|
||||
[code-size]: https://img.shields.io/github/languages/code-size/MedzikUser/servers?style=for-the-badge&color=c8df52&logo=github
|
||||
[ci]: https://img.shields.io/github/workflow/status/MedzikUser/servers/Rust/main?style=for-the-badge
|
||||
[image]:https://socialify.git.ci/MedzikUser/servers/image?description=1&font=KoHo&language=1&owner=1&pattern=Circuit%20Board&theme=Light
|
||||
|
||||
[![docs-rs]](https://servers.medzik.xyz)
|
||||
[![total-lines]](https://github.com/MedzikUser/servers)
|
||||
[![code-size]](https://github.com/MedzikUser/servers)
|
||||
[![ci]](https://github.com/MedzikUser/servers/actions/workflows/build.yml)
|
||||
|
||||
[![image]](https://github.com/MedzikUser/servers)
|
||||
|
||||
A simple TCP server for clients and WebSocket server written in Rust 🦀 which can be extended with plugins.
|
||||
|
||||
## 👨💻 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
|
||||
|
||||
Read the docs from [plugins](https://servers.medzik.xyz/servers/plugins) module.
|
|
@ -3,6 +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"]
|
||||
|
||||
|
|
|
@ -1,72 +1,45 @@
|
|||
use servers::{
|
||||
async_trait,
|
||||
plugins::{Command, Event, Plugin, PluginManagerType, Registrar, Result},
|
||||
tcp::Client,
|
||||
};
|
||||
use servers::plugins::prelude::*;
|
||||
|
||||
struct PluginTest;
|
||||
|
||||
/// Create a new plugin
|
||||
#[async_trait]
|
||||
impl Plugin for PluginTest {
|
||||
/// Name of the plugin.
|
||||
fn name(&self) -> &'static str {
|
||||
"test"
|
||||
"test_plugin"
|
||||
}
|
||||
|
||||
/// A function will be executed when plugin loading.
|
||||
/// Usally used for initialization.
|
||||
async fn on_plugin_load(&self) {}
|
||||
/// A function that will be executed when the plugin is loaded.
|
||||
async fn on_load(&self) {}
|
||||
}
|
||||
|
||||
/// Create a new command
|
||||
#[async_trait]
|
||||
impl Command for PluginTest {
|
||||
/// Command name
|
||||
/// Name of the command.
|
||||
fn name(&self) -> &'static str {
|
||||
"/test"
|
||||
}
|
||||
|
||||
/// Help message of the command
|
||||
/// Aliases for the command.
|
||||
fn aliases(&self) -> Vec<&'static str> {
|
||||
Vec::new()
|
||||
}
|
||||
/// Help message of the command.
|
||||
fn help(&self) -> &'static str {
|
||||
"Test command from plugin"
|
||||
"Test commend loaded from dylib"
|
||||
}
|
||||
|
||||
/// Command function
|
||||
async fn execute(
|
||||
&self,
|
||||
client: &mut Client,
|
||||
_args: Vec<&str>,
|
||||
_commands: &PluginManagerType,
|
||||
) -> Result<()> {
|
||||
client.send("content").await?;
|
||||
/// Usage message of the command.
|
||||
fn usage(&self) -> &'static str {
|
||||
"/test"
|
||||
}
|
||||
/// Command function.
|
||||
async fn execute(&self, client: &Client, _args: Vec<&str>) -> anyhow::Result<()> {
|
||||
client.send("successful executed command from dylib")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new event
|
||||
#[async_trait]
|
||||
impl Event for PluginTest {
|
||||
/// Event name (onConnect or onSend)
|
||||
fn name(&self) -> &'static str {
|
||||
"onConnect"
|
||||
}
|
||||
|
||||
/// Event function
|
||||
async fn execute(&self, client: &mut Client) -> Result<()> {
|
||||
client
|
||||
.send(format!("Welcome {}", client.peer_addr().unwrap()))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Register plugin
|
||||
#[no_mangle]
|
||||
pub fn plugin_entry(registrar: &mut dyn Registrar) {
|
||||
registrar.register_plugin(Box::new(PluginTest));
|
||||
registrar.register_command(Box::new(PluginTest));
|
||||
registrar.register_event(Box::new(PluginTest));
|
||||
registrar.register_plugins(Box::new(PluginTest));
|
||||
registrar.register_commands(Box::new(PluginTest));
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:base", "schedule:weekly", "group:allNonMajor", ":semanticCommits"],
|
||||
"labels": ["dependencies"],
|
||||
"automergeType": "pr",
|
||||
"prCreation": "immediate",
|
||||
"packageRules": [
|
||||
{
|
||||
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
|
||||
"automerge": true
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
# https://rust-lang.github.io/rustfmt
|
||||
|
||||
# stable
|
||||
edition = "2021"
|
||||
newline_style = "Unix"
|
||||
|
||||
# nightly
|
||||
group_imports = "StdExternalCrate"
|
||||
imports_granularity = "Crate"
|
||||
format_code_in_doc_comments = true
|
43
src/cli.rs
43
src/cli.rs
|
@ -1,43 +0,0 @@
|
|||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(
|
||||
name = env!("CARGO_PKG_NAME"),
|
||||
version = env!("CARGO_PKG_VERSION"),
|
||||
about = env!("CARGO_PKG_DESCRIPTION"),
|
||||
)]
|
||||
pub struct Cli {
|
||||
#[clap(
|
||||
short = 'h',
|
||||
long = "host",
|
||||
default_value = "0.0.0.0",
|
||||
help = "Tcp server host",
|
||||
display_order = 1
|
||||
)]
|
||||
pub host: String,
|
||||
|
||||
#[clap(
|
||||
short = 'p',
|
||||
long = "port",
|
||||
default_value = "9999",
|
||||
help = "Tcp server port [set 0 to random]",
|
||||
display_order = 2
|
||||
)]
|
||||
pub port: String,
|
||||
|
||||
#[clap(
|
||||
short = 'w',
|
||||
long = "ws-port",
|
||||
default_value = "9998",
|
||||
help = "WebSocket server port [set 0 to random]",
|
||||
display_order = 3
|
||||
)]
|
||||
pub ws_port: String,
|
||||
|
||||
#[clap(
|
||||
long = "enable-websocket",
|
||||
help = "Enable WebSocket proxy to Tcp [default disabled]",
|
||||
display_order = 4
|
||||
)]
|
||||
pub ws_enable: bool,
|
||||
}
|
|
@ -1,31 +1,28 @@
|
|||
use async_trait::async_trait;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use crate::plugins::prelude::*;
|
||||
|
||||
use crate::{
|
||||
plugins::{Command, PluginManagerType, Result},
|
||||
tcp::Client,
|
||||
};
|
||||
|
||||
pub struct CommandDisconnect;
|
||||
pub struct Disconnect;
|
||||
|
||||
#[async_trait]
|
||||
impl Command for CommandDisconnect {
|
||||
impl Command for Disconnect {
|
||||
fn name(&self) -> &'static str {
|
||||
"/disconnect"
|
||||
}
|
||||
|
||||
fn help(&self) -> &'static str {
|
||||
"Disconnect from the server"
|
||||
fn aliases(&self) -> Vec<&'static str> {
|
||||
vec!["/close", "/exit"]
|
||||
}
|
||||
|
||||
async fn execute(
|
||||
&self,
|
||||
client: &mut Client,
|
||||
_args: Vec<&str>,
|
||||
_plugin_manager: &PluginManagerType,
|
||||
) -> Result<()> {
|
||||
fn help(&self) -> &'static str {
|
||||
"Close the connection"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &'static str {
|
||||
"/disconnect"
|
||||
}
|
||||
|
||||
async fn execute(&self, client: &Client, _args: Vec<&str>) -> anyhow::Result<()> {
|
||||
// close the connection
|
||||
client.stream.shutdown().await?;
|
||||
client.close()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,38 +1,46 @@
|
|||
use async_trait::async_trait;
|
||||
use crate::plugins::prelude::*;
|
||||
|
||||
use crate::{
|
||||
plugins::{Command, PluginManagerType, Result},
|
||||
tcp::Client,
|
||||
};
|
||||
|
||||
pub struct CommandHelp;
|
||||
pub struct Help;
|
||||
|
||||
#[async_trait]
|
||||
impl Command for CommandHelp {
|
||||
impl Command for Help {
|
||||
fn name(&self) -> &'static str {
|
||||
"/help"
|
||||
}
|
||||
|
||||
fn help(&self) -> &'static str {
|
||||
"Display all available commands"
|
||||
fn aliases(&self) -> Vec<&'static str> {
|
||||
vec!["/h", "/?", "?"]
|
||||
}
|
||||
|
||||
async fn execute(
|
||||
&self,
|
||||
client: &mut Client,
|
||||
_args: Vec<&str>,
|
||||
plugin_manager: &PluginManagerType,
|
||||
) -> Result<()> {
|
||||
// Vector which will contain help messages of the commands
|
||||
let mut help = Vec::new();
|
||||
fn help(&self) -> &'static str {
|
||||
"Show commands help menu"
|
||||
}
|
||||
|
||||
for command in plugin_manager.commands.iter() {
|
||||
// add a help message for the command
|
||||
help.push(format!("{} - {}", command.name(), command.help()));
|
||||
fn usage(&self) -> &'static str {
|
||||
"/help"
|
||||
}
|
||||
|
||||
async fn execute(&self, client: &Client, _args: Vec<&str>) -> anyhow::Result<()> {
|
||||
let mut msg = Vec::new();
|
||||
|
||||
for cmd in client.plugins_manager.commands.iter() {
|
||||
let aliases = cmd.aliases();
|
||||
|
||||
let aliases = if !aliases.is_empty() {
|
||||
cmd.aliases().join(", ")
|
||||
} else {
|
||||
"none".to_string()
|
||||
};
|
||||
|
||||
msg.push(format!(
|
||||
"{name} - {help} (Aliases: {aliases})",
|
||||
name = cmd.name(),
|
||||
help = cmd.help(),
|
||||
aliases = aliases,
|
||||
))
|
||||
}
|
||||
|
||||
// send help message to the client
|
||||
client.send(help.join("\n\r")).await?;
|
||||
client.send(msg.join("\n"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
//! Build-in commands
|
||||
|
||||
mod disconnect;
|
||||
mod help;
|
||||
|
||||
use crate::plugins::Command;
|
||||
use self::{disconnect::Disconnect, help::Help};
|
||||
use crate::plugins::prelude::*;
|
||||
|
||||
/// Register build-in commands
|
||||
pub fn register_commands() -> Vec<Box<dyn Command>> {
|
||||
// create array with build-in commands
|
||||
vec![
|
||||
Box::new(help::CommandHelp),
|
||||
Box::new(disconnect::CommandDisconnect),
|
||||
]
|
||||
vec![Box::new(Help), Box::new(Disconnect)]
|
||||
}
|
||||
|
|
31
src/lib.rs
31
src/lib.rs
|
@ -1,29 +1,14 @@
|
|||
//! # Servers - Simple TCP and WebSocket 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
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
|
||||
#![doc(html_root_url = "https://servers.medzik.xyz")]
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use crate::tcp::Client;
|
||||
|
||||
pub mod commands;
|
||||
pub mod logger;
|
||||
pub mod plugins;
|
||||
pub mod tcp;
|
||||
|
||||
pub use async_trait::async_trait;
|
||||
lazy_static! {
|
||||
pub static ref CLIENTS: Mutex<HashMap<usize, Client>> = Mutex::new(HashMap::new());
|
||||
pub static ref CLIENT_NEXT: Mutex<usize> = Mutex::new(0);
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
use tracing::metadata::LevelFilter;
|
||||
|
||||
pub fn init() {
|
||||
better_panic::install();
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(LevelFilter::TRACE)
|
||||
.init();
|
||||
}
|
118
src/main.rs
118
src/main.rs
|
@ -1,88 +1,46 @@
|
|||
mod cli;
|
||||
|
||||
use clap::Parser;
|
||||
use servers::{
|
||||
logger,
|
||||
plugins::loader,
|
||||
tcp::{handle_connection, handle_websocket, Client},
|
||||
};
|
||||
use tokio::net::TcpListener;
|
||||
use tracing::{error, info};
|
||||
use servers::tcp::server;
|
||||
|
||||
use crate::cli::Cli;
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(
|
||||
name = env!("CARGO_PKG_NAME"),
|
||||
version = env!("CARGO_PKG_VERSION"),
|
||||
about = env!("CARGO_PKG_DESCRIPTION")
|
||||
)]
|
||||
struct Cli {
|
||||
#[clap(
|
||||
short = 'i',
|
||||
long = "host",
|
||||
help = "Server host",
|
||||
default_value = "0.0.0.0",
|
||||
display_order = 1
|
||||
)]
|
||||
host: String,
|
||||
#[clap(
|
||||
short = 't',
|
||||
long = "tcp-port",
|
||||
help = "TCP server port",
|
||||
default_value = "9999",
|
||||
display_order = 2
|
||||
)]
|
||||
tcp_port: u16,
|
||||
#[clap(
|
||||
short = 'w',
|
||||
long = "websocket-port",
|
||||
help = "WebSocket server port",
|
||||
default_value = "9998",
|
||||
display_order = 3
|
||||
)]
|
||||
ws_port: u16,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
logger::init();
|
||||
fn main() {
|
||||
tracing_subscriber::fmt().init();
|
||||
|
||||
// parse cli args
|
||||
let args = Cli::parse();
|
||||
|
||||
// if enabled start WebSocket server
|
||||
if args.ws_enable {
|
||||
tokio::spawn(start_ws_server(
|
||||
args.host.clone(),
|
||||
args.ws_port,
|
||||
args.port.clone(),
|
||||
));
|
||||
}
|
||||
let tcp_host = format!("{host}:{port}", host = args.host, port = args.tcp_port);
|
||||
let ws_host = format!("{host}:{port}", host = args.host, port = args.ws_port);
|
||||
|
||||
// start tcp server
|
||||
start_tcp_server(args.host, args.port).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start tcp server
|
||||
async fn start_tcp_server(host: String, port: String) -> anyhow::Result<()> {
|
||||
// listen TCP server
|
||||
let listener = TcpListener::bind(format!("{host}:{port}")).await?;
|
||||
|
||||
info!("TCP server started at: {}", listener.local_addr()?);
|
||||
|
||||
// load plugins, commands and events
|
||||
let plugin_manager = loader()?;
|
||||
|
||||
// Accepts a new incoming connection from this listener.
|
||||
while let Ok((stream, _address)) = listener.accept().await {
|
||||
let client = Client::new(stream);
|
||||
let plugin_manager = plugin_manager.clone();
|
||||
|
||||
// handle client connection in new thread
|
||||
tokio::spawn(async move {
|
||||
// get ip address of the client
|
||||
let ip = client.peer_addr().expect("failed to get peer address");
|
||||
|
||||
if let Err(e) = handle_connection(client, plugin_manager).await {
|
||||
error!("Client {ip}: {e}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// server for a unexpectedly reason be terminated
|
||||
panic!("TCP server unexpectedly terminated!")
|
||||
}
|
||||
|
||||
/// Start WebSocket server
|
||||
async fn start_ws_server(host: String, port: String, tcp_port: String) -> anyhow::Result<()> {
|
||||
// listen Tcp server
|
||||
let listener = tokio::net::TcpListener::bind(format!("{host}:{port}")).await?;
|
||||
|
||||
info!("WebSocket server started at: {}", listener.local_addr()?);
|
||||
|
||||
// Accepts a new incoming connection from this listener.
|
||||
while let Ok((stream, _address)) = listener.accept().await {
|
||||
let tcp_port = tcp_port.clone();
|
||||
tokio::spawn(async {
|
||||
// get ip address of the client
|
||||
let ip = stream.peer_addr().expect("failed to get peer address");
|
||||
|
||||
if let Err(e) = handle_websocket(stream, tcp_port).await {
|
||||
error!("Client {ip}: {e}")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// server for a unexpectedly reason be terminated
|
||||
panic!("WebSocket server unexpectedly terminated!")
|
||||
server::run(tcp_host, ws_host).expect("failed to start tcp server");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
use std::{fs, path::Path, sync::Arc};
|
||||
|
||||
use libloading::{Library, Symbol};
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::{
|
||||
commands,
|
||||
plugins::{
|
||||
manager::{PluginsManager, PluginsManagerType},
|
||||
prelude::*,
|
||||
},
|
||||
};
|
||||
|
||||
pub fn loader(plugins_dir: &str) -> anyhow::Result<PluginsManagerType> {
|
||||
// if plugins directory doesn't exists, create it
|
||||
if !Path::new(plugins_dir).exists() {
|
||||
fs::create_dir_all(plugins_dir)?;
|
||||
}
|
||||
|
||||
// get all files from the plugins directory
|
||||
let plugins_files = fs::read_dir(plugins_dir)?;
|
||||
|
||||
// init a plugins manager
|
||||
let mut plugins_manager = PluginsManager::new();
|
||||
|
||||
// add 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();
|
||||
|
||||
info!("Loading plugin {}", path_str);
|
||||
|
||||
// loading library from .so is unsafe
|
||||
unsafe {
|
||||
// Box::new and Box::leak must be there because
|
||||
// if it isn't there it throws an segmentation fault
|
||||
let lib = Box::leak(Box::new(Library::new(&path)?));
|
||||
|
||||
trace!("Finding symbol `plugin_entry` in {}", path_str);
|
||||
let func: Symbol<unsafe extern "C" fn(&mut dyn Registrar) -> ()> =
|
||||
lib.get(b"plugin_entry")?;
|
||||
|
||||
// execute the function `plugin_entry` to load the plugin (possible segmentation fault)
|
||||
trace!("Running function `plugin_entry` from plugin {}", path_str);
|
||||
func(&mut plugins_manager);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Arc::new(plugins_manager))
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
use std::{fs, path::Path, sync::Arc};
|
||||
|
||||
use libloading::{Library, Symbol};
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::{commands, plugins::Registrar};
|
||||
|
||||
use super::{PluginManager, PluginManagerType};
|
||||
|
||||
/// Plugins and Commands loader
|
||||
pub fn loader() -> anyhow::Result<PluginManagerType> {
|
||||
let config_dir = "./plugins";
|
||||
|
||||
// if config directory doesn't exists, create it
|
||||
if !Path::new(config_dir).exists() {
|
||||
fs::create_dir_all(config_dir)?;
|
||||
}
|
||||
|
||||
// get path to .so lib from command argument
|
||||
let paths = fs::read_dir(config_dir)?;
|
||||
|
||||
// create a plugin manager
|
||||
let mut plugin_manager = PluginManager::new();
|
||||
|
||||
// register default commands
|
||||
for command in commands::register_commands() {
|
||||
plugin_manager.commands.push(command)
|
||||
}
|
||||
|
||||
// for all plugin in directory
|
||||
for path in paths {
|
||||
// get library file path
|
||||
let path = path?.path();
|
||||
let plugin_path = path.to_str().unwrap();
|
||||
|
||||
info!("Loading plugin `{}`", plugin_path);
|
||||
|
||||
// loading library from .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 function `plugin_entry` from library
|
||||
trace!("Finding symbol `plugin_entry` in `{}`", plugin_path);
|
||||
let func: Symbol<unsafe extern "C" fn(&mut dyn Registrar) -> ()> =
|
||||
lib.get(b"plugin_entry")?;
|
||||
|
||||
// execute initial plugin function
|
||||
trace!(
|
||||
"Running function `plugin_entry` from plugin `{}`",
|
||||
plugin_path
|
||||
);
|
||||
func(&mut plugin_manager);
|
||||
}
|
||||
}
|
||||
|
||||
// return a `PluginManager`
|
||||
Ok(Arc::new(plugin_manager))
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
use core::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::plugins::prelude::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PluginsManager {
|
||||
/// Vector with all loaded plugins.
|
||||
pub plugins: Vec<Box<dyn Plugin>>,
|
||||
/// Vector with all loaded commands.
|
||||
pub commands: Vec<Box<dyn Command>>,
|
||||
/// Vector with all loaded events.
|
||||
pub events: Vec<Box<dyn Event>>,
|
||||
}
|
||||
|
||||
impl PluginsManager {
|
||||
/// Returns an empty PluginsManager
|
||||
pub fn new() -> PluginsManager {
|
||||
Self {
|
||||
plugins: Vec::new(),
|
||||
commands: Vec::new(),
|
||||
events: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PluginsManager {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("PluginsManager")
|
||||
.field("plugins", &self.plugins.len())
|
||||
.field("commands", &self.commands.len())
|
||||
.field("events", &self.events.len())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub type PluginsManagerType = Arc<PluginsManager>;
|
|
@ -1,161 +1,16 @@
|
|||
//! 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]
|
||||
//! servers = { git = "https://github.com/MedzikUser/servers" }
|
||||
//! ```
|
||||
//!
|
||||
//! In file `src/lib.rs`
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use servers::{plugins::{Plugin, Registrar}, tcp::Client, async_trait};
|
||||
//!
|
||||
//! struct PluginTest;
|
||||
//!
|
||||
//! /// Create a new plugin
|
||||
//! #[async_trait]
|
||||
//! impl Plugin for PluginTest {
|
||||
//! /// Name of the plugin.
|
||||
//! fn name(&self) -> &'static str {
|
||||
//! "test"
|
||||
//! }
|
||||
//!
|
||||
//! /// A function will be executed when plugin loading.
|
||||
//! /// Usally used for initialization.
|
||||
//! async fn on_plugin_load(&self) {}
|
||||
//! }
|
||||
//!
|
||||
//! /// Register plugin
|
||||
//! #[no_mangle]
|
||||
//! pub fn plugin_entry(registrar: &mut dyn Registrar) {
|
||||
//! registrar.register_plugin(Box::new(PluginTest));
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Add command
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use servers::{
|
||||
//! plugins::{Command, PluginManagerType, Registrar, Result, async_trait},
|
||||
//! tcp::Client,
|
||||
//! };
|
||||
//! #
|
||||
//! # struct PluginTest;
|
||||
//! #
|
||||
//! # #[async_trait]
|
||||
//! # impl servers::plugins::Plugin for PluginTest {
|
||||
//! # /// Name of the plugin.
|
||||
//! # fn name(&self) -> &'static str {
|
||||
//! # "test"
|
||||
//! # }
|
||||
//! #
|
||||
//! # /// A function will be executed when plugin loading.
|
||||
//! # /// Usally used for initialization.
|
||||
//! # async fn on_plugin_load(&self) {}
|
||||
//! # }
|
||||
//!
|
||||
//! /// Create a new command
|
||||
//! #[async_trait]
|
||||
//! impl Command for PluginTest {
|
||||
//! /// Command name
|
||||
//! fn name(&self) -> &'static str {
|
||||
//! "/test"
|
||||
//! }
|
||||
//!
|
||||
//! /// Help message of the command
|
||||
//! fn help(&self) -> &'static str {
|
||||
//! "test command"
|
||||
//! }
|
||||
//!
|
||||
//! /// Command function
|
||||
//! async fn execute(&self, client: &mut Client, _args: Vec<&str>, _commands: &PluginManagerType) -> Result<()> {
|
||||
//! client.send("Command executed!").await?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! /// Register plugin
|
||||
//! #[no_mangle]
|
||||
//! pub fn plugin_entry(registrar: &mut dyn Registrar) {
|
||||
//! # registrar.register_plugin(Box::new(PluginTest));
|
||||
//! registrar.register_command(Box::new(PluginTest));
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Add event
|
||||
//!
|
||||
//! In file `src/lib.rs`
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use servers::{
|
||||
//! plugins::{Event, Registrar, Result, async_trait},
|
||||
//! tcp::Client,
|
||||
//! };
|
||||
//! #
|
||||
//! # struct PluginTest;
|
||||
//! #
|
||||
//! # #[async_trait]
|
||||
//! # impl servers::plugins::Plugin for PluginTest {
|
||||
//! # /// Name of the plugin.
|
||||
//! # fn name(&self) -> &'static str {
|
||||
//! # "test"
|
||||
//! # }
|
||||
//! #
|
||||
//! # /// A function will be executed when plugin loading.
|
||||
//! # /// Usally used for initialization.
|
||||
//! # async fn on_plugin_load(&self) {}
|
||||
//! # }
|
||||
//!
|
||||
//! /// Create a new event
|
||||
//! #[async_trait]
|
||||
//! impl Event for PluginTest {
|
||||
//! /// Event name (onConnect or onSend)
|
||||
//! fn name(&self) -> &'static str {
|
||||
//! "onConnect"
|
||||
//! }
|
||||
//!
|
||||
//! /// Event function
|
||||
//! async fn execute(&self, client: &mut Client) -> Result<()> {
|
||||
//! client
|
||||
//! .send(format!("Welcome {}", client.peer_addr()?))
|
||||
//! .await?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! /// Register plugin
|
||||
//! #[no_mangle]
|
||||
//! pub fn plugin_entry(registrar: &mut dyn Registrar) {
|
||||
//! # registrar.register_plugin(Box::new(PluginTest));
|
||||
//! registrar.register_event(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 (or create a symlink) the built plugin to the `plugin/` directory in the server root directory.
|
||||
mod load;
|
||||
pub mod manager;
|
||||
pub mod types;
|
||||
|
||||
mod loader;
|
||||
mod types;
|
||||
pub use load::*;
|
||||
|
||||
pub use loader::*;
|
||||
pub use types::*;
|
||||
pub mod prelude {
|
||||
use super::*;
|
||||
|
||||
pub extern crate anyhow;
|
||||
pub extern crate async_std;
|
||||
pub use async_trait::async_trait;
|
||||
|
||||
pub use self::types::*;
|
||||
pub use crate::tcp::Client;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
use std::{any::Any, sync::Arc};
|
||||
use std::any::Any;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::tcp::Client;
|
||||
use crate::{plugins::manager::PluginsManager, tcp::Client};
|
||||
|
||||
/// Custom Result alias, imported from [anyhow::Result].
|
||||
pub type Result<T> = anyhow::Result<T>;
|
||||
|
||||
/// A plugin wich allows you to add extra functionality.
|
||||
// A main plugin trait.
|
||||
#[async_trait]
|
||||
pub trait Plugin: Any + Send + Sync {
|
||||
/// Name of the plugin.
|
||||
fn name(&self) -> &'static str;
|
||||
/// A function will be executed when plugin loading.
|
||||
/// Usally used for initialization.
|
||||
async fn on_plugin_load(&self);
|
||||
/// A function that will be executed when the plugin is loaded.
|
||||
async fn on_load(&self);
|
||||
}
|
||||
|
||||
/// Add a command to the plugin.
|
||||
|
@ -22,76 +18,52 @@ pub trait Plugin: Any + Send + Sync {
|
|||
pub trait Command: Any + Send + Sync {
|
||||
/// Name of the command.
|
||||
fn name(&self) -> &'static str;
|
||||
/// Aliases for the command.
|
||||
fn aliases(&self) -> Vec<&'static str>;
|
||||
/// Help message of the command.
|
||||
fn help(&self) -> &'static str;
|
||||
/// Command function
|
||||
async fn execute(
|
||||
&self,
|
||||
client: &mut Client,
|
||||
args: Vec<&str>,
|
||||
plugin_manager: &PluginManagerType,
|
||||
) -> Result<()>;
|
||||
/// Usage message of the command.
|
||||
fn usage(&self) -> &'static str;
|
||||
/// Command function.
|
||||
async fn execute(&self, client: &Client, args: Vec<&str>) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
/// Add a new function that will be executed when the event occurs.
|
||||
/// All possible to run events.
|
||||
pub enum EventType {
|
||||
/// On client connected.
|
||||
OnConnect,
|
||||
/// On client sent message.
|
||||
OnSend,
|
||||
}
|
||||
|
||||
/// Add a event to the plugin.
|
||||
#[async_trait]
|
||||
pub trait Event: Any + Send + Sync {
|
||||
/// Event name (onConnect or onSend)
|
||||
fn name(&self) -> &'static str;
|
||||
/// Event function
|
||||
async fn execute(&self, client: &mut Client) -> Result<()>;
|
||||
/// Type of the event.
|
||||
fn event(&self) -> EventType;
|
||||
/// Event function.
|
||||
async fn execute(&self) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
/// Plugin Manager with all plugins features.
|
||||
pub struct PluginManager {
|
||||
/// Array with loaded plugins.
|
||||
pub plugins: Vec<Box<dyn Plugin>>,
|
||||
/// Array with all commands.
|
||||
pub commands: Vec<Box<dyn Command>>,
|
||||
/// Array with all events.
|
||||
pub events: Vec<Box<dyn Event>>,
|
||||
}
|
||||
|
||||
impl PluginManager {
|
||||
/// Create an empty [PluginManager]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
plugins: Vec::new(),
|
||||
commands: Vec::new(),
|
||||
events: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PluginManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Arc type of the [PluginManager].
|
||||
pub type PluginManagerType = Arc<PluginManager>;
|
||||
|
||||
/// Plugin Registrar
|
||||
pub trait Registrar {
|
||||
/// Function to register the plugin
|
||||
fn register_plugin(&mut self, plugin: Box<dyn Plugin>);
|
||||
/// Function to register the command
|
||||
fn register_command(&mut self, command: Box<dyn Command>);
|
||||
/// Function to register the event
|
||||
fn register_event(&mut self, event: Box<dyn Event>);
|
||||
/// Function to register plugins.
|
||||
fn register_plugins(&mut self, plugin: Box<dyn Plugin>);
|
||||
/// Function to register commands.
|
||||
fn register_commands(&mut self, command: Box<dyn Command>);
|
||||
/// Function to register events.
|
||||
fn register_events(&mut self, event: Box<dyn Event>);
|
||||
}
|
||||
|
||||
impl Registrar for PluginManager {
|
||||
fn register_plugin(&mut self, plugin: Box<dyn Plugin>) {
|
||||
impl Registrar for PluginsManager {
|
||||
fn register_plugins(&mut self, plugin: Box<dyn Plugin>) {
|
||||
self.plugins.push(plugin)
|
||||
}
|
||||
|
||||
fn register_command(&mut self, command: Box<dyn Command>) {
|
||||
fn register_commands(&mut self, command: Box<dyn Command>) {
|
||||
self.commands.push(command)
|
||||
}
|
||||
|
||||
fn register_event(&mut self, event: Box<dyn Event>) {
|
||||
fn register_events(&mut self, event: Box<dyn Event>) {
|
||||
self.events.push(event)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +1,166 @@
|
|||
use core::fmt;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use tokio::{
|
||||
io::{self, AsyncReadExt, AsyncWriteExt},
|
||||
net::TcpStream,
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
io::{Read, Write},
|
||||
net::{Shutdown, SocketAddr, TcpStream},
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
/// Max size of a TCP packet
|
||||
use tungstenite::{accept, Message, WebSocket};
|
||||
|
||||
use super::server::PLUGINS_MANAGER;
|
||||
use crate::plugins::manager::PluginsManagerType;
|
||||
|
||||
/// Max length of a TCP and UDP packet
|
||||
pub const MAX_PACKET_LEN: usize = 65536;
|
||||
|
||||
/// TCP Client
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Client {
|
||||
/// TCP stream of this client
|
||||
pub stream: TcpStream,
|
||||
pub stream: ClientStream,
|
||||
pub map: HashMap<String, ClientMapValue>,
|
||||
pub plugins_manager: PluginsManagerType,
|
||||
}
|
||||
|
||||
#[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),
|
||||
}
|
||||
|
||||
/// Connection stream of the client
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ClientStream {
|
||||
/// TCP stream
|
||||
TCP(Arc<TcpStream>),
|
||||
/// WebSocket stream
|
||||
WebSocket(Arc<Mutex<WebSocket<TcpStream>>>),
|
||||
}
|
||||
|
||||
impl From<TcpStream> for Client {
|
||||
fn from(stream: TcpStream) -> Self {
|
||||
Self {
|
||||
stream: ClientStream::TCP(Arc::new(stream)),
|
||||
map: HashMap::new(),
|
||||
plugins_manager: PLUGINS_MANAGER.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebSocket<TcpStream>> for Client {
|
||||
fn from(stream: WebSocket<TcpStream>) -> Self {
|
||||
Self {
|
||||
stream: ClientStream::WebSocket(Arc::new(Mutex::new(stream))),
|
||||
map: HashMap::new(),
|
||||
plugins_manager: PLUGINS_MANAGER.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Create new Client
|
||||
pub fn new(stream: TcpStream) -> Self {
|
||||
Self { stream }
|
||||
/// Create a new TCP Client instance
|
||||
pub fn new_tcp(stream: TcpStream) -> Self {
|
||||
Self::from(stream)
|
||||
}
|
||||
|
||||
/// Read message/buffer from the client
|
||||
pub async fn read(&mut self) -> anyhow::Result<String> {
|
||||
// allocate an empty buffer
|
||||
let mut buf = [0; MAX_PACKET_LEN];
|
||||
/// Create a new WebSocket Client instance
|
||||
pub fn new_websocket(stream: TcpStream) -> anyhow::Result<Self> {
|
||||
let websocket = accept(stream)?;
|
||||
|
||||
// read buffer from stream
|
||||
let len = self.stream.read(&mut buf).await?;
|
||||
Ok(Self::from(websocket))
|
||||
}
|
||||
|
||||
// select only used bytes from the buffer
|
||||
let buf = &buf[0..len];
|
||||
/// Recieve a message from the client
|
||||
pub fn read(&self) -> anyhow::Result<String> {
|
||||
// read the message from the stream
|
||||
let mut msg = match &self.stream {
|
||||
ClientStream::TCP(stream) => {
|
||||
// allocate an empty buffer
|
||||
let mut buf = [0; MAX_PACKET_LEN];
|
||||
|
||||
// encode buffer (&[u8]) to a String
|
||||
let mut decoded = String::from_utf8(buf.to_vec())?;
|
||||
// read the message and get length of it
|
||||
let len = stream.as_ref().read(&mut buf)?;
|
||||
|
||||
// select only used bytes in the buffer
|
||||
let buf = &buf[0..len];
|
||||
|
||||
// decode buffer (&[u8]) to a String
|
||||
String::from_utf8(buf.to_vec())?
|
||||
}
|
||||
ClientStream::WebSocket(stream) => {
|
||||
// read the message from the stream
|
||||
let msg = stream.lock().unwrap().read_message()?;
|
||||
|
||||
// decode message to a String
|
||||
msg.to_string()
|
||||
}
|
||||
};
|
||||
|
||||
// remove new line characters
|
||||
while decoded.ends_with('\n') || decoded.ends_with('\r') {
|
||||
decoded.pop();
|
||||
while msg.ends_with('\n') || msg.ends_with('\r') {
|
||||
msg.pop();
|
||||
}
|
||||
|
||||
Ok(decoded)
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
/// Send message to the client
|
||||
pub async fn send<S>(&mut self, content: S) -> io::Result<()>
|
||||
/// Send a message to the client
|
||||
pub fn send<S>(&self, msg: S) -> anyhow::Result<()>
|
||||
where
|
||||
S: ToString + fmt::Display,
|
||||
S: ToString,
|
||||
S: fmt::Display,
|
||||
{
|
||||
// add a new line at the end of the content
|
||||
let content = format!("{content}\n\r");
|
||||
// convert the message into a string
|
||||
let msg = msg.to_string();
|
||||
|
||||
// send message
|
||||
self.stream.write_all(content.as_bytes()).await
|
||||
// convert the message into bytes to send it
|
||||
let buf = msg.as_bytes();
|
||||
|
||||
// send the message
|
||||
match &self.stream {
|
||||
ClientStream::TCP(stream) => stream.as_ref().write_all(buf)?,
|
||||
ClientStream::WebSocket(stream) => {
|
||||
stream.lock().unwrap().write_message(Message::from(msg))?
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
self.stream.peer_addr()
|
||||
/// Returns the socket address of the remote peer of this connection.
|
||||
pub fn peer_addr(&self) -> anyhow::Result<SocketAddr> {
|
||||
let addr = match &self.stream {
|
||||
ClientStream::TCP(stream) => stream.peer_addr(),
|
||||
ClientStream::WebSocket(stream) => stream.lock().unwrap().get_ref().peer_addr(),
|
||||
}?;
|
||||
|
||||
Ok(addr)
|
||||
}
|
||||
|
||||
/// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
|
||||
pub fn flush(&self) -> anyhow::Result<()> {
|
||||
match &self.stream {
|
||||
ClientStream::TCP(stream) => stream.as_ref().flush()?,
|
||||
ClientStream::WebSocket(_stream) => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Close the connection
|
||||
pub fn close(&self) -> anyhow::Result<()> {
|
||||
match &self.stream {
|
||||
ClientStream::TCP(stream) => stream.shutdown(Shutdown::Both)?,
|
||||
ClientStream::WebSocket(stream) => stream.lock().unwrap().close(None)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
use tokio::io::AsyncWriteExt;
|
||||
use tracing::{error, info, trace};
|
||||
|
||||
use crate::plugins::PluginManagerType;
|
||||
|
||||
use super::Client;
|
||||
|
||||
/// Handle Client connection
|
||||
pub async fn handle_connection(
|
||||
mut client: Client,
|
||||
plugin_manager: PluginManagerType,
|
||||
) -> anyhow::Result<()> {
|
||||
info!("New Client: {}", client.peer_addr()?);
|
||||
|
||||
// run `onConnect` events from plugins
|
||||
check_event(&mut client, &plugin_manager, "onConnect").await?;
|
||||
|
||||
loop {
|
||||
// read client message/buffer
|
||||
let buf = client.read().await?;
|
||||
|
||||
// run `onSend` events from plugins
|
||||
check_event(&mut client, &plugin_manager, "onSend").await?;
|
||||
|
||||
// split the message by whitespaces and collect it into Vec<&str>
|
||||
let mut args = buf.split_ascii_whitespace().collect::<Vec<&str>>();
|
||||
|
||||
// client sent an empty buffer
|
||||
if args.is_empty() {
|
||||
client.send("empty buffer").await?;
|
||||
|
||||
// don't execute the following commands because it causes panic
|
||||
continue;
|
||||
}
|
||||
|
||||
// get command from args
|
||||
let cmd = args[0];
|
||||
|
||||
// remove command name from args
|
||||
args = args[1..args.len()].to_vec();
|
||||
|
||||
// search if a command exists
|
||||
for command in plugin_manager.commands.iter() {
|
||||
// if this is the entered command
|
||||
if cmd == command.name() {
|
||||
trace!("Executing a command `{}`", command.name());
|
||||
|
||||
// execute command
|
||||
match command.execute(&mut client, args, &plugin_manager).await {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
error!("failed to execute command `{cmd}`, error message = `{err}`");
|
||||
|
||||
client.send(format!("error: {err}")).await?;
|
||||
}
|
||||
}
|
||||
|
||||
// don't search for more commands
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if an I/O or EOF error, abort the connection
|
||||
if client.stream.flush().await.is_err() {
|
||||
// terminate connection
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Search for a events and execute it
|
||||
async fn check_event(
|
||||
client: &mut Client,
|
||||
events: &PluginManagerType,
|
||||
event_name: &str,
|
||||
) -> anyhow::Result<()> {
|
||||
for event in events.events.iter() {
|
||||
// check if this event should be started
|
||||
if event.name() == event_name {
|
||||
trace!("Executing a event `{}`", event.name());
|
||||
|
||||
// execute event
|
||||
match event.execute(client).await {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
error!("failed to execute event `{event_name}`, error message = `{err}`");
|
||||
|
||||
client.send(format!("error: {err}")).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
#![allow(clippy::unused_io_amount)]
|
||||
|
||||
use futures_util::{
|
||||
stream::{SplitSink, SplitStream},
|
||||
SinkExt, StreamExt,
|
||||
};
|
||||
use tokio::{
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
net::{
|
||||
tcp::{OwnedReadHalf, OwnedWriteHalf},
|
||||
TcpStream,
|
||||
},
|
||||
};
|
||||
use tokio_tungstenite::WebSocketStream;
|
||||
use tracing::info;
|
||||
use tungstenite::Message;
|
||||
|
||||
use super::MAX_PACKET_LEN;
|
||||
|
||||
/// Handle WebSocket connection
|
||||
pub async fn handle_websocket(stream: TcpStream, tcp_port: String) -> anyhow::Result<()> {
|
||||
info!("New WebSocket Client: {}", stream.peer_addr()?);
|
||||
|
||||
// accept connection as WebSocket
|
||||
let ws_stream = tokio_tungstenite::accept_async(stream).await?;
|
||||
|
||||
// connect to Tcp server
|
||||
let tcp_stream = TcpStream::connect(format!("0.0.0.0:{}", tcp_port)).await?;
|
||||
|
||||
// split streams
|
||||
let (tcp_read, tcp_write) = tcp_stream.into_split();
|
||||
let (ws_write, ws_read) = ws_stream.split();
|
||||
|
||||
// tcp read -> ws write
|
||||
tokio::spawn(tcp_to_ws(tcp_read, ws_write));
|
||||
|
||||
// ws read -> tcp write
|
||||
ws_to_tcp(tcp_write, ws_read).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tcp read -> WebSocket write
|
||||
async fn tcp_to_ws(
|
||||
mut tcp_read: OwnedReadHalf,
|
||||
mut ws_write: SplitSink<WebSocketStream<TcpStream>, Message>,
|
||||
) -> anyhow::Result<()> {
|
||||
// allocate an empty buffer
|
||||
let mut buf = [0; MAX_PACKET_LEN];
|
||||
|
||||
loop {
|
||||
// read buffer from tcp
|
||||
let len = tcp_read.read(&mut buf).await?;
|
||||
|
||||
if len > 0 {
|
||||
// select only used bytes from the buffer
|
||||
let recv_buf = &buf[0..len];
|
||||
// covert &[u8] buffer to a vector
|
||||
let recv_vec = recv_buf.to_vec();
|
||||
// create a `Message` type from buffer Vec<u8>
|
||||
let msg = Message::Binary(recv_vec);
|
||||
|
||||
// write buffer to websocket
|
||||
ws_write.send(msg).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// WebSocket read -> Tcp write
|
||||
async fn ws_to_tcp(
|
||||
mut tcp_write: OwnedWriteHalf,
|
||||
mut ws_read: SplitStream<WebSocketStream<TcpStream>>,
|
||||
) -> anyhow::Result<()> {
|
||||
while let Some(msg) = ws_read.next().await {
|
||||
// handle error in the message
|
||||
let msg = msg?;
|
||||
// create a buffer from a message
|
||||
let buf = msg.into_data();
|
||||
|
||||
// write buffer to tcp
|
||||
tcp_write.write(&buf).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,9 +1,4 @@
|
|||
//! TCP connection utils
|
||||
|
||||
mod client;
|
||||
mod handle_connection;
|
||||
mod handle_websocket;
|
||||
pub mod server;
|
||||
|
||||
pub use client::*;
|
||||
pub use handle_connection::*;
|
||||
pub use handle_websocket::*;
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
use std::net::TcpListener;
|
||||
|
||||
use async_std::task;
|
||||
use futures::join;
|
||||
use lazy_static::lazy_static;
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::{
|
||||
plugins::{self, manager::PluginsManagerType},
|
||||
tcp::Client,
|
||||
CLIENTS, CLIENT_NEXT,
|
||||
};
|
||||
|
||||
pub const PLUGINS_DIR: &str = "plugins";
|
||||
|
||||
lazy_static! {
|
||||
pub static ref PLUGINS_MANAGER: PluginsManagerType =
|
||||
plugins::loader(PLUGINS_DIR).expect("failed to load plugins");
|
||||
}
|
||||
|
||||
/// Start server
|
||||
pub fn run(tcp_host: String, ws_host: String) -> anyhow::Result<()> {
|
||||
info!("Loaded {} plugins", PLUGINS_MANAGER.plugins.len());
|
||||
info!("Loaded {} commands", PLUGINS_MANAGER.commands.len());
|
||||
info!("Loaded {} events", PLUGINS_MANAGER.events.len());
|
||||
|
||||
let tcp_child = task::spawn(async move {
|
||||
start_tcp(tcp_host).await.unwrap();
|
||||
});
|
||||
|
||||
let ws_child = task::spawn(async move {
|
||||
start_websocket(ws_host).await.unwrap();
|
||||
});
|
||||
|
||||
task::block_on(async {
|
||||
join!(tcp_child, ws_child);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Process client connection
|
||||
async fn process(client: Client) -> anyhow::Result<()> {
|
||||
let client_addr = client.peer_addr()?;
|
||||
|
||||
info!("Processing client connection: {}", client_addr);
|
||||
|
||||
loop {
|
||||
let buf = client.read()?;
|
||||
|
||||
let mut args: Vec<&str> = buf.split_ascii_whitespace().collect();
|
||||
|
||||
// if client sent an empty buffer
|
||||
if buf.is_empty() {
|
||||
client.send("empty buffer")?;
|
||||
continue;
|
||||
}
|
||||
|
||||
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 let Some((_i, cmd)) = command {
|
||||
cmd.execute(&client, args).await?;
|
||||
} else {
|
||||
client.send("unknown command")?;
|
||||
}
|
||||
|
||||
client.flush()?;
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_tcp(host: String) -> anyhow::Result<()> {
|
||||
let listener = TcpListener::bind(host)?;
|
||||
|
||||
let incoming = listener.incoming();
|
||||
|
||||
for stream in incoming {
|
||||
let stream = stream?;
|
||||
|
||||
task::spawn(async {
|
||||
let client = Client::new_tcp(stream);
|
||||
|
||||
// get id for the client and add one to next id
|
||||
let id = (*CLIENT_NEXT.lock().unwrap() + 1).clone();
|
||||
|
||||
// insert the cloned client to CLIENTS
|
||||
CLIENTS.lock().unwrap().insert(id, client.clone());
|
||||
|
||||
if let Err(err) = process(client).await {
|
||||
error!("TCP client error: {}", err);
|
||||
}
|
||||
|
||||
// delete the client from CLIENTS map
|
||||
CLIENTS.lock().unwrap().remove(&id);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn start_websocket(host: String) -> anyhow::Result<()> {
|
||||
let listener = TcpListener::bind(host)?;
|
||||
|
||||
let incoming = listener.incoming();
|
||||
|
||||
for stream in incoming {
|
||||
let stream = stream?;
|
||||
|
||||
task::spawn(async {
|
||||
let client = Client::new_websocket(stream).unwrap();
|
||||
|
||||
// get id for the client and add one to next id
|
||||
let id = (*CLIENT_NEXT.lock().unwrap() + 1).clone();
|
||||
|
||||
// insert the cloned client to CLIENTS
|
||||
CLIENTS.lock().unwrap().insert(id, client.clone());
|
||||
|
||||
if let Err(err) = process(client).await {
|
||||
error!("TCP client error: {}", err);
|
||||
}
|
||||
|
||||
// delete the client from CLIENTS map
|
||||
CLIENTS.lock().unwrap().remove(&id);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue