diff --git a/.dockerignore b/.dockerignore index c036bff..a79056e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,9 @@ .vscode target -.env .gitignore docker-compose.yml Dockerfile renovate.json run.sh + +stuff-to-change.log diff --git a/.gitignore b/.gitignore index c5dd462..eb5a316 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ target -.env diff --git a/Cargo.lock b/Cargo.lock index 548a5d0..5613728 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,30 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aformat" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f387c59d52324934bdd3586fe904051338ce4583a9bb921982a3dbb060a26e6f" +dependencies = [ + "aformat-macros", + "to-arraystring", + "typenum", + "typenum_mappings", +] + +[[package]] +name = "aformat-macros" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254adeba6d67e7e6706f01ffdf1787cdad41e361be5b7c1e3265bba54dca7d8f" +dependencies = [ + "bytestring", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -88,48 +112,12 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bb8" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8" -dependencies = [ - "async-trait", - "futures-util", - "parking_lot", - "tokio", -] - -[[package]] -name = "bb8-postgres" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ac82c42eb30889b5c4ee4763a24b8c566518171ebea648cd7e3bc532c60680" -dependencies = [ - "async-trait", - "bb8", - "tokio", - "tokio-postgres", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" @@ -145,18 +133,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bool_to_bitflags" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c039d9bc676b768f6d59556e99f95f5e47c811b672f8b2b2b606eb28527a2f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.72", + "to-arraystring", +] + [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" -[[package]] -name = "bytecount" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" - [[package]] name = "byteorder" version = "1.5.0" @@ -170,34 +165,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] -name = "camino" -version = "1.1.7" +name = "bytestring" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", + "bytes", ] [[package]] @@ -269,15 +242,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -350,11 +314,12 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", + "crossbeam-utils", "hashbrown", "lock_api", "once_cell", @@ -397,7 +362,6 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", - "subtle", ] [[package]] @@ -421,7 +385,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn 2.0.72", @@ -444,20 +408,15 @@ dependencies = [ ] [[package]] -name = "error-chain" -version = "0.12.4" +name = "extract_map" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +checksum = "abf7509ab567289c5422ef33dd4982673b8a32d373c2abb6e7fce8ef8b2dc968" dependencies = [ - "version_check", + "gat-lending-iterator", + "serde", ] -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - [[package]] name = "fastrand" version = "2.1.0" @@ -590,6 +549,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gat-lending-iterator" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9af1174056216fca07a0c9585aed69d46aefb1107721ea30c379660329443c7" + [[package]] name = "generic-array" version = "0.14.7" @@ -617,31 +582,6 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.5" @@ -653,7 +593,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http", "indexmap", "slab", "tokio", @@ -673,21 +613,18 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - [[package]] name = "hostname" version = "0.3.1" @@ -699,17 +636,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -721,17 +647,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -739,7 +654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -750,8 +665,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -761,36 +676,6 @@ version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.4.1" @@ -800,9 +685,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "itoa", "pin-project-lite", @@ -811,20 +696,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.30", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.2" @@ -832,14 +703,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.4.1", + "http", + "hyper", "hyper-util", "rustls 0.23.12", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", "tower-service", + "webpki-roots", ] [[package]] @@ -850,7 +722,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -867,9 +739,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -1019,16 +891,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - [[package]] name = "memchr" version = "2.7.4" @@ -1051,21 +913,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "mini-moka" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c325dfab65f261f386debee8b0969da215b3fa0037e74c8a1234db7ba986d803" -dependencies = [ - "crossbeam-channel", - "crossbeam-utils", - "dashmap", - "skeptic", - "smallvec", - "tagptr", - "triomphe", -] - [[package]] name = "miniz_oxide" version = "0.7.4" @@ -1104,6 +951,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" +dependencies = [ + "serde", +] + [[package]] name = "ntapi" version = "0.4.1" @@ -1149,7 +1005,7 @@ version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -1175,6 +1031,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.3.2+3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.103" @@ -1183,6 +1048,7 @@ checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -1205,7 +1071,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -1216,24 +1082,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - [[package]] name = "pin-project" version = "1.1.5" @@ -1275,25 +1123,25 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "poise" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1819d5a45e3590ef33754abce46432570c54a120798bdbf893112b4211fa09a6" +source = "git+https://github.com/serenity-rs/poise?branch=serenity-next#e7c92b7a9b7dabb37fb879fabd65fa18bd00aad8" dependencies = [ "async-trait", "derivative", "futures-util", + "indexmap", "parking_lot", "poise_macros", "regex", "serenity", "tokio", "tracing", + "trim-in-place", ] [[package]] name = "poise_macros" version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa2c123c961e78315cd3deac7663177f12be4460f5440dbf62a7ed37b1effea" +source = "git+https://github.com/serenity-rs/poise?branch=serenity-next#e7c92b7a9b7dabb37fb879fabd65fa18bd00aad8" dependencies = [ "darling", "proc-macro2", @@ -1301,35 +1149,6 @@ dependencies = [ "syn 2.0.72", ] -[[package]] -name = "postgres-protocol" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23" -dependencies = [ - "base64 0.22.1", - "byteorder", - "bytes", - "fallible-iterator", - "hmac", - "md-5", - "memchr", - "rand", - "sha2", - "stringprep", -] - -[[package]] -name = "postgres-types" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f" -dependencies = [ - "bytes", - "fallible-iterator", - "postgres-protocol", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1354,23 +1173,60 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags 2.6.0", - "memchr", - "unicase", -] - [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.12", + "socket2", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand", + "ring", + "rustc-hash", + "rustls 0.23.12", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -1430,22 +1286,13 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -1479,37 +1326,44 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ - "base64 0.21.7", + "base64", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "hyper-rustls 0.24.2", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", "mime", "mime_guess", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.12", - "rustls-pemfile 1.0.4", + "quinn", + "rustls 0.23.12", + "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 0.1.2", - "system-configuration 0.5.1", + "sync_wrapper", + "system-configuration", "tokio", - "tokio-rustls 0.24.1", + "tokio-native-tls", + "tokio-rustls 0.26.0", "tokio-util", "tower-service", "url", @@ -1517,50 +1371,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.25.4", - "winreg", -] - -[[package]] -name = "reqwest" -version = "0.12.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.4.1", - "hyper-rustls 0.27.2", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.1.3", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 1.0.1", - "system-configuration 0.6.0", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "webpki-roots", "windows-registry", ] @@ -1593,17 +1404,48 @@ dependencies = [ name = "rustbot" version = "0.1.0" dependencies = [ - "bb8", - "bb8-postgres", - "cargo_toml", - "once_cell", "poise", - "regex", + "rand", + "reqwest", + "rustbot_events", + "rustbot_lib", + "rustbot_tokens", + "serde", "sysinfo", + "time", + "tokio", + "uptime_lib", +] + +[[package]] +name = "rustbot_events" +version = "0.1.0" +dependencies = [ + "poise", + "rustbot_lib", +] + +[[package]] +name = "rustbot_jobs" +version = "0.1.0" +dependencies = [ + "tokio", +] + +[[package]] +name = "rustbot_lib" +version = "0.1.19" +dependencies = [ + "cargo_toml", + "poise", +] + +[[package]] +name = "rustbot_tokens" +version = "0.1.0" +dependencies = [ "tokenservice-client", "tokio", - "tokio-postgres", - "uptime_lib", ] [[package]] @@ -1612,31 +1454,25 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustix" version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.22.4" @@ -1646,7 +1482,7 @@ dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki", "subtle", "zeroize", ] @@ -1658,28 +1494,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "once_cell", + "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki", "subtle", "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - [[package]] name = "rustls-pemfile" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ - "base64 0.22.1", + "base64", "rustls-pki-types", ] @@ -1689,16 +1517,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.102.6" @@ -1710,21 +1528,18 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "schannel" version = "0.1.23" @@ -1740,16 +1555,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "secrecy" version = "0.8.0" @@ -1766,7 +1571,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -1783,20 +1588,11 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] - [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -1812,9 +1608,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -1823,9 +1619,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -1857,34 +1653,40 @@ dependencies = [ [[package]] name = "serenity" version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "880a04106592d0a8f5bdacb1d935889bfbccb4a14f7074984d9cd857235d34ac" +source = "git+https://github.com/serenity-rs/serenity?branch=next#391b234fca970b312727278212a79978197124d2" dependencies = [ + "aformat", "arrayvec", "async-trait", - "base64 0.22.1", - "bitflags 2.6.0", + "base64", + "bitflags", + "bool_to_bitflags", "bytes", "chrono", "dashmap", + "extract_map", "flate2", "futures", "fxhash", "mime_guess", + "nonmax", "parking_lot", "percent-encoding", - "reqwest 0.11.27", + "reqwest", "secrecy", "serde", "serde_cow", "serde_json", + "small-fixed-array", + "strum", "time", + "to-arraystring", "tokio", "tokio-tungstenite", "tracing", - "typemap_rev", "typesize", "url", + "zeroize", ] [[package]] @@ -1898,47 +1700,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "skeptic" -version = "0.13.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.9" @@ -1948,6 +1709,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "small-fixed-array" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de1265a0b6b240b940caeea26abcffd4382248e479b6d475e7ce8fb88884e504" +dependencies = [ + "serde", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -1970,23 +1740,34 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "stringprep" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", - "unicode-properties", -] - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.72", +] + [[package]] name = "subtle" version = "2.6.1" @@ -2015,12 +1796,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.1" @@ -2044,36 +1819,15 @@ dependencies = [ "windows", ] -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys 0.5.0", -] - [[package]] name = "system-configuration" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" dependencies = [ - "bitflags 2.6.0", + "bitflags", "core-foundation", - "system-configuration-sys 0.6.0", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", + "system-configuration-sys", ] [[package]] @@ -2086,12 +1840,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tagptr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" - [[package]] name = "tempfile" version = "3.12.0" @@ -2171,13 +1919,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "to-arraystring" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fafaa22f176928fb926345e78eb2ec404603c878b274e6ab1f76de1f6dde1b1" +dependencies = [ + "arrayvec", + "itoa", + "ryu", +] + [[package]] name = "tokenservice-client" version = "0.4.1" source = "sparse+https://git.toast-server.net/api/packages/toast/cargo/" checksum = "cf11991da505b67c1a8201aa2d4746eefe338d34ce8d985c93474672d900c5cd" dependencies = [ - "reqwest 0.12.7", + "reqwest", "serde", "serde_json", "tokio", @@ -2194,9 +1953,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.52.0", @@ -2223,42 +1980,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-postgres" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures-channel", - "futures-util", - "log", - "parking_lot", - "percent-encoding", - "phf", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "rand", - "socket2", - "tokio", - "tokio-util", - "whoami", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.25.0" @@ -2294,7 +2015,7 @@ dependencies = [ "tokio", "tokio-rustls 0.25.0", "tungstenite", - "webpki-roots 0.26.3", + "webpki-roots", ] [[package]] @@ -2404,10 +2125,10 @@ dependencies = [ ] [[package]] -name = "triomphe" -version = "0.1.13" +name = "trim-in-place" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" +checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" [[package]] name = "trust-dns-proto" @@ -2470,7 +2191,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http", "httparse", "log", "rand", @@ -2482,18 +2203,24 @@ dependencies = [ "utf-8", ] -[[package]] -name = "typemap_rev" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" - [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "typenum_mappings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cbc2d8952dd1e08b0164a5b51549e80631ac9da4107669d26c8ea89cb0b5545" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", + "to-arraystring", +] + [[package]] name = "typesize" version = "0.1.7" @@ -2501,9 +2228,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb704842c709bc76f63e99e704cb208beeccca2abbabd0d9aec02e48ca1cee0f" dependencies = [ "chrono", - "dashmap", - "hashbrown", - "mini-moka", + "extract_map", + "nonmax", "parking_lot", "secrecy", "serde_json", @@ -2553,12 +2279,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-properties" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" - [[package]] name = "untrusted" version = "0.9.0" @@ -2606,16 +2326,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -2631,12 +2341,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" - [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -2726,12 +2430,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "webpki-roots" version = "0.26.3" @@ -2741,17 +2439,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "whoami" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" -dependencies = [ - "redox_syscall 0.4.1", - "wasite", - "web-sys", -] - [[package]] name = "widestring" version = "1.1.0" @@ -2774,15 +2461,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml old mode 100644 new mode 100755 index 59894e5..efc5d08 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,21 +3,41 @@ name = "rustbot" version = "0.1.0" edition = "2021" -[dependencies] -bb8 = "0.8.5" -bb8-postgres = "0.8.1" -cargo_toml = "0.20.4" -once_cell = "1.19.0" +[workspace] +members = [ + "events", + "jobs", + "library", + "tsclient" +] + +[workspace.dependencies] +cargo_toml = "0.20.5" poise = "0.6.1" -regex = "1.10.6" +regex = "1.11.0" +serde = "1.0.210" +tokio = { version = "1.40.0", features = ["macros", "rt-multi-thread"] } +reqwest = { version = "0.12.8", features = ["native-tls-vendored"] } + +[dependencies] +rustbot_events = { path = "events" } +rustbot_lib = { path = "library" } +rustbot_tokens = { path = "tsclient" } +poise = { workspace = true } +rand = "0.8.5" +reqwest = { workspace = true } +serde = { workspace = true } sysinfo = "0.32.0" -tokenservice-client = { version = "0.4.0", registry = "gitea" } -tokio = { version = "1.39.2", features = ["macros", "signal", "rt-multi-thread"] } -tokio-postgres = "0.7.11" +time = "0.3.36" +tokio = { workspace = true } uptime_lib = "0.3.1" +[patch.crates-io] +poise = { git = "https://github.com/serenity-rs/poise", branch = "serenity-next" } + [features] -production = [] +production = ["rustbot_lib/production", "rustbot_events/production"] +not_ready = ["rustbot_lib/not_ready"] [[bin]] name = "rustbot" diff --git a/Dockerfile b/Dockerfile index dedbf7f..2633c5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,10 @@ -FROM rust:1.82-alpine3.20@sha256:466dc9924d265455aa73e72fd9cdac9db69ce6a988e6f0e6baf852db3485d97d AS chef -ENV RUSTFLAGS="-C target-feature=-crt-static" -ARG GIT_HASH -ENV GIT_COMMIT_HASH=${GIT_HASH} -RUN apk add --no-cache openssl-dev musl-dev -RUN cargo install cargo-chef +FROM scratch AS base WORKDIR /builder - -FROM chef AS planner COPY . . -RUN cargo chef prepare - -FROM chef AS builder -COPY --from=planner /builder/recipe.json recipe.json -RUN cargo chef cook --release -COPY . . -RUN cargo build --offline -rF production FROM alpine:3.20@sha256:e72ad0747b9dc266fca31fb004580d316b6ae5b0fdbbb65f17bbe371a5b24cff LABEL org.opencontainers.image.source="https://git.toast-server.net/toast/Rustbot" RUN apk add --no-cache libgcc WORKDIR /rustbot -COPY --from=builder /builder/target/release/rustbot . -CMD ./rustbot +COPY --from=base /builder/target/x86_64-unknown-linux-musl/release/rustbot . +CMD [ "./rustbot" ] diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..006ab06 --- /dev/null +++ b/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +export GIT_COMMIT_HASH=$(git rev-parse HEAD) && \ +cargo zigbuild --target x86_64-unknown-linux-musl --locked -rF production && \ +docker compose build bot diff --git a/docker-compose.yml b/docker-compose.yml index 92a3c5a..388d0c6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,23 +1,6 @@ -version: '3.8' services: bot: container_name: rustbot #image: 'git.toast-server.net/toast/rustbot:main' build: . - env_file: - - .env restart: unless-stopped - depends_on: - - db - db: - container_name: rustbot-database - image: postgres:17.0-alpine3.20@sha256:14195b0729fce792f47ae3c3704d6fd04305826d57af3b01d5b4d004667df174 - restart: unless-stopped - ports: - - 37931:5432/tcp - volumes: - - /var/lib/docker/volumes/rustbot-database:/var/lib/postgresql/data:rw - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} diff --git a/events/Cargo.toml b/events/Cargo.toml new file mode 100755 index 0000000..68beb73 --- /dev/null +++ b/events/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rustbot_events" +version = "0.1.0" +edition = "2021" + +[dependencies] +rustbot_lib = { path = "../library" } +poise = { workspace = true } + +[features] +production = ["rustbot_lib/production"] +not_ready = ["rustbot_lib/not_ready"] diff --git a/events/src/events.rs b/events/src/events.rs new file mode 100755 index 0000000..3a8e35a --- /dev/null +++ b/events/src/events.rs @@ -0,0 +1,33 @@ +mod ready; +mod shards; + +use rustbot_lib::{ + RustbotError, + RustbotData +}; +use poise::{ + FrameworkContext, + serenity_prelude::FullEvent +}; + +pub const RUSTBOT_EVENT: &str = "RustbotEvent"; + +struct EventProcessor<'a> { + framework: FrameworkContext<'a, RustbotData, RustbotError> +} + +pub async fn processor( + framework: FrameworkContext<'_, RustbotData, RustbotError>, + event: &FullEvent +) -> Result<(), RustbotError> { + let processor = EventProcessor { framework }; + + match event { + FullEvent::Ready { data_about_bot } => processor.on_ready(data_about_bot).await?, + FullEvent::ShardsReady { total_shards } => processor.on_shards_ready(total_shards).await?, + FullEvent::ShardStageUpdate { event } => processor.on_shards_stageupdate(event).await?, + _ => {} + } + + Ok(()) +} diff --git a/events/src/events/ready.rs b/events/src/events/ready.rs new file mode 100755 index 0000000..2b76801 --- /dev/null +++ b/events/src/events/ready.rs @@ -0,0 +1,67 @@ +use crate::PoiseFwCtx; +use super::{ + EventProcessor, + RUSTBOT_EVENT +}; + +use rustbot_lib::{ + RustbotError, + utils::{ + BOT_VERSION, + GIT_COMMIT_HASH, + GIT_COMMIT_BRANCH + }, + config::BINARY_PROPERTIES +}; +use std::sync::atomic::{ + AtomicBool, + Ordering +}; +use poise::serenity_prelude::{ + Ready, + ChannelId, + CreateMessage, + CreateEmbed, + CreateEmbedAuthor +}; + +static READY_ONCE: AtomicBool = AtomicBool::new(false); + +async fn ready_once( + ready: &Ready, + framework: PoiseFwCtx<'_> +) -> Result<(), RustbotError> { + #[cfg(not(feature = "production"))] + { + println!("{RUSTBOT_EVENT}[Ready:Notice:S{}]: Detected a non-production environment!", framework.serenity_context.shard_id); + let gateway = framework.serenity_context.http.get_bot_gateway().await?; + let session = gateway.session_start_limit; + println!("{RUSTBOT_EVENT}[Ready:Notice:S{}]: Session limit: {}/{}", framework.serenity_context.shard_id, session.remaining, session.total); + } + + println!("{RUSTBOT_EVENT}[Ready:S{}]: Build version: {} ({}:{})", framework.serenity_context.shard_id, *BOT_VERSION, GIT_COMMIT_HASH, GIT_COMMIT_BRANCH); + println!("{RUSTBOT_EVENT}[Ready:S{}]: Connected to API as {}", framework.serenity_context.shard_id, ready.user.name); + + let message = CreateMessage::new(); + let ready_embed = CreateEmbed::new() + .color(BINARY_PROPERTIES.embed_color) + .thumbnail(ready.user.avatar_url().unwrap_or_default()) + .author(CreateEmbedAuthor::new(format!("{} is ready!", ready.user.name))); + + ChannelId::new(BINARY_PROPERTIES.rustbot_logs).send_message(&framework.serenity_context.http, message.add_embed(ready_embed)).await?; + + Ok(()) +} + +impl EventProcessor<'_> { + pub async fn on_ready( + &self, + data_about_bot: &Ready + ) -> Result<(), RustbotError> { + if !READY_ONCE.swap(true, Ordering::Relaxed) { + ready_once(data_about_bot, self.framework).await.expect("Failed to call ready_once method"); + } + + Ok(()) + } +} diff --git a/events/src/events/shards.rs b/events/src/events/shards.rs new file mode 100755 index 0000000..e810b63 --- /dev/null +++ b/events/src/events/shards.rs @@ -0,0 +1,29 @@ +use super::{ + EventProcessor, + RUSTBOT_EVENT +}; + +use std::num::NonZero; +use rustbot_lib::RustbotError; +use poise::serenity_prelude::ShardStageUpdateEvent; + +impl EventProcessor<'_> { + pub async fn on_shards_ready( + &self, + total_shards: &NonZero + ) -> Result<(), RustbotError> { + let shards = if *total_shards == NonZero::new(1).unwrap() { "shard is" } else { "shards are" }; + println!("{RUSTBOT_EVENT}[ShardsReady]: {total_shards} {shards} ready!"); + + Ok(()) + } + + pub async fn on_shards_stageupdate( + &self, + event: &ShardStageUpdateEvent + ) -> Result<(), RustbotError> { + println!("{RUSTBOT_EVENT}[ShardStageUpdate:S{}]: {event:#?}", event.shard_id); + + Ok(()) + } +} diff --git a/events/src/lib.rs b/events/src/lib.rs new file mode 100755 index 0000000..6635563 --- /dev/null +++ b/events/src/lib.rs @@ -0,0 +1,45 @@ +pub mod events; + +// use serde_json::json; +use rustbot_lib::{ + RustbotData, + RustbotError +}; +use poise::{ + FrameworkContext, + /* serenity_prelude::{ + Context, + WebhookId + } */ +}; + +type PoiseFwCtx<'a> = FrameworkContext<'a, RustbotData, RustbotError>; + +/* async fn hook_logger( + ctx: &Context, + hook_id: WebhookId, + token: &str, + content: String +) -> Result { + let current_app = ctx.http.get_current_user().await.unwrap(); + let bot_avatar = current_app.avatar_url().unwrap(); + let bot_username = ¤t_app.name; + + if let Err(e) = ctx.http.execute_webhook( + hook_id, + None, + token, + true, + vec![], + &json!({ + "content": content, + "avatar_url": bot_avatar, + "username": bot_username + }) + ).await { + println!("{}[EventWebhook]: Failed to send webhook message: {e}", events::RUSTBOT_EVENT); + Ok(false) + } else { + Ok(true) + } +} */ diff --git a/jobs/Cargo.toml b/jobs/Cargo.toml new file mode 100755 index 0000000..abafc93 --- /dev/null +++ b/jobs/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rustbot_jobs" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { workspace = true } diff --git a/jobs/src/lib.rs b/jobs/src/lib.rs new file mode 100755 index 0000000..c92fb4a --- /dev/null +++ b/jobs/src/lib.rs @@ -0,0 +1,3 @@ +pub mod tasks; + +const RUSTBOT_SCHEDULER: &str = "RustbotScheduler"; diff --git a/jobs/src/tasks.rs b/jobs/src/tasks.rs new file mode 100755 index 0000000..c032ad6 --- /dev/null +++ b/jobs/src/tasks.rs @@ -0,0 +1,43 @@ +use crate::RUSTBOT_SCHEDULER; + +use tokio::{ + task, + time::{ + interval, + Duration + } +}; +use std::{ + sync::Arc, + future::Future +}; + +pub struct Scheduler; + +impl Scheduler { + pub fn new() -> Arc { + Arc::new(Self) + } + + pub async fn spawn_job( + &self, + interval_secs: u64, + job: Arc F + Send + Sync + 'static> + ) where + F: Future> + Send + 'static, + E: std::fmt::Debug + { + let mut interval = interval(Duration::from_secs(interval_secs)); + + loop { + interval.tick().await; + + let job_clone = job.clone(); + task::spawn(async move { + if let Err(y) = job_clone().await { + eprintln!("{RUSTBOT_SCHEDULER}[Job:Error]: {y:?}"); + } + }); + } + } +} diff --git a/library/Cargo.toml b/library/Cargo.toml new file mode 100755 index 0000000..d3a5e51 --- /dev/null +++ b/library/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rustbot_lib" +version = "0.1.19" +edition = "2021" + +[dependencies] +cargo_toml = { workspace = true } +poise = { workspace = true } + +[features] +production = ["docker"] +docker = [] +not_ready = [] diff --git a/library/build.rs b/library/build.rs new file mode 100755 index 0000000..e261431 --- /dev/null +++ b/library/build.rs @@ -0,0 +1,37 @@ +fn main() { + #[cfg(feature = "production")] + { + if let Ok(git_commit_hash) = std::env::var("GIT_COMMIT_HASH") { + println!("cargo:rustc-env=GIT_COMMIT_HASH={}", &git_commit_hash[..7]); + } else { + println!("cargo:warning=GIT_COMMIT_HASH not found, falling back to 'not_found'"); + println!("cargo:rustc-env=GIT_COMMIT_HASH=not_found"); + } + } + + { + let git_branch = std::process::Command::new("git") + .args(["rev-parse", "--abbrev-ref", "HEAD"]) + .output() + .expect("Command execution failed: git"); + + if git_branch.status.success() { + let git_branch = String::from_utf8(git_branch.stdout).expect("Invalid UTF-8 sequence").trim().to_string(); + println!("cargo:rustc-env=GIT_COMMIT_BRANCH={}", &git_branch); + } else { + println!("cargo:warning=GIT_COMMIT_BRANCH not found, falling back to 'not_found'"); + println!("cargo:rustc-env=GIT_COMMIT_BRANCH=not_found"); + } + } + + { + let hostname = std::process::Command::new("hostname") + .output() + .expect("Command execution failed: hostname"); + + if hostname.status.success() { + let hostname = String::from_utf8(hostname.stdout).expect("Invalid UTF-8 sequence").trim().to_string(); + println!("cargo:rustc-env=DOCKER_HOSTNAME={}", &hostname); + } + } +} diff --git a/library/src/config.rs b/library/src/config.rs new file mode 100755 index 0000000..1508885 --- /dev/null +++ b/library/src/config.rs @@ -0,0 +1,44 @@ +use std::sync::LazyLock; + +pub struct ConfigMeta { + pub env: String, + pub embed_color: u32, + pub rustbot_logs: u64, + pub developers: Vec +} + +#[cfg(feature = "production")] +pub static BINARY_PROPERTIES: LazyLock = LazyLock::new(ConfigMeta::new); + +#[cfg(not(feature = "production"))] +pub static BINARY_PROPERTIES: LazyLock = LazyLock::new(|| + ConfigMeta::new() + .env(String::from("dev")) + .embed_color(0xf1d63c) +); + +impl ConfigMeta { + fn new() -> Self { + Self { + env: String::from("prod"), + embed_color: 0xf1d63c, + rustbot_logs: 1276874302314254448, + developers: vec![ + 190407856527376384 // toast.ts + ] + } + } + + // Scalable functions below; + #[cfg(not(feature = "production"))] + fn env(mut self, env: String) -> Self { + self.env = env; + self + } + + #[cfg(not(feature = "production"))] + fn embed_color(mut self, color: u32) -> Self { + self.embed_color = color; + self + } +} diff --git a/library/src/data.rs b/library/src/data.rs new file mode 100755 index 0000000..2aa5a3f --- /dev/null +++ b/library/src/data.rs @@ -0,0 +1,2 @@ +#[derive(Debug)] +pub struct RustbotData {} diff --git a/library/src/lib.rs b/library/src/lib.rs new file mode 100755 index 0000000..ffb3804 --- /dev/null +++ b/library/src/lib.rs @@ -0,0 +1,7 @@ +pub mod config; +mod data; +pub use data::RustbotData; +pub mod utils; + +pub type RustbotError = Box; +pub type RustbotCtx<'a> = poise::Context<'a, RustbotData, RustbotError>; diff --git a/library/src/utils.rs b/library/src/utils.rs new file mode 100755 index 0000000..7f91900 --- /dev/null +++ b/library/src/utils.rs @@ -0,0 +1,70 @@ +use poise::serenity_prelude::UserId; +use cargo_toml::Manifest; +use std::sync::LazyLock; + +#[cfg(feature = "production")] +pub static GIT_COMMIT_HASH: &str = env!("GIT_COMMIT_HASH"); +#[cfg(not(feature = "production"))] +pub static GIT_COMMIT_HASH: &str = "devel"; +pub static GIT_COMMIT_BRANCH: &str = env!("GIT_COMMIT_BRANCH"); + +pub static BOT_VERSION: LazyLock = LazyLock::new(|| { + Manifest::from_str(include_str!("../../Cargo.toml")) + .unwrap() + .package + .unwrap() + .version + .unwrap() +}); + +pub fn format_timestamp(timestamp: i64) -> String { + format!("\n") +} + +pub fn mention_dev(ctx: super::RustbotCtx<'_>) -> Option { + let devs = super::config::BINARY_PROPERTIES.developers.clone(); + let app_owners = ctx.framework().options().owners.clone(); + + let mut mentions = Vec::new(); + + for dev in devs { + if app_owners.contains(&UserId::new(dev)) { + mentions.push(format!("<@{dev}>")); + } + } + + if mentions.is_empty() { + None + } else { + Some(mentions.join(", ")) + } +} + +pub fn get_guild_name(ctx: super::RustbotCtx<'_>) -> String { + match ctx.guild() { + Some(guild) => guild.name.clone().to_string(), + None => String::from("DM") + } +} + +pub fn format_duration(secs: u64) -> String { + let days = secs / 86400; + let hours = (secs % 86400) / 3600; + let minutes = (secs % 3600) / 60; + let seconds = secs % 60; + + let mut formatted_string = String::new(); + match (days, hours, minutes, seconds) { + (d, _, _, _) if d > 0 => formatted_string.push_str(&format!("{d}d, ")), + (_, h, _, _) if h > 0 => formatted_string.push_str(&format!("{h}h, ")), + (_, _, m, _) if m > 0 => formatted_string.push_str(&format!("{m}m, ")), + (_, _, _, s) if s > 0 => formatted_string.push_str(&format!("{s}s")), + _ => {} + } + + if formatted_string.ends_with(", ") { + formatted_string.truncate(formatted_string.len() - 2); + } + + formatted_string +} diff --git a/run.sh b/run.sh index 7646904..a02df79 100755 --- a/run.sh +++ b/run.sh @@ -1,3 +1,6 @@ #!/bin/bash +export DOCKER_HOSTNAME=$(hostname) +export $(cat .env.bot | xargs) clear && cargo run +unset DOCKER_HOSTNAME diff --git a/src/commands.rs b/src/commands.rs old mode 100644 new mode 100755 index 9e3a067..5dd6a8a --- a/src/commands.rs +++ b/src/commands.rs @@ -1,4 +1,28 @@ -pub mod midi; -pub mod ping; -pub mod sample; -pub mod uptime; +mod dev; +mod eightball; +mod ping; +mod uptime; + +pub use dev::dev; +pub use eightball::eightball; +pub use ping::ping; +pub use uptime::uptime; + +type PoiseContext<'a> = rustbot_lib::RustbotCtx<'a>; + +macro_rules! collect { + () => { + vec![ + // Developer command(s) + commands::dev(), + + // Utility commands + commands::ping(), + commands::uptime(), + + // Unsorted mess + commands::eightball(), + ] + }; +} +pub(crate) use collect; diff --git a/src/commands/dev.rs b/src/commands/dev.rs new file mode 100755 index 0000000..ec0546e --- /dev/null +++ b/src/commands/dev.rs @@ -0,0 +1,50 @@ +use crate::RustbotError; +use super::PoiseContext; + +/// Developer commands +#[poise::command( + prefix_command, + owners_only, + subcommands("deploy", "servers", "shards") +)] +pub async fn dev(_: PoiseContext<'_>) -> Result<(), RustbotError> { + Ok(()) +} + +/// Deploy commands to this guild or globally +#[poise::command(prefix_command)] +async fn deploy(ctx: PoiseContext<'_>) -> Result<(), RustbotError> { + poise::builtins::register_application_commands_buttons(ctx).await?; + Ok(()) +} + +/// View how many servers the bot is in +#[poise::command(prefix_command)] +async fn servers(ctx: PoiseContext<'_>) -> Result<(), RustbotError> { + poise::builtins::servers(ctx).await?; + Ok(()) +} + +/// View the status of available shards +#[poise::command(prefix_command)] +async fn shards(ctx: PoiseContext<'_>) -> Result<(), RustbotError> { + let shard_runners = ctx.framework().shard_manager().runners.clone(); + let runners = shard_runners.lock().await; + + let mut shard_info = Vec::new(); + for (id, runner) in runners.iter() { + shard_info.push(format!( + "**Shard {}**\n> Heartbeat: {}\n> Status: `{}`", + id, + match runner.latency { + Some(lat) => format!("`{}ms`", lat.as_millis()), + None => "Waiting for heartbeat...".to_string() + }, + runner.stage + )) + } + + ctx.reply(shard_info.join("\n\n")).await?; + + Ok(()) +} diff --git a/src/commands/eightball.rs b/src/commands/eightball.rs new file mode 100755 index 0000000..d8d9370 --- /dev/null +++ b/src/commands/eightball.rs @@ -0,0 +1,80 @@ +use crate::RustbotError; +use super::PoiseContext; + +use rustbot_lib::config::BINARY_PROPERTIES; +use poise::{ + serenity_prelude::UserId, + builtins::paginate +}; + +/// Ask the Magic 8-Ball a yes/no question and get an unpredictable answer +#[poise::command( + slash_command, + rename = "8ball" +)] +pub async fn eightball( + ctx: PoiseContext<'_>, + #[description = "Your yes/no question"] question: String +) -> Result<(), RustbotError> { + if question.to_ascii_lowercase().contains("rustbot, show list") { + if ctx.author().id == UserId::new(BINARY_PROPERTIES.developers[0]) { + let chunks: Vec = RESPONSES.chunks(10).map(|chunk| chunk.join("\n\n")).collect(); + let pages: Vec<&str> = chunks.iter().map(|s| s.as_str()).collect(); + paginate(ctx, &pages).await?; + + return Ok(()); + } else { + ctx.reply("No.").await?; + return Ok(()); + } + } + + ctx.reply(format!( + "> {}\n{}", + question, + get_random_response() + )).await?; + + Ok(()) +} + +const RESPONSES: [&str; 30] = [ + "Reply hazy. Look it up on Google.", // no + "Meh — Figure it out yourself.", // no + "I don't know, what do you think?", // no + "Yes.", // yes + "No.", // no + "It is decidedly so", // yes + "Signs point to... maybe... depends on... \ + hold on, let me get my glasses, this is getting \ + pretty tiny... depends on whether you'd be up \ + to getting to know your Magic 8-Ball a little better.", // no + "Signs point to... ~~yes~~ no.", // no + "Why do you want to know the answer? It's obviously a yes.", // yes + "Outlook not so good.", // no + "Outlook hazy.", // no + "What are you, stupid?", // no + "How the hell do you not know that?", // no + "Really? Making a decision based on what the plastic 8-Ball says? Jesus...", // no + "Try asking later...", // no + "I don't know, whip out the ouija board and try again?", // no + "The answer is yes.", // yes + "Yes, actually no. Wait, nevermind.", // no + "Maybeee...", // yes + "Definitely!", // yes + "It is decidedly so.", // yes + "My reply is no.", // no + "My sources confirms that the answer is no.\n\ + Source: :sparkles: *i made it up* :sparkles:", // no + "As I see it, yes.", // yes + "Don't count on it.", // no + "Whoa! Why do I have to answer this?", // no + "Highly unlikely.", // no + "Sure, but with extreme cautions.", // yes + "What kind of stupid question is that?? No! I'm not answering that!", // no + "Try asking this to a chicken. Probably knows it better than I do!", // no +]; + +fn get_random_response() -> &'static str { + RESPONSES[rand::random::() % RESPONSES.len()] +} diff --git a/src/commands/midi.rs b/src/commands/midi.rs deleted file mode 100644 index 57f7766..0000000 --- a/src/commands/midi.rs +++ /dev/null @@ -1,101 +0,0 @@ -use crate::{ - Error, - internals::utils::{ - mention_dev, - format_bytes - } -}; - -use regex::Regex; -use std::{ - os::unix::fs::MetadataExt, - fs::{ - write, - remove_file, - metadata - } -}; -use poise::{ - CreateReply, - serenity_prelude::CreateAttachment -}; - -/// Convert MIDI file to WAV -#[poise::command(context_menu_command = "MIDI -> WAV")] -pub async fn midi_to_wav( - ctx: poise::Context<'_, (), Error>, - #[description = "MIDI file to be converted"] message: poise::serenity_prelude::Message -) -> Result<(), Error> { - let re = Regex::new(r"(?i)\.mid$").unwrap(); - - if !message.embeds.is_empty() || message.attachments.is_empty() || !re.is_match(&message.attachments[0].filename) { - ctx.reply("That ain't a MIDI file! What are you even doing??").await?; - return Ok(()); - } - - ctx.defer().await?; - - let bytes = match message.attachments[0].download().await { - Ok(bytes) => bytes, - Err(y) => { - ctx.send(CreateReply::default() - .content(format!( - "Download failed, ask {} to check console for more information!", - mention_dev(ctx).unwrap_or_default() - )) - ) - .await.unwrap(); - - return Err(Error::from(format!("Failed to download the file: {}", y))) - } - }; - - let midi_path = &message.attachments[0].filename; - write(midi_path, bytes)?; - - let wav_path = re.replace(&midi_path, ".wav"); - - let sf2_path = "/tmp/FluidR3_GM.sf2"; - write(sf2_path, include_bytes!("../internals/assets/FluidR3_GM.sf2"))?; - - let output = std::process::Command::new("fluidsynth") - .args(&["-ni", sf2_path, midi_path, "-F", &wav_path]) - .output(); - - // Just to add an info to console to tell what the bot is doing when MIDI file is downloaded. - println!("Discord[{}:{}]: Processing MIDI file: \"{}\"", ctx.guild().unwrap().name, ctx.command().qualified_name, midi_path); - - match output { - Ok(_) => { - let reply = ctx.send(CreateReply::default() - .attachment(CreateAttachment::path(&*wav_path).await.unwrap()) - ).await; - - if reply.is_err() { - println!( - "Discord[{}:{}]: Processed file couldn't be uploaded back to Discord channel due to upload limit", - ctx.guild().unwrap().name, ctx.command().qualified_name - ); - - ctx.send(CreateReply::default() - .content(format!( - "Couldn't upload the processed file (`{}`, `{}`) due to upload limit", - &*wav_path, format_bytes(metadata(&*wav_path).unwrap().size()) - )) - ).await.unwrap(); - } else if reply.is_ok() { - remove_file(midi_path)?; - remove_file(&*wav_path)?; - } - }, - Err(y) => { - ctx.send(CreateReply::default() - .content("Command didn't execute successfully, check console for more information!") - ).await.unwrap(); - - return Err(Error::from(format!("Midi conversion failed: {}", y))) - } - } - - Ok(()) -} diff --git a/src/commands/ping.rs b/src/commands/ping.rs old mode 100644 new mode 100755 index aa0300e..79acc99 --- a/src/commands/ping.rs +++ b/src/commands/ping.rs @@ -1,8 +1,36 @@ -use crate::Error; +use crate::RustbotError; +use super::PoiseContext; -/// Check if the bot is alive +use serde::Deserialize; + +#[derive(Deserialize)] +struct StatusPage { + metrics: Vec +} + +#[derive(Deserialize)] +struct Metrics { + summary: Summary +} + +#[derive(Deserialize)] +struct Summary { + mean: f64 +} + +/// Check latency of the bot's WS connection and Discord's API #[poise::command(slash_command)] -pub async fn ping(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { - ctx.reply(format!("Powong! `{:?}`", ctx.ping().await)).await?; +pub async fn ping(ctx: PoiseContext<'_>) -> Result<(), RustbotError> { + let statuspage: StatusPage = reqwest::get("https://discordstatus.com/metrics-display/5k2rt9f7pmny/day.json") + .await.unwrap() + .json() + .await.unwrap(); + + let mut latencies = Vec::new(); + latencies.push(format!("Discord: `{:.0?}ms`", statuspage.metrics[0].summary.mean)); + latencies.push(format!("WebSocket: `{:.0?}`", ctx.ping().await)); + + ctx.reply(latencies.join("\n")).await?; + Ok(()) } diff --git a/src/commands/sample.rs b/src/commands/sample.rs deleted file mode 100644 index db01265..0000000 --- a/src/commands/sample.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::{ - Error, - models::sample::SampleData -}; - -use poise::CreateReply; - -/// Perform sample CRUD operations in database -#[poise::command( - slash_command, - subcommands("list", "create", "update", "delete"), - subcommand_required -)] -pub async fn sample(_: poise::Context<'_, (), Error>) -> Result<(), Error> { - Ok(()) -} - -/// List sample data -#[poise::command(slash_command)] -pub async fn list( - ctx: poise::Context<'_, (), Error>, - #[description = "ID of the sample data"] id: u64 -) -> Result<(), Error> { - let samples = SampleData::list_data(id).await?; - - let mut response = String::new(); - for sample in samples { - response.push_str(&format!("ID: {}\n", sample.id)); - response.push_str(&format!("Text: {}\n", sample.text_val)); - response.push_str(&format!("Int: {}\n", sample.int_val)); - response.push_str(&format!("Boolean: {}\n\n", sample.boolean_val)); - } - - ctx.send(CreateReply::default() - .content(response) - ).await?; - - Ok(()) -} - -/// Create sample data -#[poise::command(slash_command)] -pub async fn create( - ctx: poise::Context<'_, (), Error>, - #[description = "Text value"] text: String, - #[description = "Int value"] int: u64, - #[description = "Boolean value"] boolean: bool -) -> Result<(), Error> { - SampleData::create_data(text, int as i64, boolean).await?; - - ctx.send(CreateReply::default().content("Done!")).await?; - - Ok(()) -} - -/// Update sample data -#[poise::command(slash_command)] -pub async fn update( - ctx: poise::Context<'_, (), Error>, - #[description = "ID of the sample data"] id: u64, - #[description = "Text value"] text: String, - #[description = "Int value"] int: u64, - #[description = "Boolean value"] boolean: bool -) -> Result<(), Error> { - SampleData::update_data(id, text, int as i64, boolean).await?; - - ctx.send(CreateReply::default().content("Done!")).await?; - - Ok(()) -} - -/// Delete sample data -#[poise::command(slash_command)] -pub async fn delete( - ctx: poise::Context<'_, (), Error>, - #[description = "ID of the sample data"] id: u64 -) -> Result<(), Error> { - SampleData::delete_data(id).await?; - - ctx.send(CreateReply::default().content("Done!")).await?; - - Ok(()) -} diff --git a/src/commands/uptime.rs b/src/commands/uptime.rs old mode 100644 new mode 100755 index 1a17136..383bff5 --- a/src/commands/uptime.rs +++ b/src/commands/uptime.rs @@ -1,16 +1,10 @@ -use crate::{ - Error, - GIT_COMMIT_HASH, - internals::utils::{ - BOT_VERSION, - format_duration, - concat_message - } -}; +use crate::RustbotError; +use super::PoiseContext; use sysinfo::System; use uptime_lib::get; use std::{ + env::var, fs::File, path::Path, time::{ @@ -23,34 +17,54 @@ use std::{ BufReader } }; +use rustbot_lib::utils::{ + BOT_VERSION, + GIT_COMMIT_HASH, + GIT_COMMIT_BRANCH, + format_duration +}; fn get_os_info() -> String { let path = Path::new("/etc/os-release"); let mut name = "BoringOS".to_string(); let mut version = "v0.0".to_string(); - if let Ok(file) = File::open(&path) { + if let Ok(file) = File::open(path) { let reader = BufReader::new(file); - for line in reader.lines() { - if let Ok(line) = line { - if line.starts_with("NAME=") { - name = line.split('=').nth(1).unwrap_or_default().trim_matches('"').to_string(); - } else if line.starts_with("VERSION=") { - version = line.split('=').nth(1).unwrap_or_default().trim_matches('"').to_string(); - } else if line.starts_with("VERSION_ID=") { - version = line.split('=').nth(1).unwrap_or_default().trim_matches('"').to_string(); - } + let set_value = |s: String| s.split('=').nth(1).unwrap_or_default().trim_matches('"').to_string(); + reader.lines().map_while(Result::ok).for_each(|line| { + match line { + l if l.starts_with("NAME=") => name = set_value(l), + l if l.starts_with("VERSION=") => version = set_value(l), + l if l.starts_with("VERSION_ID=") => version = set_value(l), + _ => {} } - } + }); } - format!("{} {}", name, version) + format!("{name} {version}") +} + +fn fmt_mem(bytes: u64) -> String { + let units = ["B", "KB", "MB", "GB"]; + let mut bytes = bytes as f64; + let mut unit = units[0]; + + for &u in &units { + if bytes < 1024.0 { + unit = u; + break; + } + bytes /= 1024.0; + } + + format!("{bytes:.2} {unit}") } /// Retrieve host and bot uptimes #[poise::command(slash_command)] -pub async fn uptime(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { - let _bot = ctx.http().get_current_user().await.unwrap(); +pub async fn uptime(ctx: PoiseContext<'_>) -> Result<(), RustbotError> { + let bot = ctx.http().get_current_user().await.unwrap(); let mut sys = System::new_all(); sys.refresh_all(); @@ -60,7 +74,17 @@ pub async fn uptime(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { // Fetch system's processor let cpu = sys.cpus(); - // Fetch bot's process uptime + // Fetch system memory usage + let sram = fmt_mem(sys.used_memory()); + let sram_total = fmt_mem(sys.total_memory()); + + // Fetch process memory usage + let pram = match sys.process(sysinfo::get_current_pid().unwrap()) { + Some(proc) => fmt_mem(proc.memory()), + None => String::from("Unavailable") + }; + + // Fetch process uptime let curr_pid = sysinfo::get_current_pid().unwrap(); let now = SystemTime::now(); let mut proc_uptime = 0; @@ -69,14 +93,22 @@ pub async fn uptime(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { proc_uptime = now.duration_since(time_started).unwrap().as_secs(); } - let stat_msg = vec![ - format!("**{} {}** `{}`", _bot.name, BOT_VERSION.as_str(), GIT_COMMIT_HASH), + // Fetch the node hostname from envvar + let docker_node = match var("DOCKER_HOSTNAME") { + Ok(h) => h.to_string(), + Err(_) => "DOCKER_HOSTNAME is empty!".to_string() + }; + + let stat_msg = [ + format!("**{} v{}** `{}:{}`", bot.name, BOT_VERSION.as_str(), GIT_COMMIT_HASH, GIT_COMMIT_BRANCH), format!(">>> System: `{}`", format_duration(sys_uptime)), format!("Process: `{}`", format_duration(proc_uptime)), - format!("CPU: `{}`", format!("{}", cpu[0].brand())), + format!("Node: `{docker_node}`"), + format!("CPU: `{}`", cpu[0].brand()), + format!("RAM: `{pram}` (`{sram}/{sram_total}`)"), format!("OS: `{}`", get_os_info()) ]; - ctx.reply(concat_message(stat_msg)).await?; + ctx.reply(stat_msg.join("\n")).await?; Ok(()) } diff --git a/src/controllers.rs b/src/controllers.rs deleted file mode 100644 index 8fd0a6b..0000000 --- a/src/controllers.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod database; diff --git a/src/controllers/database.rs b/src/controllers/database.rs deleted file mode 100644 index cfb29c4..0000000 --- a/src/controllers/database.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::internals::utils::token_path; - -use bb8::{Pool, PooledConnection}; -use bb8_postgres::PostgresConnectionManager; -use tokio::time::{ - Duration, - sleep -}; -use tokio_postgres::{ - Client, - NoTls, - Error, - config::Config -}; -use std::{ - ops::Deref, - str::FromStr, - sync::{ - Mutex, - LazyLock - } -}; - -pub static DATABASE: LazyLock>> = LazyLock::new(|| Mutex::new(None)); - -pub struct DatabaseController { - pub pool: Pool> -} - -impl DatabaseController { - pub async fn new() -> Result<(), Error> { - let manager = PostgresConnectionManager::new(Config::from_str(token_path().await.postgres_uri.as_str())?, NoTls); - let pool = bb8::Pool::builder().build(manager).await?; - let err_name = "Postgres[Error]"; - - let pool_clone = pool.clone(); - tokio::spawn(async move { - loop { - match Self::attempt_connect(&pool_clone).await { - Ok(conn) => { - println!("Postgres[Info]: Successfully connected"); - let client: &Client = conn.deref(); - - // Sample model - client.batch_execute(" - CREATE TABLE IF NOT EXISTS sample ( - id BIGSERIAL PRIMARY KEY, - text_val VARCHAR(255) NOT NULL, - int_val BIGINT NOT NULL, - boolean_val BOOLEAN NOT NULL - ); - ").await.unwrap(); - }, - Err(e) => { - eprintln!("{}: {}", err_name, e); - sleep(Duration::from_secs(5)).await; - } - } - break; - } - }); - - let controller = Self { pool }; - *DATABASE.lock().unwrap() = Some(controller); - - Ok(()) - } - - async fn attempt_connect<'a>(pool: &'a bb8::Pool>) -> Result>, bb8::RunError> { - let mut backoff = 1; - loop { - match pool.get().await { - Ok(conn) => return Ok(conn), - Err(e) => { - eprintln!("Postgres[ConnError]: {}, retrying in {} seconds", e, backoff); - sleep(Duration::from_secs(backoff)).await; - if backoff < 64 { - backoff *= 2; - } - } - } - } - } -} diff --git a/src/internals.rs b/src/internals.rs deleted file mode 100644 index 0ce8a43..0000000 --- a/src/internals.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod config; -pub mod tasks; -pub mod tsclient; -pub mod utils; diff --git a/src/internals/assets/FluidR3_GM.sf2 b/src/internals/assets/FluidR3_GM.sf2 deleted file mode 100755 index 443d42b..0000000 Binary files a/src/internals/assets/FluidR3_GM.sf2 and /dev/null differ diff --git a/src/internals/config.rs b/src/internals/config.rs deleted file mode 100644 index 994498c..0000000 --- a/src/internals/config.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::sync::LazyLock; - -pub struct ConfigMeta { - pub embed_color: i32, - pub ready_notify: u64, - pub rss_channel: u64, - pub rustbot_logs: u64, - pub deploy_commands: bool, - pub developers: Vec -} - -#[cfg(feature = "production")] -pub static BINARY_PROPERTIES: LazyLock = LazyLock::new(|| ConfigMeta::new()); - -#[cfg(not(feature = "production"))] -pub static BINARY_PROPERTIES: LazyLock = LazyLock::new(|| - ConfigMeta::new() - .embed_color(0xf1d63c) - .ready_notify(865673694184996888) - .rss_channel(865673694184996888) - .deploy_commands(false) -); - -impl ConfigMeta { - fn new() -> Self { - Self { - embed_color: 0x5a99c7, - ready_notify: 865673694184996888, - rss_channel: 865673694184996888, - rustbot_logs: 1268493237912604672, - deploy_commands: false, - developers: vec![ - 190407856527376384 // toast.ts - ] - } - } - - // Scalable functions below; - #[cfg(not(feature = "production"))] - fn embed_color(mut self, color: i32) -> Self { - self.embed_color = color; - self - } - - #[cfg(not(feature = "production"))] - fn ready_notify(mut self, channel_id: u64) -> Self { - self.ready_notify = channel_id; - self - } - - #[cfg(not(feature = "production"))] - fn rss_channel(mut self, channel_id: u64) -> Self { - self.rss_channel = channel_id; - self - } - - #[cfg(not(feature = "production"))] - fn deploy_commands(mut self, deploy: bool) -> Self { - self.deploy_commands = deploy; - self - } -} diff --git a/src/internals/tasks.rs b/src/internals/tasks.rs deleted file mode 100644 index 5063dc8..0000000 --- a/src/internals/tasks.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod sample; - -fn task_info(name: &str, message: &str) { - println!("{}", format!("TaskScheduler[{}]: {}", name, message)); -} - -fn task_err(name: &str, message: &str) { - eprintln!("{}", format!("TaskScheduler[{}:Error]: {}", name, message)); -} diff --git a/src/internals/tasks/sample.rs b/src/internals/tasks/sample.rs deleted file mode 100644 index 2ca322c..0000000 --- a/src/internals/tasks/sample.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::Error; -use super::{ - super::config::BINARY_PROPERTIES, - task_info, - task_err -}; - -use std::sync::Arc; -use poise::serenity_prelude::{ - Context, - ChannelId, - CreateMessage -}; -use tokio::time::{ - Duration, - interval -}; - -pub async fn sample(ctx: Arc) -> Result<(), Error> { - let task_name = "SampleTask"; - let mut interval = interval(Duration::from_secs(10)); - task_info(&task_name, "Task loaded!"); - - loop { - interval.tick().await; - task_info(&task_name, "Task running!"); - - if BINARY_PROPERTIES.rss_channel == 0 { - task_err(&task_name, "RSS channel ID is not set!"); - ChannelId::new(BINARY_PROPERTIES.rustbot_logs).send_message( - &ctx.http, - CreateMessage::new().content("RSS channel ID is not set!") - ).await.unwrap(); - - continue; - } - - ChannelId::new(BINARY_PROPERTIES.rss_channel).send_message( - &ctx.http, - CreateMessage::new().content("This is a sample message executed by a task!") - ).await.unwrap(); - } -} diff --git a/src/internals/tsclient.rs b/src/internals/tsclient.rs deleted file mode 100644 index f9a19dc..0000000 --- a/src/internals/tsclient.rs +++ /dev/null @@ -1,21 +0,0 @@ -use tokenservice_client::{ - TokenService, - TokenServiceApi -}; - -pub struct TSClient(TokenService); - -impl TSClient { - pub fn new() -> Self { - let args: Vec = std::env::args().collect(); - let service = if args.len() > 1 { &args[1] } else { "pgbot" }; - Self(TokenService::new(service)) - } - - pub async fn get(&self) -> Result { - match self.0.connect().await { - Ok(api) => Ok(api), - Err(e) => Err(e) - } - } -} diff --git a/src/internals/utils.rs b/src/internals/utils.rs deleted file mode 100644 index 3f2990b..0000000 --- a/src/internals/utils.rs +++ /dev/null @@ -1,86 +0,0 @@ -use poise::serenity_prelude::UserId; -use std::sync::LazyLock; -use tokio::sync::Mutex; -use tokenservice_client::TokenServiceApi; -use super::tsclient::TSClient; - -pub static BOT_VERSION: LazyLock = LazyLock::new(|| { - let cargo_version = cargo_toml::Manifest::from_str(&include_str!("../../Cargo.toml")) - .unwrap() - .package - .unwrap() - .version - .unwrap(); - format!("v{}", cargo_version) -}); - -static TSCLIENT: LazyLock> = LazyLock::new(|| Mutex::new(TSClient::new())); - -pub async fn token_path() -> TokenServiceApi { - TSCLIENT.lock().await.get().await.unwrap() -} - -pub fn concat_message(messages: Vec) -> String { - messages.join("\n") -} - -pub fn mention_dev(ctx: poise::Context<'_, (), crate::Error>) -> Option { - let devs = super::config::BINARY_PROPERTIES.developers.clone(); - let app_owners = ctx.framework().options().owners.clone(); - - let mut mentions = Vec::new(); - - for dev in devs { - if app_owners.contains(&UserId::new(dev)) { - mentions.push(format!("<@{}>", dev)); - } - } - - if mentions.is_empty() { - None - } else { - Some(mentions.join(", ")) - } -} - -pub fn format_duration(secs: u64) -> String { - let days = secs / 86400; - let hours = (secs % 86400) / 3600; - let minutes = (secs % 3600) / 60; - let seconds = secs % 60; - - let mut formatted_string = String::new(); - if days > 0 { - formatted_string.push_str(&format!("{}d, ", days)); - } - if hours > 0 || days > 0 { - formatted_string.push_str(&format!("{}h, ", hours)); - } - if minutes > 0 || hours > 0 { - formatted_string.push_str(&format!("{}m, ", minutes)); - } - formatted_string.push_str(&format!("{}s", seconds)); - - formatted_string -} - -pub fn format_bytes(bytes: u64) -> String { - let units = ["B", "KB", "MB", "GB", "TB", "PB"]; - let mut value = bytes as f64; - let mut unit = units[0]; - - for &u in &units[1..] { - if value < 1024.0 { - break; - } - - value /= 1024.0; - unit = u; - } - - if unit == "B" { - format!("{}{}", value, unit) - } else { - format!("{:.2}{}", value, unit) - } -} diff --git a/src/main.rs b/src/main.rs old mode 100644 new mode 100755 index 1d1c686..185b35a --- a/src/main.rs +++ b/src/main.rs @@ -1,187 +1,68 @@ mod commands; -mod controllers; -mod models; -mod internals; // https://cdn.toast-server.net/RustFSHiearchy.png // Using the new filesystem hierarchy -use crate::{ - internals::{ - utils::{ - BOT_VERSION, - token_path, - mention_dev - }, - config::BINARY_PROPERTIES - }, - controllers::database::DatabaseController -}; - -use std::{ - thread::current, - sync::{ - Arc, - atomic::{ - AtomicBool, - Ordering - } - } -}; +use rustbot_tokens::token_path; use poise::serenity_prelude::{ - builder::{ - CreateMessage, - CreateEmbed, - CreateEmbedAuthor - }, - Ready, - Context, - FullEvent, + builder::CreateAllowedMentions, ClientBuilder, - ChannelId, - Command, + ActivityData, GatewayIntents }; - -type Error = Box; -static TASK_RUNNING: AtomicBool = AtomicBool::new(false); - -#[cfg(feature = "production")] -pub static GIT_COMMIT_HASH: &str = env!("GIT_COMMIT_HASH"); -#[cfg(not(feature = "production"))] -pub static GIT_COMMIT_HASH: &str = "devel"; - -async fn on_ready( - ctx: &Context, - ready: &Ready, - framework: &poise::Framework<(), Error> -) -> Result<(), Error> { - #[cfg(not(feature = "production"))] - { - println!("Event[Ready][Notice]: Detected a non-production environment!"); - let gateway = ctx.http.get_bot_gateway().await?; - let session = gateway.session_start_limit; - println!("Event[Ready][Notice]: Session limit: {}/{}", session.remaining, session.total); - } - - println!("Event[Ready]: Build version: {} ({})", BOT_VERSION.to_string(), GIT_COMMIT_HASH); - println!("Event[Ready]: Connected to API as {}", ready.user.name); - - let message = CreateMessage::new(); - let ready_embed = CreateEmbed::new() - .color(BINARY_PROPERTIES.embed_color) - .thumbnail(ready.user.avatar_url().unwrap_or_default()) - .author(CreateEmbedAuthor::new(format!("{} is ready!", ready.user.name))); - - ChannelId::new(BINARY_PROPERTIES.ready_notify).send_message(&ctx.http, message.add_embed(ready_embed)).await?; - - if BINARY_PROPERTIES.deploy_commands { - let builder = poise::builtins::create_application_commands(&framework.options().commands); - let commands = Command::set_global_commands(&ctx.http, builder).await; - let mut commands_deployed = std::collections::HashSet::new(); - - match commands { - Ok(cmdmap) => for command in cmdmap.iter() { - commands_deployed.insert(command.name.clone()); - }, - Err(y) => eprintln!("Error registering commands: {:?}", y) - } - - if commands_deployed.len() > 0 { - println!("Event[Ready]: Deployed the commands globally:\n- {}", commands_deployed.into_iter().collect::>().join("\n- ")); - } - } - - Ok(()) -} - -async fn event_processor( - ctx: &Context, - event: &FullEvent, - framework: poise::FrameworkContext<'_, (), Error> -) -> Result<(), Error> { - match event { - FullEvent::Ratelimit { data } => { - println!("Event[Ratelimit]: {:#?}", data); - } - FullEvent::Message { new_message } => { - if new_message.author.bot || !new_message.guild_id.is_none() { - return Ok(()); - } - - if new_message.content.to_lowercase().starts_with("deploy") && new_message.author.id == BINARY_PROPERTIES.developers[0] { - let builder = poise::builtins::create_application_commands(&framework.options().commands); - let commands = Command::set_global_commands(&ctx.http, builder).await; - let mut commands_deployed = std::collections::HashSet::new(); - - match commands { - Ok(cmdmap) => for command in cmdmap.iter() { - commands_deployed.insert(command.name.clone()); - }, - Err(y) => { - eprintln!("Error registering commands: {:?}", y); - new_message.reply(&ctx.http, "Deployment failed, check console for more details!").await?; - } - } - - if commands_deployed.len() > 0 { - new_message.reply(&ctx.http, format!( - "Deployed the commands globally:\n- {}", - commands_deployed.into_iter().collect::>().join("\n- ") - )).await?; - } - } - } - FullEvent::Ready { .. } => { - let thread_id = format!("{:?}", current().id()); - let thread_num: String = thread_id.chars().filter(|c| c.is_digit(10)).collect(); - println!("Event[Ready]: Task Scheduler operating on thread {}", thread_num); - - let ctx = Arc::new(ctx.clone()); - - if !TASK_RUNNING.load(Ordering::SeqCst) { - TASK_RUNNING.store(true, Ordering::SeqCst); - - tokio::spawn(async move { - match internals::tasks::sample::sample(ctx).await { - Ok(_) => {}, - Err(y) => { - eprintln!("TaskScheduler[Main:Sample:Error]: Task execution failed: {}", y); - if let Some(source) = y.source() { - eprintln!("TaskScheduler[Main:Sample:Error]: Task execution failed caused by: {:#?}", source); - } - } - } - TASK_RUNNING.store(false, Ordering::SeqCst); - }); - } else { - println!("TaskScheduler[Main:Notice]: Another thread is already running, ignoring"); - } - } - _ => {} - } - - Ok(()) -} +use rustbot_lib::{ + utils::{ + mention_dev, + get_guild_name + }, + RustbotError, + RustbotData, + config::BINARY_PROPERTIES +}; +use rustbot_events::events::processor; +use std::{ + sync::Arc, + borrow::Cow +}; #[tokio::main] async fn main() { - DatabaseController::new().await.expect("Error initializing database"); + let prefix = if BINARY_PROPERTIES.env.contains("prod") { + Some(Cow::Borrowed("pg.")) + } else { + Some(Cow::Borrowed("pg!")) + }; + let commands = commands::collect!(); let framework = poise::Framework::builder() .options(poise::FrameworkOptions { - commands: vec![ - commands::ping::ping(), - commands::sample::sample(), - commands::midi::midi_to_wav(), - commands::uptime::uptime() - ], + commands, pre_command: |ctx| Box::pin(async move { - let get_guild_name = match ctx.guild() { - Some(guild) => guild.name.clone(), - None => String::from("Direct Message") + let get_guild_channel_name = match ctx.guild_channel().await { + Some(channel) => format!("in #{}", channel.name.clone()), + None => String::from("") }; - println!("Discord[{}]: {} ran /{}", get_guild_name, ctx.author().name, ctx.command().qualified_name); + let prefix = match ctx.command().prefix_action { + Some(_) => ctx.framework().options.prefix_options.prefix.as_ref().unwrap(), + None => "/" + }; + + println!( + "Discord[{}:S{}]: {} ran {}{} {}", + get_guild_name(ctx), + ctx.serenity_context().shard_id, + ctx.author().name, + prefix, + ctx.command().qualified_name, + get_guild_channel_name); }), + prefix_options: poise::PrefixFrameworkOptions { + prefix, + case_insensitive_commands: true, + ignore_bots: true, + execute_self_messages: false, + mention_as_prefix: false, + ..Default::default() + }, on_error: |error| Box::pin(async move { match error { poise::FrameworkError::Command { error, ctx, .. } => { @@ -192,32 +73,63 @@ async fn main() { )).await.expect("Error sending message"); }, poise::FrameworkError::EventHandler { error, event, .. } => println!("PoiseEventHandlerError({}): {}", event.snake_case_name(), error), - poise::FrameworkError::Setup { error, .. } => println!("PoiseSetupError: {}", error), + poise::FrameworkError::NotAnOwner { ctx, .. } => { + println!("PoiseNotAnOwner: {} tried to execute a developer-level command ({})", ctx.author().name, ctx.command().qualified_name); + ctx.reply("Whoa, you discovered a hidden command! Too bad, I can't allow you to execute it as you're not my creator.").await.expect("Error sending message"); + }, poise::FrameworkError::UnknownInteraction { interaction, .. } => println!( "PoiseUnknownInteractionError: {} tried to execute an unknown interaction ({})", interaction.user.name, interaction.data.name ), - other => println!("PoiseOtherError: {}", other) + poise::FrameworkError::UnknownCommand { msg, .. } => println!( + "PoiseUnknownCommandError: {} tried to execute an unknown command ({})", + msg.author.name, + msg.content + ), + poise::FrameworkError::ArgumentParse { ctx, error, .. } => { + println!("PoiseArgumentParseError: {}", error); + ctx.reply(format!("Error parsing argument(s): {error}")).await.expect("Error sending message"); + }, + poise::FrameworkError::CommandPanic { ctx, payload, .. } => { + if let Some(payload) = payload.clone() { + println!("PoiseCommandPanic: {payload}"); + ctx.reply(format!( + "The command panicked, please tell my developer about this!\n**Error:**```\n{payload}\n```" + )).await.expect("Error sending message"); + } else { + println!("PoiseCommandPanic: No payload provided"); + let uh_oh = [ + "Well, this is concerning... Hopefully you notified my developer about this!", + "The command panicked, but didn't leave any trace behind... Suspicious!", + ].join("\n"); + ctx.reply(uh_oh).await.expect("Error sending message"); + } + }, + other => println!("PoiseOtherError: {other}") } }), + allowed_mentions: Some(CreateAllowedMentions::default().empty_users()), initialize_owners: true, - event_handler: |ctx, event, framework, _| Box::pin(event_processor(ctx, event, framework)), + skip_checks_for_owners: true, + event_handler: |framework, event| Box::pin(processor(framework, event)), ..Default::default() }) - .setup(|ctx, ready, framework| Box::pin(on_ready(ctx, ready, framework))) .build(); let mut client = ClientBuilder::new( - token_path().await.main, + &token_path().await.main, GatewayIntents::GUILDS - | GatewayIntents::MESSAGE_CONTENT + | GatewayIntents::GUILD_MESSAGES | GatewayIntents::DIRECT_MESSAGES + | GatewayIntents::MESSAGE_CONTENT ) .framework(framework) + .data(Arc::new(RustbotData {})) + .activity(ActivityData::custom("nep nep!")) .await.expect("Error creating client"); - if let Err(why) = client.start().await { + if let Err(why) = client.start_autosharded().await { println!("Error starting client: {:#?}", why); } } diff --git a/src/models.rs b/src/models.rs deleted file mode 100644 index ce8e751..0000000 --- a/src/models.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod sample; diff --git a/src/models/sample.rs b/src/models/sample.rs deleted file mode 100644 index 43d3b04..0000000 --- a/src/models/sample.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::controllers::database::DATABASE; - -use std::ops::Deref; - -pub struct SampleData { - pub id: i64, - pub text_val: String, - pub int_val: i64, - pub boolean_val: bool -} - -impl SampleData { - pub async fn list_data(id: u64) -> Result, tokio_postgres::Error> { - let pool = { - let db = DATABASE.lock().unwrap(); - let controller = db.as_ref().unwrap(); - controller.pool.clone() - }; - let conn = pool.get().await.unwrap(); - let client = conn.deref(); - let rows = client.query(" - SELECT * FROM sample - WHERE id = $1 - ", &[&(id as i64)]).await?; - - let mut data = Vec::new(); - for row in rows { - data.push(Self { - id: row.get("id"), - text_val: row.get("text_val"), - int_val: row.get("int_val"), - boolean_val: row.get("boolean_val") - }); - } - - Ok(data) - } - - pub async fn create_data( - text: String, - int: i64, - boolean: bool - ) -> Result<(), tokio_postgres::Error> { - let pool = { - let db = DATABASE.lock().unwrap(); - let controller = db.as_ref().unwrap(); - controller.pool.clone() - }; - let conn = pool.get().await.unwrap(); - let client = conn.deref(); - client.execute(" - INSERT INTO sample (text_val, int_val, boolean_val) - VALUES ($1, $2, $3) - ", &[&text, &int, &boolean]).await?; - - Ok(()) - } - - pub async fn update_data( - id: u64, - text: String, - int: i64, - boolean: bool - ) -> Result<(), tokio_postgres::Error> { - let pool = { - let db = DATABASE.lock().unwrap(); - let controller = db.as_ref().unwrap(); - controller.pool.clone() - }; - let conn = pool.get().await.unwrap(); - let client = conn.deref(); - client.execute(" - UPDATE sample - SET text_val = $1, int_val = $2, boolean_val = $3 - WHERE id = $4 - ", &[&text, &int, &boolean, &(id as i64)]).await?; - - Ok(()) - } - - pub async fn delete_data(id: u64) -> Result<(), tokio_postgres::Error> { - let pool = { - let db = DATABASE.lock().unwrap(); - let controller = db.as_ref().unwrap(); - controller.pool.clone() - }; - let conn = pool.get().await.unwrap(); - let client = conn.deref(); - client.execute(" - DELETE FROM sample - WHERE id = $1 - ", &[&(id as i64)]).await?; - - Ok(()) - } -} diff --git a/stuff-to-change.log b/stuff-to-change.log new file mode 100644 index 0000000..f648eda --- /dev/null +++ b/stuff-to-change.log @@ -0,0 +1,11 @@ +Only things that are needing to be changed before deploying this template to real-world use; +- The project name (Rustbot) +- Dockerfile image tag and its service in compose file +- events (rustbot_events), and its references +- jobs (rustbot_jobs), and its references +- library (rustbot_lib), and its references +- tsclient (rustbot_tokens), and its references + +Search by Rustbot in its usual form (all-caps, pascalcase, and such) to find all the references that need to be changed too. + +(and delete this file too!) diff --git a/tsclient/Cargo.toml b/tsclient/Cargo.toml new file mode 100755 index 0000000..e64270b --- /dev/null +++ b/tsclient/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rustbot_tokens" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokenservice-client = { version = "0.4.1", registry = "gitea" } +tokio = { workspace = true } diff --git a/tsclient/src/lib.rs b/tsclient/src/lib.rs new file mode 100755 index 0000000..04bd9c2 --- /dev/null +++ b/tsclient/src/lib.rs @@ -0,0 +1,35 @@ +use std::sync::LazyLock; +use tokio::sync::Mutex; +use tokenservice_client::{ + TokenService, + TokenServiceApi +}; + +pub struct TSClient(TokenService); + +impl Default for TSClient { + fn default() -> Self { + Self::new() + } +} + +impl TSClient { + pub fn new() -> Self { + let args: Vec = std::env::args().collect(); + let service = if args.len() > 1 { &args[1] } else { "pgbot" }; + Self(TokenService::new(service)) + } + + pub async fn get(&self) -> Result> { + match self.0.connect().await { + Ok(api) => Ok(api), + Err(e) => Err(e) + } + } +} + +static TSCLIENT: LazyLock> = LazyLock::new(|| Mutex::new(TSClient::new())); + +pub async fn token_path() -> TokenServiceApi { + TSCLIENT.lock().await.get().await.unwrap() +}