html terminal
use bot
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Cargo.lock | 929 | ||||
| -rw-r--r-- | Cargo.toml | 20 | ||||
| -rw-r--r-- | src/bot.rs | 281 | ||||
| -rw-r--r-- | src/logging.rs | 1 | ||||
| -rw-r--r-- | src/main.rs | 1 | ||||
| -rw-r--r-- | src/process.rs | 1 | ||||
| -rw-r--r-- | src/server.rs | 28 | ||||
| -rw-r--r-- | src/webhook.rs | 310 |
9 files changed, 1140 insertions, 432 deletions
@@ -1 +1,2 @@ /target +*token @@ -3,6 +3,12 @@ version = 3 [[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] name = "aho-corasick" version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -21,6 +27,21 @@ dependencies = [ ] [[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] name = "ansi-to-html" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -32,6 +53,12 @@ dependencies = [ ] [[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] name = "arrayvec" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -150,6 +177,22 @@ dependencies = [ ] [[package]] +name = "async-tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b71b31561643aa8e7df3effe284fa83ab1a840e52294c5f4bd7bfd8b2becbb" +dependencies = [ + "futures-io", + "futures-util", + "log", + "pin-project-lite", + "tokio", + "tokio-rustls 0.23.4", + "tungstenite 0.17.3", + "webpki-roots", +] + +[[package]] name = "atomic-waker" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -286,6 +329,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "chrono" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "winapi", +] + +[[package]] name = "concurrent-queue" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -301,16 +357,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] name = "core-foundation-sys" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -326,6 +372,15 @@ dependencies = [ ] [[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] name = "crossbeam-utils" version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -356,6 +411,66 @@ dependencies = [ ] [[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] name = "derive_more" version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -379,6 +494,15 @@ dependencies = [ ] [[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] name = "errno" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -386,7 +510,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -415,31 +539,26 @@ dependencies = [ ] [[package]] -name = "fnv" -version = "1.0.7" +name = "flate2" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ - "foreign-types-shared", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -560,9 +679,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -607,6 +726,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] name = "hermit-abi" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -680,23 +805,52 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" dependencies = [ - "bytes", + "http", "hyper", - "native-tls", + "rustls 0.21.1", "tokio", - "tokio-native-tls", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", ] [[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -729,10 +883,16 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" + +[[package]] name = "itoa" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -764,9 +924,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "linux-raw-sys" @@ -775,10 +935,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] name = "log" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" dependencies = [ "value-bag", ] @@ -802,6 +972,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] name = "minify-html" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -832,32 +1012,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "mio" -version = "0.8.8" +name = "miniz_oxide" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", + "adler", ] [[package]] -name = "native-tls" -version = "0.2.11" +name = "mio" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ - "lazy_static", "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "wasi", + "windows-sys", ] [[package]] @@ -871,73 +1042,37 @@ dependencies = [ ] [[package]] -name = "num_cpus" -version = "1.15.0" +name = "num-traits" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ - "hermit-abi 0.2.6", - "libc", + "autocfg", ] [[package]] -name = "once_cell" -version = "1.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" - -[[package]] -name = "openssl" -version = "0.10.54" +name = "num_cpus" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", + "hermit-abi 0.2.6", "libc", - "once_cell", - "openssl-macros", - "openssl-sys", ] [[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "111.26.0+1.1.1u" +name = "once_cell" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37" -dependencies = [ - "cc", -] +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] -name = "openssl-sys" -version = "0.9.88" +name = "ordered-float" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", + "num-traits", ] [[package]] @@ -945,16 +1080,21 @@ name = "panel" version = "0.1.0" dependencies = [ "ansi-to-html", + "anyhow", "async-std", "axum", "futures", "futures-util", "minify-html", + "minify-js", "paste", + "poise", + "regex", + "serenity", "strip-ansi-escapes", + "strum", "tokio", "tokio-stream", - "webhook", ] [[package]] @@ -964,6 +1104,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" [[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] name = "parse-js" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -982,9 +1145,9 @@ checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" @@ -1019,10 +1182,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.27" +name = "poise" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "6d591af1c934c29adda172665f69b837e642d4fee85598baffb95dd98110467d" +dependencies = [ + "async-trait", + "derivative", + "futures-core", + "futures-util", + "log", + "once_cell", + "parking_lot", + "poise_macros", + "regex", + "serenity", + "tokio", +] + +[[package]] +name = "poise_macros" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40270099e1527efae99fdc0609d397e76310b529d4980ad38ab14d81803ca0fa" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "polling" @@ -1037,7 +1225,7 @@ dependencies = [ "libc", "log", "pin-project-lite", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1048,9 +1236,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] @@ -1121,6 +1309,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64 0.21.2", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.1", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls 0.24.1", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1137,60 +1382,87 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] -name = "rustversion" -version = "1.0.12" +name = "rustls" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] [[package]] -name = "ryu" -version = "1.0.13" +name = "rustls" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] [[package]] -name = "schannel" -version = "0.1.21" +name = "rustls-pemfile" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "windows-sys 0.42.0", + "base64 0.21.2", ] [[package]] -name = "security-framework" -version = "2.9.1" +name = "rustls-webpki" +version = "0.100.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", + "ring", + "untrusted", ] [[package]] -name = "security-framework-sys" -version = "2.9.0" +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "ryu" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "core-foundation-sys", - "libc", + "ring", + "untrusted", ] [[package]] @@ -1201,18 +1473,28 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", @@ -1252,6 +1534,49 @@ dependencies = [ ] [[package]] +name = "serenity" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fd5e7b5858ad96e99d440138f34f5b98e1b959ebcd3a1036203b30e78eb788" +dependencies = [ + "async-trait", + "async-tungstenite", + "base64 0.13.1", + "bitflags", + "bytes", + "cfg-if", + "chrono", + "dashmap", + "flate2", + "futures", + "mime", + "mime_guess", + "parking_lot", + "percent-encoding", + "reqwest", + "rustversion", + "serde", + "serde-value", + "serde_json", + "time", + "tokio", + "tracing", + "typemap_rev", + "url", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] name = "sha1" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1281,6 +1606,12 @@ dependencies = [ ] [[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] name = "socket2" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1291,6 +1622,12 @@ dependencies = [ ] [[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] name = "strip-ansi-escapes" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1300,6 +1637,34 @@ dependencies = [ ] [[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1328,19 +1693,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] -name = "tempfile" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.45.0", -] - -[[package]] name = "thiserror" version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1361,6 +1713,33 @@ dependencies = [ ] [[package]] +name = "time" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + +[[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1386,11 +1765,12 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1405,12 +1785,23 @@ dependencies = [ ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.8", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "native-tls", + "rustls 0.21.1", "tokio", ] @@ -1434,7 +1825,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.18.0", ] [[package]] @@ -1488,10 +1879,22 @@ dependencies = [ "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] [[package]] +name = "tracing-attributes" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] name = "tracing-core" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1508,6 +1911,27 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +dependencies = [ + "base64 0.13.1", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "rustls 0.20.8", + "sha-1", + "thiserror", + "url", + "utf-8", + "webpki", +] + +[[package]] +name = "tungstenite" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788" @@ -1526,12 +1950,27 @@ dependencies = [ ] [[package]] +name = "typemap_rev" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5b74f0a24b5454580a79abb6994393b09adf0ab8070f15827cb666255de155" + +[[package]] name = "typenum" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] name = "unicode-bidi" version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1553,14 +1992,21 @@ dependencies = [ ] [[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -1582,12 +2028,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e" [[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1703,6 +2143,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] +name = "wasm-streams" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] name = "web-sys" version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1713,15 +2166,22 @@ dependencies = [ ] [[package]] -name = "webhook" -version = "2.1.2" +name = "webpki" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d801ea0225da29d32c85b21d0cb12ed628783f5fa1fbe226e586a3ef6ca96f" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "hyper", - "hyper-tls", - "serde", - "serde_json", + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", ] [[package]] @@ -1747,27 +2207,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.42.2", + "windows-targets", ] [[package]] @@ -1776,22 +2221,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] @@ -1800,95 +2230,62 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" +name = "winreg" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] @@ -23,11 +23,29 @@ tokio = { version = "1.28.2", features = [ "sync", "rt-multi-thread", "process", + "parking_lot", ] } -webhook = "2.1.2" tokio-stream = "0.1.14" futures-util = "0.3.28" strip-ansi-escapes = "0.1.1" +serenity = { version = "0.11.5", features = [ + "builder", + "client", + # "framework", + "utils", + "rustls_backend", + "gateway", + # "standard_framework", +], default-features = false } +poise = "0.5.5" +anyhow = "1.0.71" +strum = { version = "0.24.1", features = [ + "strum_macros", + "derive", + "std", +], default-features = false } +regex = { version = "1.8.4", features = ["std"], default-features = false } +minify-js = "0.4.3" [profile.release] lto = true diff --git a/src/bot.rs b/src/bot.rs new file mode 100644 index 0000000..e7de0f4 --- /dev/null +++ b/src/bot.rs @@ -0,0 +1,281 @@ +use crate::webhook::Webhook; +use anyhow::Result; +use futures_util::StreamExt; +use minify_js::TopLevelMode; +use regex::Regex; +use serenity::http::Http; +use serenity::prelude::*; +use std::fs::read_to_string; +use std::sync::{Arc, Mutex, OnceLock}; +use strum::{AsRefStr, EnumString, EnumVariantNames, VariantNames}; +use tokio::sync::broadcast; +use tokio::sync::OnceCell as TokLock; +pub struct Data { + stdin: broadcast::Sender<String>, +} + +static SKIPPING: OnceLock<(Arc<Mutex<u8>>, broadcast::Sender<String>)> = OnceLock::new(); + +pub struct Bot; +impl Bot { + pub async fn new(stdout: broadcast::Receiver<String>, stdin: broadcast::Sender<String>) { + let tok = std::env::var("TOKEN").unwrap_or(read_to_string("token").expect("wher token")); + let f: poise::FrameworkBuilder<Data, anyhow::Error> = poise::Framework::builder() + .options(poise::FrameworkOptions { + commands: vec![raw(), say(), ban(), js(), maps(), start(), end(), help()], + prefix_options: poise::PrefixFrameworkOptions { + prefix: Some(">".to_string()), + ..Default::default() + }, + ..Default::default() + }) + .token(&tok) + .intents(GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT) + .setup(|ctx, _ready, framework| { + Box::pin(async move { + poise::builtins::register_globally(ctx, &framework.options().commands).await?; + println!("registered"); + Ok(Data { stdin }) + }) + }); + + tokio::spawn(async move { + let http = Http::new(""); + let mut wh = Webhook::new(&http, &std::env::var("WEBHOOK").expect("no webhook!")).await; + SKIPPING.get_or_init(|| (wh.skip.clone(), wh.skipped.clone())); + wh.link(stdout).await; + }); + tokio::spawn(async move { + f.run().await.unwrap(); + }); + } +} + +type Context<'a> = poise::Context<'a, Data, anyhow::Error>; + +#[poise::command( + prefix_command, + required_permissions = "USE_SLASH_COMMANDS", + category = "ADMINISTRATION" +)] +/// send a raw command to the server +async fn raw( + ctx: Context<'_>, + #[description = "Command"] + #[rest] + cmd: String, +) -> Result<()> { + ctx.data().stdin.send(cmd)?; + println!("sent"); + Ok(()) +} + +macro_rules! return_next { + ($ctx:expr) => {{ + let line = get_nextblock().await; + $ctx.send(|m| m.content(line)).await?; + Ok(()) + }}; +} + +async fn get_nextblock() -> String { + let (skip_count, skip_send) = SKIPPING.get().unwrap(); + { + *skip_count.lock().unwrap() += 1; + } + skip_send + .subscribe() + .recv() + .await + .unwrap_or("._?".to_string()) +} + +#[poise::command(slash_command, category = "ADMINISTRATION")] +/// say something as the server +async fn say(ctx: Context<'_>, #[description = "Message"] message: String) -> Result<()> { + let _ = ctx.defer(); + ctx.data().stdin.send(format!("say {message}"))?; + return_next!(ctx) +} + +#[derive(EnumString, EnumVariantNames, AsRefStr)] +#[strum(serialize_all = "snake_case")] +enum BanType { + Id, + Ip, + Name, +} + +async fn autocomplete_ban<'a>( + _ctx: Context<'_>, + partial: &'a str, +) -> impl futures::Stream<Item = String> + 'a { + futures::stream::iter(BanType::VARIANTS) + .filter(move |name| futures::future::ready(name.starts_with(partial))) + .map(|name| name.to_string()) +} + +#[poise::command(slash_command, category = "ADMINISTRATION")] +/// ban a player +async fn ban( + ctx: Context<'_>, + #[autocomplete = "autocomplete_ban"] ban_type: BanType, + #[description = "Player (id/ip/name)"] player: String, +) -> Result<()> { + let _ = ctx.defer(); + ctx.data() + .stdin + .send(format!("ban {} {player}", ban_type.as_ref()))?; + return_next!(ctx) +} + +#[poise::command( + prefix_command, + required_permissions = "USE_SLASH_COMMANDS", + category = "ADMINISTRATION", + track_edits +)] +/// run arbitrary javascript +async fn js( + ctx: Context<'_>, + #[description = "Script"] + #[rest] + script: String, +) -> Result<()> { + static RE: OnceLock<Regex> = OnceLock::new(); + let _ = ctx.channel_id().start_typing(&ctx.serenity_context().http); + let re = RE.get_or_init(|| Regex::new(r#"```(js|javascript)?([^`]+)```"#).unwrap()); + let mat = re + .captures(&script) + .ok_or(anyhow::anyhow!(r#"no code found (use \`\`\`js...\`\`\`."#))?; + let script = mat.get(2).unwrap().as_str(); + let mut out = vec![]; + let script = if let Err(_) = minify_js::minify(TopLevelMode::Global, script.into(), &mut out) { + std::borrow::Cow::from(script.replace('\n', ";")) // xd + } else { + String::from_utf8_lossy(&out) + }; + ctx.data().stdin.send(format!("js {script}"))?; + let line = get_nextblock().await; + ctx.send(|m| m.content(line)).await?; + Ok(()) +} + +fn strip_colors(from: &str) -> String { + let mut result = String::new(); + result.reserve(from.len()); + let mut level: u8 = 0; + for c in from.chars() { + if c == '[' { + level += 1; + } else if c == ']' { + level -= 1; + } else if level == 0 { + result.push(c); + } + } + result +} + +static MAPS: TokLock<Vec<String>> = TokLock::const_new(); +async fn get_maps(stdin: &broadcast::Sender<String>) -> &Vec<String> { + MAPS.get_or_init(|| async move { + stdin.send(format!("listmaps")).unwrap(); + let res = get_nextblock().await; + let mut vec = vec![]; + for line in res.lines() { + if let Some((_, name)) = line.split_once(':') { + vec.push(strip_colors(name)); + } + } + vec + }) + .await +} + +#[poise::command(slash_command, required_permissions = "USE_SLASH_COMMANDS")] +/// lists the maps. +pub async fn maps(ctx: Context<'_>) -> Result<()> { + let _ = ctx.defer(); + let maps = get_maps(&ctx.data().stdin).await; + poise::send_reply(ctx, |m| { + m.embed(|e| { + for (k, v) in maps.iter().enumerate() { + e.field((k + 1).to_string(), v, true); + } + e.description("map list.") + }) + }) + .await?; + Ok(()) +} + +async fn autocomplete_map<'a>( + ctx: Context<'a>, + partial: &'a str, +) -> impl futures::Stream<Item = String> + 'a { + futures::stream::iter(get_maps(&ctx.data().stdin).await) + .filter(move |name| futures::future::ready(name.starts_with(partial))) + .map(|name| name.to_string()) +} + +async fn mapi(map: &str, stdin: &broadcast::Sender<String>) -> usize { + get_maps(stdin).await.iter().position(|r| r == map).unwrap() +} + +#[poise::command(slash_command, required_permissions = "USE_SLASH_COMMANDS")] +/// start the game. +pub async fn start( + ctx: Context<'_>, + #[description = "the map"] + #[autocomplete = "autocomplete_map"] + map: String, +) -> Result<()> { + let _ = ctx.defer(); + ctx.data() + .stdin + .send(format!("plague {}", mapi(&map, &ctx.data().stdin).await)) + .unwrap(); + return_next!(ctx) +} + +#[poise::command(slash_command, required_permissions = "USE_SLASH_COMMANDS")] +/// end the game. +pub async fn end( + ctx: Context<'_>, + #[description = "the map to go to"] + #[autocomplete = "autocomplete_map"] + map: String, +) -> Result<()> { + let _ = ctx.defer(); + ctx.data() + .stdin + .send(format!("endplague {}", mapi(&map, &ctx.data().stdin).await)) + .unwrap(); + return_next!(ctx) +} + +#[poise::command( + prefix_command, + slash_command, + required_permissions = "USE_SLASH_COMMANDS", + track_edits +)] +/// show help and stuff +pub async fn help( + ctx: Context<'_>, + #[description = "Specific command to show help about"] + #[autocomplete = "poise::builtins::autocomplete_command"] + command: Option<String>, +) -> Result<()> { + poise::builtins::help( + ctx, + command.as_deref(), + poise::builtins::HelpConfiguration { + extra_text_at_bottom: "Mindustry server management bot", + ..Default::default() + }, + ) + .await?; + Ok(()) +} diff --git a/src/logging.rs b/src/logging.rs index 1a151f4..85354eb 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -35,7 +35,6 @@ macro_rules! define_print { ($prefix:expr) => { define_print!(fail, concat!($prefix, " ", "!!"), break); define_print!(flush, concat!($prefix, " ", "<<")); - define_print!(nooutput, concat!($prefix, " ", "!>")); define_print!(input, concat!($prefix, " ", "<")); define_print!(output, concat!($prefix, " ", ">")); }; diff --git a/src/main.rs b/src/main.rs index c738a3e..48ce3d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use std::str::FromStr; #[macro_use] mod logging; +mod bot; mod process; mod server; mod webhook; diff --git a/src/process.rs b/src/process.rs index 9a414ff..da36818 100644 --- a/src/process.rs +++ b/src/process.rs @@ -93,7 +93,6 @@ impl Process { if html_output.receiver_count() > 0 { html_output.send(ansi2html(&string)).unwrap(); } - nooutput!(); async_std::task::sleep(Duration::from_millis(500)).await; } }) diff --git a/src/server.rs b/src/server.rs index 756c984..6e0a274 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,7 +1,6 @@ +use crate::bot::Bot; +use crate::process::Process; use crate::websocket::WebSocket; -use crate::{process::Process, webhook::Webhook}; -use axum::http::StatusCode; -use axum::response::{Redirect, Response}; use axum::{ extract::{ ws::{Message, WebSocketUpgrade}, @@ -15,7 +14,6 @@ use axum::{ use futures::sink::SinkExt; use minify_html::{minify, Cfg}; use paste::paste; -use std::sync::Mutex; use std::{ net::SocketAddr, sync::{Arc, OnceLock}, @@ -86,7 +84,6 @@ impl Server { .route("/plaguess.png", png!(plaguess)) .route("/favicon.ico", png!(logo32)) .route("/connect/:id", get(connect_ws)) - .route("/hook/*k", get(connect_wh)) .with_state(state.clone()); let mut server_handle = tokio::spawn(async move { AxumServer::bind(&addr) @@ -95,6 +92,7 @@ impl Server { .unwrap() }); let mut process_handle = proc.input(stdin).with_state(&state).link(); + Bot::new(state.stdout_plain.subscribe(), state.stdin.clone()).await; tokio::select! { _ = (&mut server_handle) => process_handle.abort(), _ = (&mut process_handle) => server_handle.abort(), @@ -136,23 +134,3 @@ async fn connect_ws( WebSocket::new(socket, state).await.wait().await; }) } - -async fn connect_wh(StateW(state): StateW<Arc<State>>, Path(params): Path<String>) -> Response { - static WEBHOOK: Mutex<Option<Webhook>> = Mutex::new(None); //one slot - let (id, url) = { - match params.split_once('/') { - None => return StatusCode::BAD_REQUEST.into_response(), - Some((a, b)) => (a, b), - } - }; - if !matches(id) { - return StatusCode::FORBIDDEN.into_response(); - } - if let Some(w) = WEBHOOK.lock().unwrap().as_ref() { - if w.running() { - return StatusCode::LOCKED.into_response(); - } - } - *WEBHOOK.lock().unwrap() = Some(Webhook::new(state.stdout_plain.subscribe(), url).await); - Redirect::to("/panel").into_response() -} diff --git a/src/webhook.rs b/src/webhook.rs index 275cdf9..6412a8f 100644 --- a/src/webhook.rs +++ b/src/webhook.rs @@ -1,84 +1,147 @@ -use std::{ - sync::Arc, - time::{Duration, Instant}, -}; +use poise::serenity_prelude::Webhook as RealHook; +use serenity::{builder::ExecuteWebhook, http::Http, json}; +use std::convert::AsRef; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; +use tokio::sync::broadcast::{self, error::TryRecvError}; -use tokio::{ - sync::broadcast::{self, error::TryRecvError}, - task::JoinHandle, -}; -use webhook::{client::WebhookClient, models::Message}; - -macro_rules! send { - ($client:ident, $block:expr) => {{ - let client = $client.clone(); - let mut m = Message::new(); - let mut bloc: Box<dyn FnMut(&mut Message) -> &mut Message> = Box::new($block); - bloc(&mut m); - m.allow_mentions(None, None, None, false); - tokio::spawn(async move { - client.send_message(&m).await.unwrap(); - }); - // handle goes out of scope, detatched - }}; +pub struct Webhook<'a> { + pub skipped: broadcast::Sender<String>, + pub skip: Arc<Mutex<u8>>, + inner: RealHook, + http: &'a Http, } -pub struct Webhook(JoinHandle<()>); -impl Webhook { - pub async fn new(mut stdout: broadcast::Receiver<String>, url: &str) -> Self { - let client = Arc::new(WebhookClient::new(url)); - Self(tokio::spawn(async move { - define_print!("webhook"); - let mut last: Option<Instant> = None; - let mut feed: Vec<String> = vec![]; - loop { - let out = stdout.try_recv(); - let now = Instant::now(); - match out { - Err(e) => match e { - TryRecvError::Closed => fail!("closed"), - TryRecvError::Lagged(_) => continue, - TryRecvError::Empty => { - if let Some(earlier) = last { - let since = now.duration_since(earlier).as_secs(); - if since > 2 || feed.len() > 15 { - last.take(); - flush::<MindustryStyle>(feed, &client).await; - feed = vec![]; - flush!(); - } +impl<'a> Webhook<'a> { + pub async fn new(http: &'a impl AsRef<Http>, url: &str) -> Webhook<'a> { + Self { + inner: RealHook::from_url(http, url).await.unwrap(), + http: http.as_ref(), + skip: Arc::new(Mutex::new(0)), + skipped: broadcast::channel(16).0, + } + } + + async fn send<F>(&self, block: F) + where + for<'b> F: FnOnce(&'b mut ExecuteWebhook<'a>) -> &'b mut ExecuteWebhook<'a>, + { + let mut execute_webhook = ExecuteWebhook::default(); + block(&mut execute_webhook); + + let map = json::hashmap_to_json_map(execute_webhook.0); + if let Err(e) = self + .http + .as_ref() + .execute_webhook( + self.inner.id.0, + self.inner.token.as_ref().unwrap(), + false, + &map, + ) + .await + { + println!("sending {map:#?} got error {e}."); + }; + } + + async fn send_message(&self, username: &str, content: &str) { + self.send(|m| m.username(username).content(content)).await; + } + + pub async fn link(&mut self, mut stdout: broadcast::Receiver<String>) { + define_print!("webhook"); + let mut last: Option<Instant> = None; + let mut feed: Vec<String> = vec![]; + loop { + let out = stdout.try_recv(); + let now = Instant::now(); + match out { + Err(e) => match e { + TryRecvError::Closed => fail!("closed"), + TryRecvError::Lagged(_) => continue, + TryRecvError::Empty => { + if let Some(earlier) = last { + let since = now.duration_since(earlier).as_secs(); + if since > 1 || feed.len() > 15 { + last.take(); + self.flush::<MindustryStyle>(feed).await; + feed = vec![]; + flush!(); } - async_std::task::sleep(Duration::from_millis(20)).await; - continue; - } - }, - Ok(m) => { - for line in m.lines() { - feed.push(line.to_string()); - input!("{line}"); } - last = Some(now); + async_std::task::sleep(Duration::from_millis(20)).await; + continue; + } + }, + Ok(m) => { + let mut lock = self.skip.lock().unwrap(); + if *lock > 0 { + *lock -= 1; + input!("{m} < skipped"); + self.skipped.send(m).unwrap(); + continue; } + drop(lock); + for line in m.lines() { + let line = line.to_string(); + input!("{line}"); + feed.push(line); + } + last = Some(now); } - async_std::task::sleep(Duration::from_millis(20)).await; } - })) + async_std::task::sleep(Duration::from_millis(20)).await; + } } - pub fn running(&self) -> bool { - !self.0.is_finished() + pub async fn flush<Style: OutputStyle>(&self, feed: Vec<String>) { + let mut current: Option<String> = None; + let mut message: Option<String> = None; + let mut unnamed: Option<String> = None; + + // this code is very game dependent + for line in feed.into_iter() { + let line: String = Style::fix(line); + if let Some((name, msg)) = Style::split(&line) { + if let Some(n) = current.as_ref() { + if n == &name { + message.madd_panic(&msg); + continue; + } else { + let message = message.take().unwrap(); + self.send_message(n, &message).await; + current.take(); + } + } + current = Some(name.to_owned()); + message = Some(msg.to_owned()); + // interrupt + if let Some(msg) = unnamed.take() { + self.send_message("server", &msg).await; + } + continue; + } + unnamed.madd(line); + } + // finish + if let Some(n) = current.as_ref() { + let message = message.take().unwrap(); + self.send_message(n, &message).await; + } + if let Some(msg) = unnamed.as_ref() { + self.send_message("server", msg).await; + } } } /// functions ordered by call order pub trait OutputStyle { /// first step - fn fix(raw_line: String) -> String; - /// ignore completely? - fn ignore(line: &str) -> bool; - /// is there no user - fn unnamed(line: &str) -> bool; - /// get the user and the content + fn fix(raw_line: String) -> String { + raw_line + } + /// get the user and the content (none for no user) fn split(line: &str) -> Option<(String, String)>; } @@ -92,92 +155,34 @@ macro_rules! s { } pub struct MindustryStyle; impl OutputStyle for MindustryStyle { - fn fix(raw_line: String) -> String { - raw_line.split(' ').skip(3).collect::<Vec<&str>>().join(" ") - } - fn ignore(line: &str) -> bool { - line.trim().is_empty() - || line.contains("requested trace info") - || s!(line, Server) - || s!(line, Connected) - || s!(line, PLAGUE) - || s!(line, "1 mods loaded") - } - - fn unnamed(line: &str) -> bool { - s!(line, [' ', '\t']) - } - fn split(line: &str) -> Option<(String, String)> { - if let Some(n) = line.find(':') { - if n < 12 { - if let Some((u, c)) = line.split_once(':') { - return Some(( - unify(u).trim_start_matches('<').to_owned(), - unify(c).trim_end_matches('>').to_owned(), - )); + if s!(line, [' ', '\t']) || s!(line, "at") { + return None; + } + if line.chars().filter(|x| x == &':').count() == 1 { + if let Some((u, c)) = line.split_once(':') { + let u = unify(u).trim_start_matches('<').trim().to_owned(); + let c = unify(c).trim_end_matches('>').trim().to_owned(); + if !(u.is_empty() || c.is_empty()) { + return Some((u, c)); } } } if let Some(index) = line.find("has") { if line.contains("connected") { let player = &line[..index]; - return Some((unify(player).trim().to_owned(), "joined".to_owned())); + let prefix = if line.contains("disconnected") { + "left" + } else { + "joined" + }; + return Some((unify(player).trim().to_owned(), prefix.to_owned())); } } None } } -async fn flush<Style: OutputStyle>(feed: Vec<String>, client: &Arc<WebhookClient>) { - let mut current: Option<String> = None; - let mut message: Option<String> = None; - let mut unnamed: Option<String> = None; - - // this code is very game dependent - for line in feed.into_iter() { - // [0-0-0-0 0-0-0-0] [i] ... -> ... - let line: String = Style::fix(line); - if Style::ignore(&line) { - continue; - } - if Style::unnamed(&line) { - unnamed.madd(line); - continue; - } - - if let Some((name, msg)) = Style::split(&line) { - if !(msg.is_empty() || name.is_empty()) { - if let Some(n) = current.as_ref() { - if n == &name { - message.madd_panic(&msg); - continue; - } else { - let message = message.take().unwrap(); - send!(client, |m| m.content(&message).username(n)); - current.take(); - } - } - current = Some(name.to_owned()); - message = Some(msg.to_owned()); - // interrupt - if let Some(msg) = unnamed.take() { - send!(client, |m| m.username("server").content(&msg)); - } - continue; - } - } - unnamed.madd(line); - } - // leftovers - if let Some(n) = current.as_ref() { - let message = message.take().unwrap(); - send!(client, |m| m.content(&message).username(n)); - } - if let Some(msg) = unnamed.as_ref() { - send!(client, |m| m.username("server").content(msg)); - } -} /// latin > extended a > kill fn unify(s: &str) -> String { s.chars() @@ -205,3 +210,32 @@ impl Madd for Option<String> { } } } + +#[test] +fn style() { + macro_rules! test_line { + ($line:expr) => { + let line = $line.to_string(); // no fixing done! + let got = MindustryStyle::split(&line); + assert!(got == None, "got {got:?}, expected None"); + }; + ($line:expr, $name: expr, $content: expr) => { + let line = $line.to_string(); + let got = MindustryStyle::split(&line); + assert!( + got == Some(($name.into(), $content.into())), + "got {got:?}, expected ({}, {})", + $name, + $content + ); + }; + } + //unnamed + test_line!("undefined"); + test_line!("Lost command socket connection: localhost/127.0.0.1:6859"); + //named + test_line!("abc: hi", "abc", "hi"); + test_line!("<a: /help>", "a", "/help"); + test_line!("a has connected. [abc==]", "a", "joined"); + test_line!("a has disconnected. [abc==] (closed)", "a", "left"); +} |