diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 45c68e2..3c1ed9d 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -23,4 +23,4 @@ jobs: no-test: "true" secrets: | DISCORD_TOKEN = '${{ secrets.DISCORD_TOKEN }}' - GUILD_ID = '${{ secrets.GUILD_ID }}' \ No newline at end of file + GUILD_ID = '${{ secrets.GUILD_ID }}' diff --git a/Cargo.lock b/Cargo.lock index f5be311..d91ab03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,18 +113,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "axum" @@ -160,7 +160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", @@ -175,12 +175,46 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower", "tower-layer", "tower-service", ] +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core 0.4.3", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.2.0", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.0", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "axum-core" version = "0.3.4" @@ -198,11 +232,32 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -278,9 +333,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "camino" @@ -296,6 +351,7 @@ name = "cangrebot" version = "0.1.0" dependencies = [ "anyhow", + "axum 0.7.5", "color-eyre", "image", "parking_lot", @@ -306,7 +362,6 @@ dependencies = [ "serde_json", "serenity", "shuttle-runtime", - "shuttle-serenity", "songbird", "symphonia", "tokio", @@ -616,7 +671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -792,9 +847,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fdeflate" @@ -923,7 +978,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -1056,7 +1111,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -1075,7 +1130,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -1235,6 +1290,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.0", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -1377,7 +1433,7 @@ dependencies = [ "approx", "conv", "image", - "itertools 0.10.5", + "itertools", "nalgebra", "num", "rand 0.7.3", @@ -1404,9 +1460,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1436,20 +1492,11 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jpeg-decoder" @@ -1839,7 +1886,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -1868,7 +1915,7 @@ checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" dependencies = [ "futures-core", "futures-sink", - "indexmap 2.2.6", + "indexmap 2.2.5", "js-sys", "once_cell", "pin-project-lite", @@ -2041,7 +2088,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -2079,7 +2126,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -2129,7 +2176,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -2242,10 +2289,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -2412,14 +2459,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.6", - "regex-syntax 0.8.3", + "regex-syntax 0.8.2", ] [[package]] @@ -2439,7 +2486,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.3", + "regex-syntax 0.8.2", ] [[package]] @@ -2450,9 +2497,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" @@ -2485,7 +2532,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", @@ -2531,7 +2578,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", @@ -2689,9 +2736,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868e20fada228fefaf6b652e00cc73623d54f8171e7352c18bb281571f2d92da" +checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" [[package]] name = "rustls-webpki" @@ -2808,7 +2855,7 @@ dependencies = [ "ego-tree", "getopts", "html5ever", - "indexmap 2.2.6", + "indexmap 2.2.5", "once_cell", "selectors", "tendril", @@ -2923,20 +2970,30 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.18" @@ -2945,7 +3002,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -3047,7 +3104,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -3115,16 +3172,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "shuttle-serenity" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a951e067cf3f497c88671ff8145f22d0da7db3252960a20c9f1aa7b23eae75" -dependencies = [ - "serenity", - "shuttle-runtime", -] - [[package]] name = "shuttle-service" version = "0.42.0" @@ -3392,7 +3439,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -3499,9 +3546,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -3514,6 +3561,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384595c11a4e2969895cad5a8c4029115f5ab956a9e5ef4de79d11a426e5f20c" + [[package]] name = "system-configuration" version = "0.5.1" @@ -3581,7 +3634,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -3688,7 +3741,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -3813,7 +3866,7 @@ checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.7", "bytes", "h2 0.3.25", @@ -3884,7 +3937,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -4148,7 +4201,7 @@ checksum = "0b122284365ba8497be951b9a21491f70c9688eb6fddc582931a0703f6a00ece" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] @@ -4319,7 +4372,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", "wasm-bindgen-shared", ] @@ -4353,7 +4406,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4646,7 +4699,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.53", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1fc31c7..536a1eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,15 +2,26 @@ name = "cangrebot" version = "0.1.0" edition = "2021" -authors = ["Sergio Meneses ", "Daniel Solarte "] +authors = [ + "Sergio Meneses ", + "Daniel Solarte ", +] description = "A Discord Bot made with Rust from RustLangEs Community" readme = "README.md" [dependencies] anyhow = "1.0.66" -shuttle-serenity = "0.42.0" shuttle-runtime = "0.42.0" -serenity = { version = "=0.12.0", default-features = true, features = ["cache", "framework", "client", "gateway", "rustls_backend", "model", "standard_framework", "voice"] } +serenity = { version = "=0.12.0", default-features = true, features = [ + "cache", + "framework", + "client", + "gateway", + "rustls_backend", + "model", + "standard_framework", + "voice", +] } #shuttle-secrets = "0.42.0" tokio = "1.26.0" tracing = "0.1.37" @@ -20,10 +31,19 @@ serde_json = "1.0.105" songbird = { version = "0.4.1", features = ["serenity"] } #shuttle-static-folder = "0.42.0" reqwest = { version = "0.12.2", features = ["json"] } -scraper = { version = "0.19.0", features = ["indexmap", "deterministic", "atomic"] } +scraper = { version = "0.19.0", features = [ + "indexmap", + "deterministic", + "atomic", +] } plantita_welcomes = { git = "https://github.com/CrawKatt/plantita_welcomes.git" } image = "0.24.7" -symphonia = { version = "0.5.3", default-features = false, features = ["mp3", "ogg", "wav"] } +symphonia = { version = "0.5.3", default-features = false, features = [ + "mp3", + "ogg", + "wav", +] } +axum = "0.7.5" [dependencies.parking_lot] version = "0.12" diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..e66ac57 --- /dev/null +++ b/default.nix @@ -0,0 +1,55 @@ +let + inherit + (builtins) + currentSystem + fromJSON + readFile + ; + getFlake = name: + with (fromJSON (readFile ./flake.lock)).nodes.${name}.locked; { + inherit rev; + outPath = fetchTarball { + url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; + sha256 = narHash; + }; + }; +in + { + system ? currentSystem, + pkgs ? import (getFlake "nixpkgs") {localSystem = {inherit system;};}, + lib ? pkgs.lib, + crane, + cranix, + fenix, + ... + }: let + # fenix: rustup replacement for reproducible builds + toolchain = fenix.${system}.fromToolchainFile { + file = ./rust-toolchain.toml; + sha256 = "sha256-e4mlaJehWBymYxJGgnbuCObVlqMlQSilZ8FljG9zPHY="; + }; + # crane: cargo and artifacts manager + craneLib = crane.${system}.overrideToolchain toolchain; + # cranix: extends crane building system with workspace bin building and Mold + Cranelift integrations + cranixLib = craneLib.overrideScope' (cranix.${system}.craneOverride); + + # buildInputs for Examples + buildInputs = with pkgs; [ + openssl + libopus + ]; + in { + # `nix develop` + devShells.default = cranixLib.devShell { + depsBuildBuild = [ pkgs.stdenv.cc ]; + packages = with pkgs; + [ + cmake + toolchain + pkg-config + cargo-shuttle + ] + ++ buildInputs; + LD_LIBRARY_PATH = lib.makeLibraryPath buildInputs; + }; + } diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..71ce339 --- /dev/null +++ b/flake.lock @@ -0,0 +1,219 @@ +{ + "nodes": { + "crane": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1710886643, + "narHash": "sha256-saTZuv9YeZ9COHPuj8oedGdUwJZcbQ3vyRqe7NVJMsQ=", + "owner": "ipetkov", + "repo": "crane", + "rev": "5bace74e9a65165c918205cf67ad3977fe79c584", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "cranix": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1705985690, + "narHash": "sha256-O5l2+lryVuT8ByokNrpv+NJreFKTt1jIIwdNg4kHAxI=", + "owner": "Lemin-n", + "repo": "cranix", + "rev": "2af6b2e71577bb8836b10e28f3267f2c5342a8fd", + "type": "github" + }, + "original": { + "owner": "Lemin-n", + "repo": "cranix", + "rev": "2af6b2e71577bb8836b10e28f3267f2c5342a8fd", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": "nixpkgs_3", + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1710829337, + "narHash": "sha256-uDsDTHN7hlx1k9OCukv1DQ9LoTXiM6joTXNV+6LLY1E=", + "owner": "nix-community", + "repo": "fenix", + "rev": "c3383b4ebf6191410babd6c11b4be5e295ec69b1", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1710827359, + "narHash": "sha256-/KY8hffTh9SN/tTcDn/FrEiYwTXnU8NKnr4D7/stmmA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5710127d9693421e78cca4f74fac2db6d67162b1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1705677747, + "narHash": "sha256-eyM3okYtMgYDgmYukoUzrmuoY4xl4FUujnsv/P6I/zI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bbe7d8f876fbbe7c959c90ba2ae2852220573261", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1710631334, + "narHash": "sha256-rL5LSYd85kplL5othxK5lmAtjyMOBg390sGBTb3LRMM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "c75037bbf9093a2acb617804ee46320d6d1fea5a", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1710806803, + "narHash": "sha256-qrxvLS888pNJFwJdK+hf1wpRCSQcqA6W5+Ox202NDa0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b06025f1533a1e07b6db3e75151caa155d1c7eb3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "cranix": "cranix", + "fenix": "fenix", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_4" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1710800801, + "narHash": "sha256-MYfxHeKLAhgwgha88ON0SkpNmydpg3Ib93Qny6RQZao=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "4de0204d58125392aa14d4f224b29f3c54a274e5", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..30676b3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,31 @@ +{ + description = "cangrebot"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + cranix.url = "github:Lemin-n/cranix/2af6b2e71577bb8836b10e28f3267f2c5342a8fd"; + crane.url = "github:ipetkov/crane"; + fenix.url = "github:nix-community/fenix"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + ... + } @ inputs: + # Iterate over Arm, x86 for MacOs 🍎 and Linux 🐧 + flake-utils.lib.eachSystem (flake-utils.lib.defaultSystems) ( + system: let + cangrebotBundle = import ./. { + inherit system; + pkgs = nixpkgs.legacyPackages.${system}; + crane = inputs.crane.lib; + cranix = inputs.cranix.lib; + fenix = inputs.fenix.packages; + }; + in { + inherit (cangrebotBundle) apps devShells; + } + ); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..0cb2df4 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "stable" +profile = "default" +targets = ["wasm32-unknown-unknown"] diff --git a/src/config/setup.rs b/src/config/setup.rs index 98653b5..df1efd2 100644 --- a/src/config/setup.rs +++ b/src/config/setup.rs @@ -3,16 +3,16 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::anyhow; +use serenity::framework::standard::Configuration; +use serenity::framework::{standard::macros::hook, StandardFramework}; +use serenity::model::channel::Message; +use serenity::prelude::*; use shuttle_runtime::SecretStore; use songbird::driver::Bitrate; -use songbird::SerenityInit; use songbird::input::cached::Compressed; use songbird::input::File; -use serenity::prelude::*; -use serenity::framework::{StandardFramework, standard::macros::hook}; -use serenity::framework::standard::Configuration; -use serenity::model::channel::Message; -use tracing::{instrument, info}; +use songbird::SerenityInit; +use tracing::{info, instrument}; use crate::config::songbird_config::{CachedSound, SoundStore}; @@ -20,43 +20,47 @@ use super::general_command_loader::GENERAL_GROUP; use super::slash_command_loader::Handler; -pub async fn setup( secret_store: SecretStore, public_folder: PathBuf) -> Result { +pub async fn setup( + secret_store: SecretStore, + public_folder: PathBuf, +) -> Result { // Get the discord token set in `Secrets.toml` - let token = if let Some(token) = secret_store.get("DISCORD_TOKEN") { - token - } else { - return Err(anyhow!("'DISCORD_TOKEN' was not found")); - }; + let token = if let Some(token) = secret_store.get("DISCORD_TOKEN") { + token + } else { + return Err(anyhow!("'DISCORD_TOKEN' was not found")); + }; - let prefix = secret_store.get("DISCORD_PREFIX").unwrap_or("!".to_string()); + let prefix = secret_store + .get("DISCORD_PREFIX") + .unwrap_or("!".to_string()); - let framework = StandardFramework::new() + let framework = StandardFramework::new() .unrecognised_command(unknown_command) .group(&GENERAL_GROUP) .before(before); - framework.configure(Configuration::new().prefix(prefix)); + framework.configure(Configuration::new().prefix(prefix)); + + info!("Starting bot with token: {}", token); + // Set gateway intents, which decides what events the bot will be notified about + let intents = GatewayIntents::all(); - info!("Starting bot with token: {}", token); - - // Set gateway intents, which decides what events the bot will be notified about - let intents = - GatewayIntents::all(); - - info!("{:?}", secret_store.get("GUILD_ID")); + info!("{:?}", secret_store.get("GUILD_ID")); - let Some(guild_id) = secret_store.get("GUILD_ID") else { - return Err(anyhow!("'GUILD_ID' was not found")); - }; - let handler = Handler(guild_id.parse().unwrap()); + let Some(guild_id) = secret_store.get("GUILD_ID") else { + return Err(anyhow!("'GUILD_ID' was not found")); + }; - let client = Client::builder(token, intents) - .event_handler(handler) - .framework(framework) - .register_songbird() - .await - .expect("Error creating client"); + let handler = Handler::new(guild_id.parse().unwrap()); + + let client = Client::builder(token, intents) + .event_handler(handler) + .framework(framework) + .register_songbird() + .await + .expect("Error creating client"); // Obtain a lock to the data owned by the client, and insert the client's // voice manager into it. This allows the voice manager to be accessible by // event handlers and framework commands. @@ -64,12 +68,11 @@ pub async fn setup( secret_store: SecretStore, public_folder: PathBuf) -> Result let mut data = client.data.write().await; // Loading the audio ahead of time. - let mut audio_map = HashMap::new(); - - load_sound_file(&mut audio_map, &public_folder, "loop", "loop.mp3").await; - load_sound_file(&mut audio_map, &public_folder, "ting", "ting.mp3").await; - load_sound_file(&mut audio_map, &public_folder, "song", "Cloudkicker_-_Loops_-_22_2011_07.mp3").await; + let audio_map = HashMap::new(); + // load_sound_file(&mut audio_map, &public_folder, "loop", "loop.mp3").await; + // load_sound_file(&mut audio_map, &public_folder, "ting", "ting.mp3").await; + // load_sound_file(&mut audio_map, &public_folder, "song", "Cloudkicker_-_Loops_-_22_2011_07.mp3").await; data.insert::(Arc::new(Mutex::new(audio_map))); } @@ -77,43 +80,13 @@ pub async fn setup( secret_store: SecretStore, public_folder: PathBuf) -> Result Ok(client) } - -async fn load_sound_file(audio_map: &mut HashMap, public_folder: &PathBuf, sound: &str, song_file: &str) { - // Creation of a compressed source. - // - // This is a full song, making this a much less memory-heavy choice. - // - // Music by Cloudkicker, used under CC BY-SC-SA 3.0 (https://creativecommons.org/licenses/by-nc-sa/3.0/). - let src = public_folder.clone().join(song_file); - let file = File::new(src); - let song_src = Compressed::new( - file.into(), - Bitrate::Auto, - ) - .await - .expect("These parameters are well-defined."); - let _ = song_src.raw.spawn_loader(); - - // Compressed sources are internally stored as DCA1 format files. - // Because `Compressed` implements `std::io::Read`, we can save these - // to disk and use them again later if we want! - let mut creator = song_src.new_handle(); - - let song_file_compressed = song_file.replace("mp3", "dca"); - - std::thread::spawn(move || { - let mut out_file = std::fs::File::create(&song_file_compressed).unwrap(); - std::io::copy(&mut creator, &mut out_file).expect("Error writing out song!"); - }); - - audio_map.insert(sound.into(), CachedSound::Compressed(song_src)); -} - - #[hook] #[instrument] pub async fn before(_: &Context, msg: &Message, command_name: &str) -> bool { - info!("Got command '{}' by user '{}'", command_name, msg.author.name); + info!( + "Got command '{}' by user '{}'", + command_name, msg.author.name + ); true } @@ -121,4 +94,4 @@ pub async fn before(_: &Context, msg: &Message, command_name: &str) -> bool { #[hook] pub async fn unknown_command(_ctx: &Context, _msg: &Message, unknown_command_name: &str) { info!("Could not find command named '{}'", unknown_command_name); -} \ No newline at end of file +} diff --git a/src/config/slash_command_loader.rs b/src/config/slash_command_loader.rs index 5bd6831..ea27116 100644 --- a/src/config/slash_command_loader.rs +++ b/src/config/slash_command_loader.rs @@ -1,28 +1,34 @@ +use std::net::{IpAddr, SocketAddr}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; + +use crate::events::daily_challenge::{run_daily_challenge, DailyChallengeRequest}; use crate::{events::join::guild_member_addition, slash_commands}; use serenity::{ + all::{Command, CreateInteractionResponse, CreateInteractionResponseMessage}, async_trait, - all::{ - Command, - CreateInteractionResponse, - CreateInteractionResponseMessage - }, - model::prelude::{ - Interaction, - GuildId, Member, Ready, - }, + model::prelude::{GuildId, Interaction, Member, Ready}, prelude::{Context, EventHandler}, }; use tracing::{error, log::info}; +use crate::slash_commands::ping; use slash_commands::attachmentinput::run as attachmentinput_run; use slash_commands::explica::run as explica_run; use slash_commands::id::run as id_run; use slash_commands::invite::run as invite_run; use slash_commands::ping::run as ping_run; use slash_commands::sugerencia; -use crate::slash_commands::ping; -pub struct Handler(pub u64); +pub struct Handler { + guild_id: u64, +} + +impl Handler { + pub fn new(guild_id: u64) -> Self { + Self { guild_id } + } +} #[async_trait] impl EventHandler for Handler { @@ -47,15 +53,14 @@ impl EventHandler for Handler { &command.data.options, &command.user, ) - .await + .await } _ => "not implemented :(".to_string(), }; let data = CreateInteractionResponseMessage::new().content(content); let builder = CreateInteractionResponse::Message(data); - if let Err(why) = command.create_response(&ctx.http, builder).await - { + if let Err(why) = command.create_response(&ctx.http, builder).await { info!("Cannot respond to slash command: {}", why); } } @@ -64,20 +69,21 @@ impl EventHandler for Handler { async fn ready(&self, ctx: Context, ready: Ready) { info!("{} is connected!", ready.user.name); - let guild_id = GuildId::new(self.0); + let guild_id = GuildId::new(self.guild_id.into()); - if let Err(error) = guild_id.set_commands( - &ctx.http, - vec![ - slash_commands::explica::register(), - ping::register(), - slash_commands::id::register(), - slash_commands::invite::register(), - slash_commands::welcome::register(), - slash_commands::attachmentinput::register(), - sugerencia::register(), - ], - ) + if let Err(error) = guild_id + .set_commands( + &ctx.http, + vec![ + slash_commands::explica::register(), + ping::register(), + slash_commands::id::register(), + slash_commands::invite::register(), + slash_commands::welcome::register(), + slash_commands::attachmentinput::register(), + sugerencia::register(), + ], + ) .await { error!("Cannot create slash commands: {}", error); @@ -85,8 +91,11 @@ impl EventHandler for Handler { // info!("I now have the following guild slash commands: {:#?}", commands); - let _guild_command = Command::create_global_command(&ctx.http, slash_commands::wonderful_command::register()) - .await; + let _guild_command = Command::create_global_command( + &ctx.http, + slash_commands::wonderful_command::register(), + ) + .await; // info!("I created the following global slash command: {:#?}", guild_command); } diff --git a/src/events/daily_challenge.rs b/src/events/daily_challenge.rs new file mode 100644 index 0000000..84ac2a5 --- /dev/null +++ b/src/events/daily_challenge.rs @@ -0,0 +1,67 @@ +use std::sync::Arc; + +use axum::extract::State; +use axum::http::StatusCode; +use axum::response::IntoResponse; +use axum::Json; +use serde::{Deserialize, Serialize}; +use serenity::all::{ForumTagId, MessageFlags}; +use serenity::builder::{CreateAllowedMentions, CreateForumPost, CreateForumTag, CreateMessage}; +use serenity::http::Http; +use serenity::model::prelude::ChannelId; +use serenity::prelude::Context; +use tracing::info; + +const PARTICIPANT_ROLE: u64 = 1224238464958992495; + +#[derive(Deserialize, Serialize)] +pub struct DailyChallengeRequest { + title: String, + message: String, + tag_name: String, +} + +pub async fn run_daily_challenge( + State(ctx): State>, + Json(DailyChallengeRequest { + title, + message, + tag_name, + }): Json, +) -> impl IntoResponse { + info!("Running create suggestion"); + let msg_channel = ChannelId::new(1219703076944871616_u64.into()); + + let Ok(forum) = msg_channel.to_channel(&ctx).await else { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + "Cannot convert to channel", + ); + }; + let Some(forum) = forum.guild() else { + return (StatusCode::NOT_FOUND, "GuildId not found"); + }; + let Some(tag) = forum.available_tags.iter().find(|t| t.name == tag_name) else { + return (StatusCode::NOT_FOUND, "Tag not found"); + }; + + match msg_channel + .create_forum_post( + &ctx, + CreateForumPost::new( + title, + CreateMessage::new() + .content(message) + .allowed_mentions(CreateAllowedMentions::new().roles([PARTICIPANT_ROLE])), + ) + .add_applied_tag(tag.id), + ) + .await + { + Ok(_) => (StatusCode::OK, "Ok"), + Err(_) => ( + StatusCode::INTERNAL_SERVER_ERROR, + "Cannot Create Forum Post", + ), + } +} diff --git a/src/events/mod.rs b/src/events/mod.rs index ed92ceb..87dcc03 100644 --- a/src/events/mod.rs +++ b/src/events/mod.rs @@ -1 +1,2 @@ -pub mod join; \ No newline at end of file +pub mod join; +pub mod daily_challenge; diff --git a/src/main.rs b/src/main.rs index 21e6fa8..124f2c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,12 @@ -use std::path::PathBuf; +use axum::{Router, ServiceExt}; +use events::daily_challenge::run_daily_challenge; +use serenity::http::Http; +use serenity::prelude::Context; +use serenity::Client; use shuttle_runtime::SecretStore; +use std::net::SocketAddr; +use std::path::PathBuf; +use std::sync::Arc; pub mod config; pub mod events; @@ -7,16 +14,52 @@ pub mod general_commands; pub mod slash_commands; use config::setup::setup; +pub struct CustomService { + discord_bot: Client, + router: Router, +} + +#[shuttle_runtime::async_trait] +impl shuttle_runtime::Service for CustomService { + async fn bind(mut self, addr: SocketAddr) -> Result<(), shuttle_runtime::Error> { + let router = self.router.into_service(); + + let listener = tokio::net::TcpListener::bind(&addr).await?; + let serve_router = async move { + axum::serve(listener, router.into_make_service()) + .await + .unwrap(); + }; + + tokio::select! { + _ = self.discord_bot.start_autosharded() => {}, + _ = serve_router => {}, + }; + + Ok(()) + } +} + +fn build_router(ctx: Arc) -> Router { + Router::new() + .route("/daily_challenge", axum::routing::post(run_daily_challenge)) + .with_state(ctx) +} + #[shuttle_runtime::main] -async fn serenity( +async fn init( #[shuttle_runtime::Secrets] secret_store: SecretStore, -) -> shuttle_serenity::ShuttleSerenity { +) -> Result { let Ok(_) = color_eyre::install() else { panic!("Failed to install color_eyre"); }; let public_folder = PathBuf::from("static"); - let client = setup(secret_store,public_folder).await?; + let discord_bot = setup(secret_store, public_folder).await?; + let router = build_router(discord_bot.http.clone()); - Ok(client.into()) + Ok(CustomService { + discord_bot, + router, + }) }