diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 9d863c4..bef3908 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -52,5 +52,5 @@ jobs: port: ${{ secrets.SSH_PORT }} script: | cd kon && docker compose pull bot && \ - docker compose down bot --remove-orphans && docker compose up -d bot && \ + docker compose down bot && docker compose up -d bot && \ docker image prune -f && docker system prune -f diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..88ab769 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + "recommendations": [ + "fill-labs.dependi", + "usernamehw.errorlens", + "tamasfe.even-better-toml", + "GitHub.vscode-pull-request-github", + "rust-lang.rust-analyzer", + "redhat.vscode-yaml", + "sumneko.lua" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 2938df3..eb62eaf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,4 @@ { - "rust-analyzer.linkedProjects": [ - "./Cargo.toml" - ], - "rust-analyzer.showUnlinkedFileNotification": false + "rust-analyzer.showUnlinkedFileNotification": false, + "rust-analyzer.linkedProjects": ["./Cargo.toml"] } diff --git a/Cargo.lock b/Cargo.lock index ee933f9..7920ea2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,6 +94,30 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bb8" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b10cf871f3ff2ce56432fddc2615ac7acc3aa22ca321f8fea800846fbb32f188" +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" @@ -139,16 +163,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" -[[package]] -name = "bzip2-rs" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beeb59e7e4c811ab37cc73680c798c7a5da77fc9989c62b09138e31ee740f735" -dependencies = [ - "crc32fast", - "tinyvec", -] - [[package]] name = "camino" version = "1.1.6" @@ -182,9 +196,9 @@ dependencies = [ [[package]] name = "cargo_toml" -version = "0.20.2" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8cb1d556b8b8f36e5ca74938008be3ac102f5dcb5b68a0477e4249ae2291cd3" +checksum = "ad639525b1c67b6a298f378417b060fbc04618bea559482a8484381cce27d965" dependencies = [ "serde", "toml", @@ -576,23 +590,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "gamedig" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f351da15ad9dd6cafd687c9a016e0128741120884925c53d79c7d20f0f9e6ef9" -dependencies = [ - "byteorder", - "bzip2-rs", - "crc32fast", - "encoding_rs", - "phf", - "serde", - "serde_json", - "ureq", - "url", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -828,6 +825,23 @@ dependencies = [ "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "rustls 0.23.7", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -875,7 +889,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.52.0", ] [[package]] @@ -958,13 +972,15 @@ dependencies = [ [[package]] name = "kon" -version = "0.2.11" +version = "0.3.0" dependencies = [ + "bb8", + "bb8-postgres", "cargo_toml", - "gamedig", "once_cell", + "os_info", "poise", - "reqwest 0.12.4", + "reqwest 0.12.5", "serde", "serde_json", "sysinfo", @@ -982,9 +998,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "linked-hash-map" @@ -1207,6 +1223,17 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "os_info" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +dependencies = [ + "log", + "serde", + "windows-sys 0.52.0", +] + [[package]] name = "parking_lot" version = "0.12.2" @@ -1242,33 +1269,9 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ - "phf_macros", "phf_shared", ] -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "syn 2.0.61", -] - [[package]] name = "phf_shared" version = "0.11.2" @@ -1533,7 +1536,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", - "hyper-rustls", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -1547,7 +1550,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-rustls 0.24.1", @@ -1564,9 +1567,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", @@ -1578,6 +1581,7 @@ dependencies = [ "http-body 1.0.0", "http-body-util", "hyper 1.3.1", + "hyper-rustls 0.27.2", "hyper-tls", "hyper-util", "ipnet", @@ -1592,7 +1596,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "system-configuration", "tokio", "tokio-native-tls", @@ -1674,6 +1678,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki 0.102.3", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -1804,18 +1821,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", @@ -1824,9 +1841,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -1835,9 +1852,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -2021,10 +2038,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] -name = "sysinfo" -version = "0.30.12" +name = "sync_wrapper" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "sysinfo" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" dependencies = [ "cfg-if", "core-foundation-sys", @@ -2032,7 +2055,7 @@ dependencies = [ "ntapi", "once_cell", "rayon", - "windows", + "windows 0.52.0", ] [[package]] @@ -2076,18 +2099,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -2142,27 +2165,29 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokenservice-client" -version = "0.2.8" +version = "0.3.2" source = "sparse+https://git.toast-server.net/api/packages/toast/cargo/" -checksum = "7553919fa2e0356a894cc8e6ef1d72d1a04d95b9323eca01949120080e56b5b6" +checksum = "afce7633f840504c54b2d2dfee881e183543ad8945bedbd86ea8fbaeb498bfb8" dependencies = [ - "reqwest 0.12.4", + "reqwest 0.12.5", "serde", + "serde_json", "tokio", "trust-dns-resolver", ] [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" dependencies = [ "backtrace", "bytes", "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -2172,9 +2197,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", @@ -2238,6 +2263,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.7", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-tungstenite" version = "0.21.0" @@ -2269,9 +2305,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" dependencies = [ "serde", "serde_spanned", @@ -2281,18 +2317,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" dependencies = [ "indexmap", "serde", @@ -2519,28 +2555,13 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "uptime_lib" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e71ddbefed856d5881821d6ada4e606bbb91fd332296963ed596e2ad2100f3" +checksum = "9e64b558561f12a171bbea5325c3f24f129db371adee1d7ae93b6e310bd69192" dependencies = [ "libc", "thiserror", - "windows", -] - -[[package]] -name = "ureq" -version = "2.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" -dependencies = [ - "base64 0.22.1", - "flate2", - "log", - "once_cell", - "serde", - "serde_json", - "url", + "windows 0.57.0", ] [[package]] @@ -2762,7 +2783,17 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", "windows-targets 0.52.5", ] @@ -2775,6 +2806,49 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index c0adc2f..3f3d959 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,21 +1,26 @@ [package] name = "kon" -version = "0.2.11" +version = "0.3.0" edition = "2021" [dependencies] -cargo_toml = "0.20.2" -gamedig = "0.5.0" +bb8 = "0.8.5" +bb8-postgres = "0.8.1" +cargo_toml = "0.20.4" once_cell = "1.19.0" +os_info = "3.8.2" poise = "0.6.1" -reqwest = { version = "0.12.4", features = ["json"] } -serde = "1.0.201" -serde_json = "1.0.117" -sysinfo = "0.30.12" -tokenservice-client = { version = "0.2.4", registry = "gitea" } -tokio = { version = "1.37.0", features = ["macros", "signal", "rt-multi-thread"] } +reqwest = { version = "0.12.5", features = ["json"] } +serde = "1.0.204" +serde_json = "1.0.120" +sysinfo = "0.30.13" +tokenservice-client = { version = "0.3.2", registry = "gitea" } +tokio = { version = "1.38.1", features = ["macros", "signal", "rt-multi-thread"] } tokio-postgres = "0.7.10" -uptime_lib = "0.3.0" +uptime_lib = "0.3.1" + +[features] +production = [] [[bin]] name = "kon" diff --git a/Dockerfile b/Dockerfile index 61d9412..3c188df 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -FROM rust:1.78-alpine3.19@sha256:d4d3f81f3111991353bd7c7fa513ad3725a27027575fd82e24fb7babcd8f26f7 AS chef -ENV RUSTFLAGS -C target-feature=-crt-static +FROM rust:1.79-alpine3.20 AS chef +ENV RUSTFLAGS="-C target-feature=-crt-static" ARG CARGO_TOKEN RUN apk add --no-cache openssl-dev musl-dev -RUN cargo install cargo-chef +RUN cargo install cargo-chef WORKDIR /usr/src/kon FROM chef AS planner @@ -15,11 +15,10 @@ FROM chef AS builder COPY --from=planner /usr/src/kon/recipe.json recipe.json RUN cargo chef cook --release COPY . . -RUN cargo build -r +RUN cargo build -rF production -FROM alpine:3.19@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b +FROM alpine:3.20 RUN apk add --no-cache libgcc WORKDIR /kon COPY --from=builder /usr/src/kon/target/release/kon . -COPY --from=builder /usr/src/kon/Cargo.toml . -CMD ./kon +CMD [ "./kon" ] diff --git a/docker-compose.yml b/docker-compose.yml index 1389cb8..ad065bf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,20 +3,18 @@ services: container_name: kon #image: 'git.toast-server.net/toast/kon:main' build: . - env_file: - - .env restart: unless-stopped - depends_on: - - db - db: - container_name: kon-database - image: postgres:16.2-alpine3.19@sha256:951bfda460300925caa3949eaa092ba022e9aec191bbea9056a39e2382260b27 - restart: unless-stopped - ports: - - 37930:5432/tcp - volumes: - - /var/lib/docker/volumes/kon-database:/var/lib/postgresql/data:rw - environment: - POSTGRES_USER: ${POSTGRES_USER} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} - POSTGRES_DB: ${POSTGRES_DB} +# depends_on: +# - db +# db: +# container_name: kon-database +# image: postgres:16.2-alpine3.19@sha256:951bfda460300925caa3949eaa092ba022e9aec191bbea9056a39e2382260b27 +# restart: unless-stopped +# ports: +# - 37930:5432/tcp +# volumes: +# - /var/lib/docker/volumes/kon-database:/var/lib/postgresql/data:rw +# environment: +# POSTGRES_USER: ${POSTGRES_USER} +# POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} +# POSTGRES_DB: ${POSTGRES_DB} diff --git a/run.sh b/run.sh index 2806c3a..2492acd 100755 --- a/run.sh +++ b/run.sh @@ -1,3 +1,3 @@ #!/bin/bash -export $(grep -v '^#' .env | xargs) && cargo run kon_dev +clear && cargo run kon_dev diff --git a/src/commands/mod.rs b/src/commands.rs similarity index 69% rename from src/commands/mod.rs rename to src/commands.rs index 3c4d858..2cd38c3 100644 --- a/src/commands/mod.rs +++ b/src/commands.rs @@ -1,4 +1,3 @@ pub mod ping; pub mod status; pub mod uptime; -pub mod gameserver; diff --git a/src/commands/gameserver.rs b/src/commands/gameserver.rs deleted file mode 100644 index 58e818c..0000000 --- a/src/commands/gameserver.rs +++ /dev/null @@ -1,265 +0,0 @@ -use crate::{ - Error, - internals::utils::EMBED_COLOR, - models::gameservers::Gameservers -}; - -use poise::serenity_prelude::{ - futures::{ - stream::iter, - future::ready, - Stream, - StreamExt - }, - builder::CreateActionRow, - builder::CreateEmbed, -}; -use poise::{ - CreateReply, - serenity_prelude, - serenity_prelude::ButtonStyle, - ChoiceParameter -}; - -#[derive(Debug, ChoiceParameter)] -enum GameNames { - #[name = "Minecraft"] - Minecraft -} - -/// Manage the game servers for this guild -#[poise::command( - slash_command, - subcommands("add", "remove", "update", "list"), - subcommand_required, - guild_only, - default_member_permissions = "MANAGE_GUILD", - required_permissions = "MANAGE_GUILD" // No clue if this is needed or not. Just leaving it here for now -)] -pub async fn gameserver(_: poise::Context<'_, (), Error>) -> Result<(), Error> { - Ok(()) -} - -/// Add a game server to the database -#[poise::command(slash_command)] -pub async fn add( - ctx: poise::Context<'_, (), Error>, - #[description = "Server name as shown in-game or friendly name"] server_name: String, - #[description = "Which game is this server running?"] game_name: GameNames, - #[description = "IP address/domain of the server (Include the port if it has one, e.g 127.0.0.1:8080)"] ip_address: String -) -> Result<(), Error> { - let action_row = CreateActionRow::Buttons(vec![ - serenity_prelude::CreateButton::new("add-confirm") - .style(ButtonStyle::Success) - .label("Yes"), - serenity_prelude::CreateButton::new("add-cancel") - .style(ButtonStyle::Danger) - .label("No") - ]); - - let reply = CreateReply::default() - .embed(CreateEmbed::new() - .title("Does this look correct?") - .description(format!(" - **Server name:** `{}` - **Game name:** `{}` - **IP Address:** `{}` - ", server_name, game_name.name(), ip_address)) - .color(EMBED_COLOR) - ) - .components(vec![action_row]); - - ctx.send(reply).await?; - - while let Some(collector) = serenity_prelude::ComponentInteractionCollector::new(ctx) - .guild_id(ctx.guild_id().unwrap()) - .author_id(ctx.author().id) - .timeout(std::time::Duration::from_secs(30)) - .await - { - if collector.data.custom_id == "add-confirm" { - let result = Gameservers::add_server( - ctx.guild_id().unwrap().into(), - server_name.as_str(), - game_name.name(), - ip_address.as_str() - ).await; - - let mut msg = collector.message.clone(); - - match result { - Ok(_) => { - msg.edit( - ctx, - serenity_prelude::EditMessage::new() - .content("*Confirmed, added the server to database*") - .embeds(Vec::new()) - .components(Vec::new()) - ).await?; - }, - Err(y) => { - msg.edit( - ctx, - serenity_prelude::EditMessage::new() - .content(format!("*Error adding server to database:\n`{}`*", y)) - .embeds(Vec::new()) - .components(Vec::new()) - ).await?; - } - } - } else if collector.data.custom_id == "add-cancel" { - let mut msg = collector.message.clone(); - - msg.edit( - ctx, - serenity_prelude::EditMessage::new() - .content("*Command cancelled*") - .embeds(Vec::new()) - .components(Vec::new()) - ).await?; - } - } - - Ok(()) -} - -/// Remove a game server from the database -#[poise::command(slash_command)] -pub async fn remove( - ctx: poise::Context<'_, (), Error>, - #[description = "Server name"] #[autocomplete = "ac_server_name"] server_name: String -) -> Result<(), Error> { - let reply = CreateReply::default() - .embed(CreateEmbed::new() - .title("Are you sure you want to remove this server?") - .description(format!("**Server name:** `{}`", server_name)) - .color(EMBED_COLOR) - ) - .components(vec![ - CreateActionRow::Buttons(vec![ - serenity_prelude::CreateButton::new("delete-confirm") - .style(ButtonStyle::Success) - .label("Yes"), - serenity_prelude::CreateButton::new("delete-cancel") - .style(ButtonStyle::Danger) - .label("No") - ]) - ]); - - ctx.send(reply).await?; - - while let Some(collector) = serenity_prelude::ComponentInteractionCollector::new(ctx) - .guild_id(ctx.guild_id().unwrap()) - .author_id(ctx.author().id) - .timeout(std::time::Duration::from_secs(30)) - .await - { - if collector.data.custom_id == "delete-confirm" { - let result = Gameservers::remove_server(ctx.guild_id().unwrap().into(), server_name.as_str()).await; - - let mut msg = collector.message.clone(); - - match result { - Ok(_) => { - msg.edit( - ctx, - serenity_prelude::EditMessage::new() - .content("*Confirmed, removed the server from database*") - .embeds(Vec::new()) - .components(Vec::new()) - ).await?; - }, - Err(y) => { - msg.edit( - ctx, - serenity_prelude::EditMessage::new() - .content(format!("*Error removing server from database:\n`{}`*", y)) - .embeds(Vec::new()) - .components(Vec::new()) - ).await?; - } - } - } else if collector.data.custom_id == "delete-cancel" { - let mut msg = collector.message.clone(); - - msg.edit( - ctx, - serenity_prelude::EditMessage::new() - .content("*Command cancelled*") - .embeds(Vec::new()) - .components(Vec::new()) - ).await?; - } - } - - Ok(()) -} - -/// Update a game server in the database -#[poise::command(slash_command)] -pub async fn update( - ctx: poise::Context<'_, (), Error>, - #[description = "Server name"] #[autocomplete = "ac_server_name"] server_name: String, - #[description = "Game name"] game_name: GameNames, - #[description = "IP address"] ip_address: String -) -> Result<(), Error> { - let result = Gameservers::update_server( - ctx.guild_id().unwrap().into(), - &server_name, - &game_name.name(), - &ip_address - ).await; - - match result { - Ok(_) => { - ctx.send(CreateReply::default().content("Updated the server in database.")).await?; - }, - Err(y) => { - ctx.send(CreateReply::default().content(format!("Error updating the server in database: {:?}", y))).await?; - } - } - - Ok(()) -} - -/// List all the available game servers for this guild -#[poise::command(slash_command)] -pub async fn list(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { - let servers = Gameservers::list_servers(ctx.guild_id().unwrap().into()).await?; - - let mut embed_fields = Vec::new(); - for server in servers { - embed_fields.push( - (server.server_name, format!("Game: `{}`\nIP: `{}`", server.game_name, server.ip_address), true) - ); - } - - ctx.send(CreateReply::default() - .embed(CreateEmbed::new() - .title("List of registered gameservers") - .fields(embed_fields) - .color(EMBED_COLOR) - ) - ).await?; - - Ok(()) -} - -pub async fn ac_server_name<'a>( - ctx: poise::Context<'_, (), Error>, - partial: &'a str -) -> impl Stream + 'a { - let result = Gameservers::get_server_names(ctx.guild_id().unwrap().into()).await; - - let names = match result { - Ok(names_vector) => names_vector, - Err(y) => { - println!("Error retrieving server names: {:?}", y); - Vec::new() - } - }; - - iter(names) - .filter(move |server_name| ready(server_name.starts_with(partial))) - .map(|server_name| server_name.to_string()) -} diff --git a/src/commands/status.rs b/src/commands/status.rs index 78ed7e2..73c86d1 100644 --- a/src/commands/status.rs +++ b/src/commands/status.rs @@ -1,41 +1,23 @@ use crate::{ Error, - models::gameservers::Gameservers, - commands::gameserver::ac_server_name, - internals::utils::EMBED_COLOR, - internals::http::HttpClient, - internals::utils::token_path + internals::{ + config::BINARY_PROPERTIES, + http::HttpClient, + utils::token_path + } }; +use serde_json::Value; use std::collections::HashMap; use tokio::join; -use poise::CreateReply; -use poise::serenity_prelude::builder::CreateEmbed; -use serde::Deserialize; -use serde_json::Value; - -#[derive(Deserialize)] -struct MinecraftQueryData { - motd: Option, - players: Option, - version: Option, - online: bool -} - -#[derive(Deserialize)] -struct MinecraftMotd { - clean: Vec -} - -#[derive(Deserialize, Clone, Copy)] -struct MinecraftPlayers { - online: i32, - max: i32 -} +use poise::{ + CreateReply, + serenity_prelude::builder::CreateEmbed +}; async fn pms_serverstatus(url: &str) -> Result)>, Error> { let client = HttpClient::new(); - let req = client.get(url).await?; + let req = client.get(url, "PMS-Status").await?; let response = req.json::>().await?; let data = response["data"].as_array().unwrap(); @@ -84,22 +66,12 @@ fn process_pms_statuses(servers: Vec<(String, Vec)>) -> Vec<(String, Stri statuses } -async fn gs_query_minecraft(server_ip: &str) -> Result { - let client = HttpClient::new(); - let req = client.get(&format!("https://api.mcsrvstat.us/2/{}", server_ip)).await?; - - if req.status().is_success() { - let data: MinecraftQueryData = req.json().await?; - Ok(data) - } else if req.status().is_server_error() { - Err(Error::from("Webserver returned a 5xx error.")) - } else { - Err(Error::from("Failed to query the server.")) - } -} - /// Query the server statuses -#[poise::command(slash_command, subcommands("wg", "gs"), subcommand_required)] +#[poise::command( + slash_command, + subcommands("wg"), + subcommand_required +)] pub async fn status(_: poise::Context<'_, (), Error>) -> Result<(), Error> { Ok(()) } @@ -109,7 +81,7 @@ pub async fn status(_: poise::Context<'_, (), Error>) -> Result<(), Error> { pub async fn wg(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { let pms_asia = token_path().await.wg_pms; let pms_eu = pms_asia.replace("asia", "eu"); - let embed = CreateEmbed::new().color(EMBED_COLOR); + let embed = CreateEmbed::new().color(BINARY_PROPERTIES.embed_color); let (servers_asia, servers_eu) = join!(pms_serverstatus(&pms_asia), pms_serverstatus(&pms_eu)); let joined_pms_servers = [servers_eu.unwrap(), servers_asia.unwrap()].concat(); @@ -119,46 +91,3 @@ pub async fn wg(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { Ok(()) } - -/// Retrieve the given server data from gameservers DB -#[poise::command(slash_command, guild_only)] -pub async fn gs( - ctx: poise::Context<'_, (), Error>, - #[description = "Server name"] #[autocomplete = "ac_server_name"] server_name: String -) -> Result<(), Error> { - let server_data = Gameservers::get_server_data(ctx.guild_id().unwrap().into(), &server_name).await?; - - // Extract values from a Vec above - let game_name = &server_data[1]; - let ip_address = &server_data[2]; - - match game_name.as_str() { - "Minecraft" => { - let result = gs_query_minecraft(ip_address).await?; - let embed = CreateEmbed::new().color(EMBED_COLOR); - - if result.online { - let mut embed_fields = Vec::new(); - embed_fields.push(("Server IP".to_owned(), ip_address.to_owned(), true)); - embed_fields.push((format!("\u{200b}"), format!("\u{200b}"), true)); - embed_fields.push(("MOTD".to_owned(), format!("{}", result.motd.unwrap().clean[0]), true)); - embed_fields.push(("Players".to_owned(), format!("**{}**/**{}**", result.players.unwrap().online, result.players.clone().unwrap().max), true)); - embed_fields.push(("Version".to_owned(), result.version.unwrap(), true)); - - ctx.send(CreateReply::default() - .embed(embed - .title(server_name) - .fields(embed_fields) - ) - ).await?; - } else { - ctx.send(CreateReply::default() - .content(format!("**{}** (`{}`) is currently offline or unreachable.", server_name, ip_address)) - ).await?; - } - }, - _ => {} - } - - Ok(()) -} diff --git a/src/commands/uptime.rs b/src/commands/uptime.rs index c7928eb..5608a2a 100644 --- a/src/commands/uptime.rs +++ b/src/commands/uptime.rs @@ -22,6 +22,10 @@ pub async fn uptime(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { let mut sys = System::new_all(); sys.refresh_all(); + // Fetch system's operating system + let sys_os_info = os_info::get(); + let sys_os = format!("{} {}", sys_os_info.os_type(), sys_os_info.version()); + // Fetch system's uptime let sys_uptime = get().unwrap().as_secs(); @@ -37,7 +41,8 @@ pub async fn uptime(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> { let stat_msg = vec![ format!("**{} {}**", _bot.name, BOT_VERSION.as_str()), format!(">>> System: `{}`", format_duration(sys_uptime)), - format!("Process: `{}`", format_duration(proc_uptime)) + format!("Process: `{}`", format_duration(proc_uptime)), + format!("OS: `{}`", sys_os) ]; ctx.reply(concat_message(stat_msg)).await?; diff --git a/src/controllers.rs b/src/controllers.rs new file mode 100644 index 0000000..6ecfc8e --- /dev/null +++ b/src/controllers.rs @@ -0,0 +1 @@ +// pub mod database; diff --git a/src/controllers/database.rs b/src/controllers/database.rs index 0ad0cff..d4edebb 100644 --- a/src/controllers/database.rs +++ b/src/controllers/database.rs @@ -1,37 +1,75 @@ -use crate::internals; +use crate::internals::utils::token_path; -use poise::serenity_prelude::prelude::TypeMapKey; -use tokio_postgres::{Client, NoTls, Error}; +use once_cell::sync::Lazy; +use bb8::{Pool, PooledConnection}; +use bb8_postgres::PostgresConnectionManager; +use tokio_postgres::{ + Client, + NoTls, + Error, + config::Config +}; +use tokio::time::{ + sleep, + Duration +}; +use std::{ + ops::Deref, + str::FromStr, + sync::Mutex +}; + +pub static DATABASE: Lazy>> = Lazy::new(|| Mutex::new(None)); pub struct DatabaseController { - pub client: Client -} - -impl TypeMapKey for DatabaseController { - type Value = DatabaseController; + pub pool: Pool> } impl DatabaseController { - pub async fn new() -> Result { - let (client, connection) = tokio_postgres::connect(&internals::utils::token_path().await.postgres_uri, NoTls).await?; + pub async fn new() -> Result<(), Error> { + let manager = PostgresConnectionManager::new(Config::from_str(token_path().await.postgres_uri.as_str())?, NoTls); + let pool = Pool::builder().build(manager).await?; + let err_name = "Postgres[Error]"; + let pool_clone = pool.clone(); tokio::spawn(async move { - if let Err(e) = connection.await { - eprintln!("Connection error: {}", e); + let conn = match Self::attempt_connect(&pool_clone).await { + Ok(conn) => { + println!("Postgres[Info]: Successfully connected"); + conn + }, + Err(y) => { + eprintln!("{}: {}", err_name, y); + return; + } + }; + let client: &Client = conn.deref(); + + /* if let Err(e) = client.batch_execute("").await { + eprintln!("{}: {}", err_name, e); + } */ // Uncomment this if bot is going to use a database + }).await.unwrap(); + + let controller = Self { pool }; + *DATABASE.lock().unwrap() = Some(controller); + + Ok(()) + } + + async fn attempt_connect<'a>(pool: &'a Pool>) -> Result>, bb8::RunError> { + let mut backoff = 1; + + loop { + match pool.get().await { + Ok(conn) => return Ok(conn), + Err(y) => { + eprintln!("Postgres[ConnError]: {}, retrying in {} seconds", y, backoff); + sleep(Duration::from_secs(backoff)).await; + if backoff < 64 { + backoff *= 2; + } + } } - }); - - // Gameservers - client.batch_execute(" - CREATE TABLE IF NOT EXISTS gameservers ( - server_name VARCHAR(255) NOT NULL, - game_name VARCHAR(255) NOT NULL, - guild_owner BIGINT NOT NULL, - ip_address VARCHAR(255) NOT NULL, - PRIMARY KEY (server_name, guild_owner) - ); - ").await?; - - Ok(DatabaseController { client }) + } } } diff --git a/src/controllers/mod.rs b/src/controllers/mod.rs deleted file mode 100644 index 8fd0a6b..0000000 --- a/src/controllers/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod database; diff --git a/src/internals/mod.rs b/src/internals.rs similarity index 74% rename from src/internals/mod.rs rename to src/internals.rs index 0dfd5fa..396515a 100644 --- a/src/internals/mod.rs +++ b/src/internals.rs @@ -1,3 +1,4 @@ -pub mod utils; +pub mod config; pub mod http; pub mod tsclient; +pub mod utils; diff --git a/src/internals/config.rs b/src/internals/config.rs new file mode 100644 index 0000000..f5605a1 --- /dev/null +++ b/src/internals/config.rs @@ -0,0 +1,60 @@ +use once_cell::sync::Lazy; + +pub struct ConfigMeta { + pub guild_id: u64, + pub embed_color: i32, + pub ready_notify: u64, + pub deploy_commands: bool, + pub developers: Vec +} + +#[cfg(feature = "production")] +pub static BINARY_PROPERTIES: Lazy = Lazy::new(|| ConfigMeta::new()); + +#[cfg(not(feature = "production"))] +pub static BINARY_PROPERTIES: Lazy = Lazy::new(|| + ConfigMeta::new() + .guild_id(865673694184996885) + .embed_color(0xf1d63c) + .ready_notify(865673694184996888) + .deploy_commands(false) +); + +impl ConfigMeta { + fn new() -> Self { + Self { + guild_id: 865673694184996885, + embed_color: 0x5a99c7, + ready_notify: 865673694184996888, + deploy_commands: false, + developers: vec![ + 190407856527376384 // toast.ts + ] + } + } + + // Scalable functions below; + #[cfg(not(feature = "production"))] + fn guild_id(mut self, guild_id: u64) -> Self { + self.guild_id = guild_id; + self + } + + #[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 deploy_commands(mut self, deploy: bool) -> Self { + self.deploy_commands = deploy; + self + } +} diff --git a/src/internals/http.rs b/src/internals/http.rs index 8ac5156..5d4911a 100644 --- a/src/internals/http.rs +++ b/src/internals/http.rs @@ -1,30 +1,26 @@ -use std::sync::Arc; -use once_cell::sync::Lazy; +use std::time::Duration; use reqwest::{ Client, - header::USER_AGENT + Response, + Error }; -static CUSTOM_USER_AGENT: Lazy = Lazy::new(|| - format!("Kon/{}/Rust", super::utils::BOT_VERSION.as_str()) -); - -pub struct HttpClient { - client: Arc -} +pub struct HttpClient(Client); impl HttpClient { pub fn new() -> Self { - Self { - client: Arc::new(Client::new()) - } + Self(Client::new()) } - pub async fn get(&self, url: &str) -> Result { - let req = self.client.get(url) - .header(USER_AGENT, CUSTOM_USER_AGENT.as_str()) + pub async fn get(&self, url: &str, ua: &str) -> Result { + Ok( + self.0.get(url).header( + reqwest::header::USER_AGENT, + format!("Kon ({}) - {}/reqwest", super::utils::BOT_VERSION.as_str(), ua) + ) + .timeout(Duration::from_secs(15)) .send() - .await?; - Ok(req) + .await? + ) } } diff --git a/src/internals/tsclient.rs b/src/internals/tsclient.rs index 2473441..4737901 100644 --- a/src/internals/tsclient.rs +++ b/src/internals/tsclient.rs @@ -1,19 +1,36 @@ -use tokenservice_client::{TokenService, TokenServiceApi}; +use once_cell::sync::Lazy; +use tokio::sync::RwLock; +use tokenservice_client::{ + TokenService, + TokenServiceApi +}; -pub struct TSClient { - client: TokenService -} +static TS_GLOBAL_CACHE: Lazy>> = Lazy::new(|| RwLock::new(None)); + +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].as_str() } else { "kon" }; - TSClient { - client: TokenService::new(service) + let service = if args.len() > 1 { &args[1] } else { "kon" }; + Self(TokenService::new(service)) + } + + pub async fn get(&self) -> Result { + { + let cache = TS_GLOBAL_CACHE.read().await; + if let Some(ref api) = *cache { + return Ok(api.clone()); + } + } + + match self.0.connect().await { + Ok(api) => { + let mut cache = TS_GLOBAL_CACHE.write().await; + *cache = Some(api.clone()); + Ok(api) + } + Err(e) => Err(e) } } - pub async fn get(&self) -> Result> { - let api = self.client.connect().await.unwrap(); - Ok(api) - } } diff --git a/src/internals/utils.rs b/src/internals/utils.rs index 6f8699c..736151a 100644 --- a/src/internals/utils.rs +++ b/src/internals/utils.rs @@ -1,10 +1,10 @@ use once_cell::sync::Lazy; +use tokio::sync::Mutex; use tokenservice_client::TokenServiceApi; - -pub static EMBED_COLOR: i32 = 0x5a99c7; +use super::tsclient::TSClient; pub static BOT_VERSION: Lazy = Lazy::new(|| { - let cargo_version = cargo_toml::Manifest::from_path("./Cargo.toml") + let cargo_version = cargo_toml::Manifest::from_str(&include_str!("../../Cargo.toml")) .unwrap() .package .unwrap() @@ -13,9 +13,10 @@ pub static BOT_VERSION: Lazy = Lazy::new(|| { format!("v{}", cargo_version) }); +static TSCLIENT: Lazy> = Lazy::new(|| Mutex::new(TSClient::new())); + pub async fn token_path() -> TokenServiceApi { - let client = super::tsclient::TSClient::new().get().await.unwrap(); - client + TSCLIENT.lock().await.get().await.unwrap() } pub fn concat_message(messages: Vec) -> String { diff --git a/src/main.rs b/src/main.rs index 8376117..975ec36 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,57 +1,89 @@ mod commands; mod controllers; -mod models; mod internals; +// https://cdn.toast-server.net/RustFSHiearchy.png +// Using the new filesystem hierarchy -use std::{ - env::var, - error +use crate::{ + internals::{ + utils::token_path, + config::BINARY_PROPERTIES + }, + // controllers::database::DatabaseController }; + +use std::error; use poise::serenity_prelude::{ builder::{ CreateMessage, CreateEmbed, CreateEmbedAuthor }, - Context, Ready, + Context, + FullEvent, ClientBuilder, ChannelId, Command, + UserId, GatewayIntents }; type Error = Box; -static BOT_READY_NOTIFY: u64 = 865673694184996888; - async fn on_ready( ctx: &Context, ready: &Ready, framework: &poise::Framework<(), Error> ) -> Result<(), Error> { - println!("Connected to API as {}", ready.user.name); + #[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]: Connected to API as {}", ready.user.name); let message = CreateMessage::new(); let ready_embed = CreateEmbed::new() - .color(internals::utils::EMBED_COLOR) + .color(BINARY_PROPERTIES.embed_color) .thumbnail(ready.user.avatar_url().unwrap_or_default()) - .author(CreateEmbedAuthor::new(format!("{} is ready!", ready.user.name)).clone()); + .author(CreateEmbedAuthor::new(format!("{} is ready!", ready.user.name))); - ChannelId::new(BOT_READY_NOTIFY).send_message(&ctx.http, message.add_embed(ready_embed)).await?; + ChannelId::new(BINARY_PROPERTIES.ready_notify).send_message(&ctx.http, message.add_embed(ready_embed)).await?; - let register_commands = var("REGISTER_CMDS").unwrap_or_else(|_| String::from("true")).parse::().unwrap_or(true); - - if register_commands { + 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() { - println!("Registered command globally: {}", command.name); + commands_deployed.insert(command.name.clone()); }, - Err(why) => println!("Error registering commands: {:?}", why) + 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); + } + _ => {} } Ok(()) @@ -59,47 +91,60 @@ async fn on_ready( #[tokio::main] async fn main() { - let db = controllers::database::DatabaseController::new().await.expect("Failed to connect to database"); + // DatabaseController::new().await.expect("Error initializing database"); let framework = poise::Framework::builder() .options(poise::FrameworkOptions { commands: vec![ commands::ping::ping(), - commands::uptime::uptime(), commands::status::status(), - commands::gameserver::gameserver() + commands::uptime::uptime() ], pre_command: |ctx| Box::pin(async move { let get_guild_name = match ctx.guild() { Some(guild) => guild.name.clone(), - None => String::from("DM") + None => String::from("Direct Message") }; - println!("[{}] {} ran /{}", get_guild_name, ctx.author().name, ctx.command().qualified_name) + println!("Discord[{}] {} ran /{}", get_guild_name, ctx.author().name, ctx.command().qualified_name); }), on_error: |error| Box::pin(async move { match error { poise::FrameworkError::Command { error, ctx, .. } => { println!("PoiseCommandError({}): {}", ctx.command().qualified_name, error); - } + ctx.reply(format!( + "Encountered an error during command execution, ask **{}** to check console for more details!", + UserId::new(BINARY_PROPERTIES.developers[0]) + .to_user(&ctx.http()) + .await.expect("Error getting user") + .nick_in(&ctx.http(), BINARY_PROPERTIES.guild_id) + .await.expect("Error getting nickname") + )).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::UnknownInteraction { interaction, .. } => println!( + "PoiseUnknownInteractionError: {} tried to execute an unknown interaction ({})", + interaction.user.name, + interaction.data.name + ), other => println!("PoiseOtherError: {}", other) } }), initialize_owners: true, + event_handler: |ctx, event, framework, _| Box::pin(event_processor(ctx, event, framework)), ..Default::default() }) .setup(|ctx, ready, framework| Box::pin(on_ready(ctx, ready, framework))) .build(); - let mut client = ClientBuilder::new(internals::utils::token_path().await.main, GatewayIntents::GUILDS) - .framework(framework) - .await.expect("Error creating client"); - - { - let mut data = client.data.write().await; - data.insert::(db); - } + let mut client = ClientBuilder::new( + token_path().await.main, + GatewayIntents::GUILDS + ) + .framework(framework) + .await.expect("Error creating client"); if let Err(why) = client.start().await { - println!("Client error: {:?}", why); + println!("Error starting client: {:#?}", why); } } diff --git a/src/models/gameservers.rs b/src/models/gameservers.rs deleted file mode 100644 index 5e6d5a8..0000000 --- a/src/models/gameservers.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::controllers::database::DatabaseController; - -pub struct Gameservers { - pub server_name: String, - pub game_name: String, - pub guild_owner: i64, - pub ip_address: String -} - -impl Gameservers { - pub async fn list_servers(guild_id: u64) -> Result, tokio_postgres::Error> { - let client = DatabaseController::new().await?.client; - let rows = client.query(" - SELECT * FROM gameservers - WHERE guild_owner = $1 - ", &[&(guild_id as i64)]).await?; - - let mut servers = Vec::new(); - for row in rows { - servers.push(Self { - server_name: row.get("server_name"), - game_name: row.get("game_name"), - guild_owner: row.get("guild_owner"), - ip_address: row.get("ip_address") - }); - } - - Ok(servers) - } - - pub async fn add_server( - guild_id: u64, - server_name: &str, - game_name: &str, - ip_address: &str - ) -> Result<(), tokio_postgres::Error> { - let client = DatabaseController::new().await?.client; - client.execute(" - INSERT INTO gameservers (server_name, game_name, guild_owner, ip_address) - VALUES ($1, $2, $3, $4) - ", &[&server_name, &game_name, &(guild_id as i64), &ip_address]).await?; - - Ok(()) - } - - pub async fn remove_server(guild_id: u64, server_name: &str) -> Result<(), tokio_postgres::Error> { - let client = DatabaseController::new().await?.client; - client.execute(" - DELETE FROM gameservers - WHERE guild_owner = $1 AND server_name = $2 - ", &[&(guild_id as i64), &server_name]).await?; - - Ok(()) - } - - pub async fn update_server( - guild_id: u64, - server_name: &str, - game_name: &str, - ip_address: &str - ) -> Result<(), tokio_postgres::Error> { - let client = DatabaseController::new().await?.client; - client.execute(" - UPDATE gameservers - SET game_name = $1, ip_address = $2 - WHERE guild_owner = $3 AND server_name = $4 - ", &[&game_name, &ip_address, &(guild_id as i64), &server_name]).await?; - - Ok(()) - } - - pub async fn get_server_names(guild_id: u64) -> Result, tokio_postgres::Error> { - let client = DatabaseController::new().await?.client; - let rows = client.query(" - SELECT server_name FROM gameservers - WHERE guild_owner = $1 - ", &[&(guild_id as i64)]).await?; - - let mut servers = Vec::new(); - for row in rows { - servers.push(row.get("server_name")); - } - - Ok(servers) - } - - pub async fn get_server_data(guild_id: u64, server_name: &str) -> Result, tokio_postgres::Error> { - let client = DatabaseController::new().await?.client; - let rows = client.query(" - SELECT * FROM gameservers - WHERE guild_owner = $1 AND server_name = $2 - ", &[&(guild_id as i64), &server_name]).await?; - - let mut server = Vec::new(); - for row in rows { - server.push(row.get("server_name")); - server.push(row.get("game_name")); - server.push(row.get("ip_address")) - } - - Ok(server) - } -} diff --git a/src/models/mod.rs b/src/models/mod.rs deleted file mode 100644 index ca6994a..0000000 --- a/src/models/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod gameservers;