From bb54c0d2c031639563b9cc9cfb043ae6f289a1c5 Mon Sep 17 00:00:00 2001 From: jellywx Date: Tue, 25 Jan 2022 22:59:05 +0000 Subject: [PATCH] lots of things and stuff --- Cargo.lock | 973 +++++++++++++++++---------- Cargo.toml | 7 +- regex_command_attr/Cargo.toml | 15 - regex_command_attr/src/attributes.rs | 408 ----------- regex_command_attr/src/consts.rs | 6 - regex_command_attr/src/lib.rs | 173 ----- regex_command_attr/src/structures.rs | 359 ---------- regex_command_attr/src/util.rs | 239 ------- src/cmds/info.rs | 213 +----- src/cmds/manage.rs | 253 ++----- src/cmds/mod.rs | 6 +- src/cmds/play.rs | 481 +++---------- src/cmds/search.rs | 9 +- src/event_handlers.rs | 241 +++---- src/framework.rs | 735 -------------------- src/guild_data.rs | 30 +- src/main.rs | 276 +++----- src/sound.rs | 51 +- 18 files changed, 988 insertions(+), 3487 deletions(-) delete mode 100644 regex_command_attr/Cargo.toml delete mode 100644 regex_command_attr/src/attributes.rs delete mode 100644 regex_command_attr/src/consts.rs delete mode 100644 regex_command_attr/src/lib.rs delete mode 100644 regex_command_attr/src/structures.rs delete mode 100644 regex_command_attr/src/util.rs delete mode 100644 src/framework.rs diff --git a/Cargo.lock b/Cargo.lock index f9baebc..d8c1cd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,9 +20,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom", "once_cell", @@ -38,6 +38,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "arrayvec" version = "0.4.12" @@ -49,31 +58,15 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "async-tungstenite" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b30ef0ea5c20caaa54baea49514a206308989c68be7ecd86c7f956e4da6378" -dependencies = [ - "futures-io", - "futures-util", - "log", - "pin-project-lite", - "tokio", - "tokio-rustls", - "tungstenite", - "webpki-roots", -] - [[package]] name = "async-tungstenite" version = "0.14.0" @@ -85,9 +78,25 @@ dependencies = [ "log", "pin-project-lite", "tokio", - "tokio-rustls", - "tungstenite", - "webpki-roots", + "tokio-rustls 0.22.0", + "tungstenite 0.13.0", + "webpki-roots 0.21.1", +] + +[[package]] +name = "async-tungstenite" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5682ea0913e5c20780fe5785abacb85a411e7437bf52a1bedb93ddb3972cb8dd" +dependencies = [ + "futures-io", + "futures-util", + "log", + "pin-project-lite", + "tokio", + "tokio-rustls 0.23.2", + "tungstenite 0.16.0", + "webpki-roots 0.22.2", ] [[package]] @@ -147,13 +156,19 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "base64ct" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" + [[package]] name = "bigdecimal" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1e50562e37200edf7c6c43e54a08e64a5553bfb59d9c297d5572512aa517256" dependencies = [ - "num-bigint 0.3.3", + "num-bigint", "num-integer", "num-traits 0.2.14", ] @@ -175,9 +190,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "byteorder" @@ -193,15 +208,9 @@ checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.70" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -219,7 +228,6 @@ dependencies = [ "num-integer", "num-traits 0.2.14", "serde", - "time", "winapi", ] @@ -233,20 +241,16 @@ dependencies = [ ] [[package]] -name = "command_attr" -version = "0.3.7" -source = "git+https://github.com/serenity-rs/serenity?branch=next#723749c43182838925dd89ac90b93dd2a837261d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +name = "const-oid" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" [[package]] name = "core-foundation" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" dependencies = [ "core-foundation-sys", "libc", @@ -254,9 +258,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" @@ -269,54 +273,132 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "a2209c310e29876f7f0b2721e7e26b84aff178aa3da5d091f9bfbf47669e60e3" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-queue" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +checksum = "b979d76c9fcb84dffc80a73f7290da0f83e4c95773494674cb44b76d13a7a110" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] +[[package]] +name = "crypto-bigint" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" +dependencies = [ + "generic-array", + "rand_core", + "subtle", +] + +[[package]] +name = "darling" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "dashmap" version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "num_cpus", +] + +[[package]] +name = "dashmap" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b799062aaf67eb976af3bdca031ee6f846d2f0a5710ddbb0d2efee33f3cc4760" +dependencies = [ + "cfg-if", + "num_cpus", + "parking_lot", "serde", ] +[[package]] +name = "der" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" +dependencies = [ + "const-oid", + "crypto-bigint", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.9.0" @@ -350,11 +432,11 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "encoding_rs" -version = "0.8.28" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -379,13 +461,22 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "flate2" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crc32fast", "libc", "miniz_oxide", @@ -393,9 +484,9 @@ dependencies = [ [[package]] name = "flume" -version = "0.10.9" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24c3fd473b3a903a62609e413ed7538f99e10b665ecb502b5e481a95283f8ab4" +checksum = "5d04dafd11240188e146b6f6476a898004cace3be31d4ec5e08e216bf4947ac0" dependencies = [ "futures-core", "futures-sink", @@ -437,9 +528,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" dependencies = [ "futures-channel", "futures-core", @@ -452,9 +543,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" dependencies = [ "futures-core", "futures-sink", @@ -462,15 +553,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" dependencies = [ "futures-core", "futures-task", @@ -490,18 +581,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" dependencies = [ - "autocfg 1.0.1", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -509,23 +598,22 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" dependencies = [ - "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -535,16 +623,14 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] [[package]] name = "generator" -version = "0.6.25" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061d3be1afec479d56fa3bd182bf966c7999ec175fcfdb87ac14d417241366c6" +checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" dependencies = [ "cc", "libc", @@ -555,9 +641,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -565,11 +651,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi", @@ -578,9 +664,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.4" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f3675cfef6a30c8031cf9e6493ebdc3bb3272a3fea3923c4210d1830e6a472" +checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689" dependencies = [ "bytes", "fnv", @@ -639,20 +725,20 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 1.0.1", ] [[package]] name = "http-body" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" dependencies = [ "bytes", "http", @@ -667,9 +753,9 @@ checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] name = "httpdate" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "humantime" @@ -679,9 +765,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.13" +version = "0.14.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593" +checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ "bytes", "futures-channel", @@ -692,7 +778,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 0.4.8", "pin-project-lite", "socket2", "tokio", @@ -703,17 +789,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ - "futures-util", + "http", "hyper", - "log", - "rustls", + "rustls 0.20.2", "tokio", - "tokio-rustls", - "webpki", + "tokio-rustls 0.23.2", ] [[package]] @@ -729,6 +813,12 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -742,9 +832,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg 1.0.1", "hashbrown", @@ -761,11 +851,11 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -776,9 +866,9 @@ checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "itertools" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] @@ -790,10 +880,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] -name = "js-sys" -version = "0.3.55" +name = "itoa" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "js-sys" +version = "0.3.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" dependencies = [ "wasm-bindgen", ] @@ -809,9 +905,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.102" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" +checksum = "b0005d08a8f7b65fb8073cb697aa0b12b631ed251ce73d862ce50eeb52ce3b50" [[package]] name = "libm" @@ -834,20 +930,31 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] name = "loom" -version = "0.3.6" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" +checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "generator", "scoped-tls", "serde", "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", ] [[package]] @@ -880,9 +987,9 @@ dependencies = [ [[package]] name = "minimal-lexical" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" @@ -896,9 +1003,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ "libc", "log", @@ -951,9 +1058,9 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "nom" -version = "7.0.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ "memchr", "minimal-lexical", @@ -980,17 +1087,6 @@ dependencies = [ "num-traits 0.2.14", ] -[[package]] -name = "num-bigint" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535" -dependencies = [ - "autocfg 1.0.1", - "num-integer", - "num-traits 0.2.14", -] - [[package]] name = "num-bigint-dig" version = "0.7.0" @@ -1051,9 +1147,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -1061,9 +1157,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "opaque-debug" @@ -1073,12 +1169,12 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.36" +version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ "bitflags", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -1087,15 +1183,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.66" +version = "0.9.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" dependencies = [ "autocfg 1.0.1", "cc", @@ -1121,7 +1217,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "instant", "libc", "redox_syscall", @@ -1130,14 +1226,12 @@ dependencies = [ ] [[package]] -name = "pem" -version = "0.8.3" +name = "pem-rfc7468" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +checksum = "84e93a3b1cc0510b03020f33f21e62acdde3dcaef432edc95bea377fbd4c2cd4" dependencies = [ - "base64", - "once_cell", - "regex", + "base64ct", ] [[package]] @@ -1148,18 +1242,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" dependencies = [ "proc-macro2", "quote", @@ -1168,9 +1262,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] name = "pin-utils" @@ -1179,10 +1273,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.19" +name = "pkcs1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "116bee8279d783c0cf370efa1a94632f2108e5ef0bb32df31f051647810a4e2c" +dependencies = [ + "der", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "pkcs8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" +dependencies = [ + "der", + "pem-rfc7468", + "pkcs1", + "spki", + "zeroize", +] + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "pnet_base" @@ -1211,6 +1329,32 @@ dependencies = [ "pnet_base", ] +[[package]] +name = "poise" +version = "0.1.0" +source = "git+https://github.com/kangalioo/poise?branch=master#9ebc7b541b2deca8efde1c8bcbdf3d415d8e3a9a" +dependencies = [ + "async-trait", + "futures-core", + "futures-util", + "once_cell", + "poise_macros", + "regex", + "serenity", + "tokio", +] + +[[package]] +name = "poise_macros" +version = "0.1.0" +source = "git+https://github.com/kangalioo/poise?branch=master#9ebc7b541b2deca8efde1c8bcbdf3d415d8e3a9a" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "poly1305" version = "0.7.2" @@ -1224,36 +1368,24 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ "proc-macro2", ] @@ -1318,21 +1450,21 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "regex_command_attr" -version = "0.3.6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "remove_dir_all" version = "0.5.3" @@ -1344,15 +1476,16 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.4" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" +checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", "futures-util", + "h2", "http", "http-body", "hyper", @@ -1367,18 +1500,20 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.20.2", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.23.2", + "tokio-util", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.22.2", "winreg", ] @@ -1399,9 +1534,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0aeddcca1082112a6eeb43bf25fd7820b066aaf6eaef776e19d0a1febe38fe" +checksum = "e05c2603e2823634ab331437001b411b9ed11660fbc4066f3908c84a9439260d" dependencies = [ "byteorder", "digest", @@ -1410,9 +1545,9 @@ dependencies = [ "num-integer", "num-iter", "num-traits 0.2.14", - "pem", + "pkcs1", + "pkcs8", "rand", - "simple_asn1", "subtle", "zeroize", ] @@ -1426,21 +1561,42 @@ dependencies = [ "base64", "log", "ring", - "sct", - "webpki", + "sct 0.6.1", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +dependencies = [ + "log", + "ring", + "sct 0.7.0", + "webpki 0.22.0", +] + +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", ] [[package]] name = "rustversion" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "salsa20" @@ -1485,10 +1641,20 @@ dependencies = [ ] [[package]] -name = "security-framework" -version = "2.4.2" +name = "sct" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d09d3c15d814eda1d6a836f2f2b56a6abc1446c8a34351cb3180d3db92ffe4ce" dependencies = [ "bitflags", "core-foundation", @@ -1499,9 +1665,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +checksum = "e90dd10c41c6bfc633da6e0c659bd25d31e0791e5974ac42970267d59eba87f7" dependencies = [ "core-foundation-sys", "libc", @@ -1509,18 +1675,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.130" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -1529,11 +1695,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "d23c1ba4cf0efd44be32017709280b32d1cea5c3f1275c3b6d9e8bc54f758085" dependencies = [ - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -1551,29 +1717,28 @@ dependencies = [ [[package]] name = "serde_urlencoded" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa", + "itoa 1.0.1", "ryu", "serde", ] [[package]] name = "serenity" -version = "0.10.9" -source = "git+https://github.com/serenity-rs/serenity?branch=next#723749c43182838925dd89ac90b93dd2a837261d" +version = "0.10.10" +source = "git+https://github.com/serenity-rs/serenity?branch=next#ad78ab6543c8671f005246c89ce2651bf4809375" dependencies = [ "async-trait", - "async-tungstenite 0.13.1", + "async-tungstenite 0.16.1", "base64", "bitflags", "bytes", "chrono", - "command_attr", - "dashmap", + "dashmap 5.0.0", "flate2", "futures", "mime", @@ -1583,18 +1748,16 @@ dependencies = [ "reqwest", "serde", "serde_json", - "static_assertions", "tokio", "tracing", "typemap_rev", "url", - "uwl", ] [[package]] name = "serenity-voice-model" -version = "0.1.0" -source = "git+https://github.com/serenity-rs/serenity?branch=next#723749c43182838925dd89ac90b93dd2a837261d" +version = "0.1.1" +source = "git+https://github.com/serenity-rs/serenity?branch=next#ad78ab6543c8671f005246c89ce2651bf4809375" dependencies = [ "bitflags", "enum_primitive", @@ -1610,7 +1773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", "opaque-debug", @@ -1618,17 +1781,26 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", "opaque-debug", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1638,35 +1810,23 @@ dependencies = [ "libc", ] -[[package]] -name = "simple_asn1" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80" -dependencies = [ - "chrono", - "num-bigint 0.4.2", - "num-traits 0.2.14", - "thiserror", -] - [[package]] name = "slab" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "socket2" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +checksum = "0f82496b90c36d70af5fcd482edaa2e0bd16fade569de1330405fecbbdac736b" dependencies = [ "libc", "winapi", @@ -1674,14 +1834,15 @@ dependencies = [ [[package]] name = "songbird" -version = "0.2.0" -source = "git+https://github.com/serenity-rs/songbird?branch=next#a953430810cc3f08d609ad6f76f7708f457703fc" +version = "0.2.1" +source = "git+https://github.com/serenity-rs/songbird?branch=next#d3f0974412d217e7047c9681ba85d0217d79e741" dependencies = [ "async-trait", "async-tungstenite 0.14.0", "audiopus", "byteorder", - "dashmap", + "dashmap 4.0.2", + "derivative", "discortp", "flume", "futures", @@ -1706,18 +1867,17 @@ dependencies = [ [[package]] name = "soundfx-rs" -version = "1.4.3" +version = "1.5.0" dependencies = [ - "dashmap", + "dashmap 4.0.2", "dotenv", "env_logger", "lazy_static", "log", + "poise", "regex", - "regex_command_attr", "reqwest", "serde_json", - "serenity", "songbird", "sqlx", "tokio", @@ -1748,6 +1908,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "spki" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" +dependencies = [ + "der", +] + [[package]] name = "sqlformat" version = "0.1.8" @@ -1761,9 +1930,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4b94ab0f8c21ee4899b93b06451ef5d965f1a355982ee73684338228498440" +checksum = "692749de69603d81e016212199d73a2e14ee20e2def7d7914919e8db5d4d48b9" dependencies = [ "sqlx-core", "sqlx-macros", @@ -1771,13 +1940,12 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec28b91a01e1fe286d6ba66f68289a2286df023fc97444e1fd86c2fd6d5dc026" +checksum = "518be6f6fff5ca76f985d434f9c37f3662af279642acf730388f271dff7b9016" dependencies = [ "ahash", "atoi", - "base64", "bigdecimal", "bitflags", "byteorder", @@ -1794,17 +1962,18 @@ dependencies = [ "generic-array", "hashlink", "hex", - "itoa", + "indexmap", + "itoa 1.0.1", "libc", "log", "memchr", - "num-bigint 0.3.3", + "num-bigint", "once_cell", "parking_lot", "percent-encoding", "rand", "rsa", - "rustls", + "rustls 0.19.1", "sha-1", "sha2", "smallvec", @@ -1814,20 +1983,18 @@ dependencies = [ "thiserror", "tokio-stream", "url", - "webpki", - "webpki-roots", - "whoami", + "webpki 0.21.4", + "webpki-roots 0.21.1", ] [[package]] name = "sqlx-macros" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33c35d54774eed73d54568d47a6ac099aed8af5e1556a017c131be88217d5" +checksum = "38e45140529cf1f90a5e1c2e561500ca345821a1c513652c8f486bbf07407cc8" dependencies = [ "dotenv", "either", - "futures", "heck", "once_cell", "proc-macro2", @@ -1840,26 +2007,20 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14302b678d9c76b28f2e60115211e25e0aabc938269991745a169753dc00e35c" +checksum = "8061cbaa91ee75041514f67a09398c65a64efed72c90151ecd47593bad53da99" dependencies = [ "once_cell", "tokio", - "tokio-rustls", + "tokio-rustls 0.22.0", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "streamcatcher" -version = "0.1.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9501b1be04455a53f782940f7ca17050482de0a6e322c1ff606afc0ebbc62674" +checksum = "71664755c349abb0758fda6218fb2d2391ca2a73f9302c03b145491db4fcea29" dependencies = [ "crossbeam-utils", "futures-util", @@ -1876,6 +2037,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.4.1" @@ -1897,9 +2064,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.76" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ "proc-macro2", "quote", @@ -1908,9 +2075,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", @@ -1920,13 +2087,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "fastrand", "libc", - "rand", "redox_syscall", "remove_dir_all", "winapi", @@ -1943,18 +2110,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -1962,20 +2129,19 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.1.43" +name = "thread_local" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ - "libc", - "winapi", + "once_cell", ] [[package]] name = "tinyvec" -version = "1.4.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5241dd6f21443a3606b432718b166d3cedc962fd4b8bea54a8bc7f514ebda986" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -1988,11 +2154,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.11.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "autocfg 1.0.1", "bytes", "libc", "memchr", @@ -2007,9 +2172,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", @@ -2032,16 +2197,27 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "rustls", + "rustls 0.19.1", "tokio", - "webpki", + "webpki 0.21.4", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +dependencies = [ + "rustls 0.20.2", + "tokio", + "webpki 0.22.0", ] [[package]] name = "tokio-stream" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ "futures-core", "pin-project-lite", @@ -2050,9 +2226,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ "bytes", "futures-core", @@ -2070,11 +2246,11 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.27" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba9ab62b7d6497a8638dfda5e5c4fb3b2d5a7fca4118f2b96151c8ef1a437e" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2083,9 +2259,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.16" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98863d0dd09fa59a1b79c6750ad80dbda6b75f4e71c437a6a1a8cb91a8bcbd77" +checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ "proc-macro2", "quote", @@ -2094,9 +2270,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] @@ -2111,6 +2287,35 @@ dependencies = [ "tracing", ] +[[package]] +name = "tracing-log" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5312f325fe3588e277415f5a6cca1f4ccad0f248c4cd5a4bd33032d7286abc22" +dependencies = [ + "ansi_term", + "lazy_static", + "matchers", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -2131,13 +2336,34 @@ dependencies = [ "input_buffer", "log", "rand", - "rustls", + "rustls 0.19.1", "sha-1", "thiserror", "url", "utf-8", - "webpki", - "webpki-roots", + "webpki 0.21.4", + "webpki-roots 0.21.1", +] + +[[package]] +name = "tungstenite" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "rustls 0.20.2", + "sha-1", + "thiserror", + "url", + "utf-8", + "webpki 0.22.0", ] [[package]] @@ -2148,9 +2374,9 @@ checksum = "ed5b74f0a24b5454580a79abb6994393b09adf0ab8070f15827cb666255de155" [[package]] name = "typenum" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unicase" @@ -2163,9 +2389,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-normalization" @@ -2238,12 +2464,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "uwl" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4bf03e0ca70d626ecc4ba6b0763b934b6f2976e8c744088bb3c1d646fbb1ad0" - [[package]] name = "vcpkg" version = "0.2.15" @@ -2252,9 +2472,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" @@ -2274,21 +2494,19 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ - "cfg-if 1.0.0", - "serde", - "serde_json", + "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" dependencies = [ "bumpalo", "lazy_static", @@ -2301,11 +2519,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -2313,9 +2531,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2323,9 +2541,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" dependencies = [ "proc-macro2", "quote", @@ -2336,15 +2554,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2360,23 +2578,32 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki-roots" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ - "webpki", + "webpki 0.21.4", ] [[package]] -name = "whoami" -version = "1.1.3" +name = "webpki-roots" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7741161a40200a867c96dfa5574544efa4178cf4c8f770b62dd1cc0362d7ae1" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" dependencies = [ - "wasm-bindgen", - "web-sys", + "webpki 0.22.0", ] [[package]] @@ -2444,9 +2671,9 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.1.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1" +checksum = "81e8f13fef10b63c06356d65d416b070798ddabcadc10d3ece0c5be9b3c7eddb" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index ed3dd3b..015bd0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "soundfx-rs" -version = "1.4.3" +version = "1.5.0" authors = ["jellywx "] edition = "2018" [dependencies] songbird = { git = "https://github.com/serenity-rs/songbird", branch = "next" } -serenity = { git = "https://github.com/serenity-rs/serenity", branch = "next", features = ["voice", "collector", "unstable_discord_api"] } +poise = { git = "https://github.com/kangalioo/poise", branch = "master", features = ["collector"] } sqlx = { version = "0.5", default-features = false, features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal"] } dotenv = "0.15" tokio = { version = "1", features = ["fs", "process", "io-util"] } @@ -17,6 +17,3 @@ regex = "1.4" log = "0.4" serde_json = "1.0" dashmap = "4.0" - -[dependencies.regex_command_attr] -path = "./regex_command_attr" diff --git a/regex_command_attr/Cargo.toml b/regex_command_attr/Cargo.toml deleted file mode 100644 index 24e5fa5..0000000 --- a/regex_command_attr/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "regex_command_attr" -version = "0.3.6" -authors = ["acdenisSK ", "jellywx "] -edition = "2018" -description = "Procedural macros for command creation for the Serenity library." -license = "ISC" - -[lib] -proc-macro = true - -[dependencies] -quote = "^1.0" -syn = { version = "^1.0", features = ["full", "derive", "extra-traits"] } -proc-macro2 = "1.0" diff --git a/regex_command_attr/src/attributes.rs b/regex_command_attr/src/attributes.rs deleted file mode 100644 index f9522b3..0000000 --- a/regex_command_attr/src/attributes.rs +++ /dev/null @@ -1,408 +0,0 @@ -use std::fmt::{self, Write}; - -use proc_macro2::Span; -use syn::parse::{Error, Result}; -use syn::spanned::Spanned; -use syn::{Attribute, Ident, Lit, LitStr, Meta, NestedMeta, Path}; - -use crate::structures::{ApplicationCommandOptionType, Arg, CommandKind, PermissionLevel}; -use crate::util::{AsOption, LitExt}; - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum ValueKind { - // #[] - Name, - - // #[ = ] - Equals, - - // #[([, , , ...])] - List, - - // #[([ = , = , ...])] - EqualsList, - - // #[()] - SingleList, -} - -impl fmt::Display for ValueKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ValueKind::Name => f.pad("`#[]`"), - ValueKind::Equals => f.pad("`#[ = ]`"), - ValueKind::List => f.pad("`#[([, , , ...])]`"), - ValueKind::EqualsList => { - f.pad("`#[([ = , = , ...])]`") - } - ValueKind::SingleList => f.pad("`#[()]`"), - } - } -} - -fn to_ident(p: Path) -> Result { - if p.segments.is_empty() { - return Err(Error::new( - p.span(), - "cannot convert an empty path to an identifier", - )); - } - - if p.segments.len() > 1 { - return Err(Error::new( - p.span(), - "the path must not have more than one segment", - )); - } - - if !p.segments[0].arguments.is_empty() { - return Err(Error::new( - p.span(), - "the singular path segment must not have any arguments", - )); - } - - Ok(p.segments[0].ident.clone()) -} - -#[derive(Debug)] -pub struct Values { - pub name: Ident, - pub literals: Vec<(Option, Lit)>, - pub kind: ValueKind, - pub span: Span, -} - -impl Values { - #[inline] - pub fn new( - name: Ident, - kind: ValueKind, - literals: Vec<(Option, Lit)>, - span: Span, - ) -> Self { - Values { - name, - literals, - kind, - span, - } - } -} - -pub fn parse_values(attr: &Attribute) -> Result { - fn is_list_or_named_list(meta: &NestedMeta) -> ValueKind { - match meta { - // catch if the nested value is a literal value - NestedMeta::Lit(_) => ValueKind::List, - // catch if the nested value is a meta value - NestedMeta::Meta(m) => match m { - // path => some quoted value - Meta::Path(_) => ValueKind::List, - Meta::List(_) | Meta::NameValue(_) => ValueKind::EqualsList, - }, - } - } - - let meta = attr.parse_meta()?; - - match meta { - Meta::Path(path) => { - let name = to_ident(path)?; - - Ok(Values::new(name, ValueKind::Name, Vec::new(), attr.span())) - } - Meta::List(meta) => { - let name = to_ident(meta.path)?; - let nested = meta.nested; - - if nested.is_empty() { - return Err(Error::new(attr.span(), "list cannot be empty")); - } - - if is_list_or_named_list(nested.first().unwrap()) == ValueKind::List { - let mut lits = Vec::with_capacity(nested.len()); - - for meta in nested { - match meta { - // catch if the nested value is a literal value - NestedMeta::Lit(l) => lits.push((None, l)), - // catch if the nested value is a meta value - NestedMeta::Meta(m) => match m { - // path => some quoted value - Meta::Path(path) => { - let i = to_ident(path)?; - lits.push((None, Lit::Str(LitStr::new(&i.to_string(), i.span())))) - } - Meta::List(_) | Meta::NameValue(_) => { - return Err(Error::new(attr.span(), "cannot nest a list; only accept literals and identifiers at this level")) - } - }, - } - } - - let kind = if lits.len() == 1 { - ValueKind::SingleList - } else { - ValueKind::List - }; - - Ok(Values::new(name, kind, lits, attr.span())) - } else { - let mut lits = Vec::with_capacity(nested.len()); - - for meta in nested { - match meta { - // catch if the nested value is a literal value - NestedMeta::Lit(_) => { - return Err(Error::new(attr.span(), "key-value pairs expected")) - } - // catch if the nested value is a meta value - NestedMeta::Meta(m) => match m { - Meta::NameValue(n) => { - let name = to_ident(n.path)?.to_string(); - let value = n.lit; - - lits.push((Some(name), value)); - } - Meta::List(_) | Meta::Path(_) => { - return Err(Error::new(attr.span(), "key-value pairs expected")) - } - }, - } - } - - Ok(Values::new(name, ValueKind::EqualsList, lits, attr.span())) - } - } - Meta::NameValue(meta) => { - let name = to_ident(meta.path)?; - let lit = meta.lit; - - Ok(Values::new( - name, - ValueKind::Equals, - vec![(None, lit)], - attr.span(), - )) - } - } -} - -#[derive(Debug, Clone)] -struct DisplaySlice<'a, T>(&'a [T]); - -impl<'a, T: fmt::Display> fmt::Display for DisplaySlice<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut iter = self.0.iter().enumerate(); - - match iter.next() { - None => f.write_str("nothing")?, - Some((idx, elem)) => { - write!(f, "{}: {}", idx, elem)?; - - for (idx, elem) in iter { - f.write_char('\n')?; - write!(f, "{}: {}", idx, elem)?; - } - } - } - - Ok(()) - } -} - -#[inline] -fn is_form_acceptable(expect: &[ValueKind], kind: ValueKind) -> bool { - if expect.contains(&ValueKind::List) && kind == ValueKind::SingleList { - true - } else { - expect.contains(&kind) - } -} - -#[inline] -fn validate(values: &Values, forms: &[ValueKind]) -> Result<()> { - if !is_form_acceptable(forms, values.kind) { - return Err(Error::new( - values.span, - // Using the `_args` version here to avoid an allocation. - format_args!( - "the attribute must be in of these forms:\n{}", - DisplaySlice(forms) - ), - )); - } - - Ok(()) -} - -#[inline] -pub fn parse(values: Values) -> Result { - T::parse(values) -} - -pub trait AttributeOption: Sized { - fn parse(values: Values) -> Result; -} - -impl AttributeOption for Vec { - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::List])?; - - Ok(values - .literals - .into_iter() - .map(|(_, l)| l.to_str()) - .collect()) - } -} - -impl AttributeOption for String { - #[inline] - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::Equals, ValueKind::SingleList])?; - - Ok(values.literals[0].1.to_str()) - } -} - -impl AttributeOption for bool { - #[inline] - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::Name, ValueKind::SingleList])?; - - Ok(values.literals.get(0).map_or(true, |(_, l)| l.to_bool())) - } -} - -impl AttributeOption for Ident { - #[inline] - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::SingleList])?; - - Ok(values.literals[0].1.to_ident()) - } -} - -impl AttributeOption for Vec { - #[inline] - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::List])?; - - Ok(values - .literals - .into_iter() - .map(|(_, l)| l.to_ident()) - .collect()) - } -} - -impl AttributeOption for Option { - fn parse(values: Values) -> Result { - validate( - &values, - &[ValueKind::Name, ValueKind::Equals, ValueKind::SingleList], - )?; - - Ok(values.literals.get(0).map(|(_, l)| l.to_str())) - } -} - -impl AttributeOption for PermissionLevel { - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::SingleList])?; - - Ok(values - .literals - .get(0) - .map(|(_, l)| PermissionLevel::from_str(&*l.to_str()).unwrap()) - .unwrap()) - } -} - -impl AttributeOption for CommandKind { - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::SingleList])?; - - Ok(values - .literals - .get(0) - .map(|(_, l)| CommandKind::from_str(&*l.to_str()).unwrap()) - .unwrap()) - } -} - -impl AttributeOption for Arg { - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::EqualsList])?; - - let mut arg: Arg = Default::default(); - - for (key, value) in &values.literals { - match key { - Some(s) => match s.as_str() { - "name" => { - arg.name = value.to_str(); - } - "description" => { - arg.description = value.to_str(); - } - "required" => { - arg.required = value.to_bool(); - } - "kind" => arg.kind = ApplicationCommandOptionType::from_str(value.to_str()), - _ => { - return Err(Error::new(key.span(), "unexpected attribute")); - } - }, - _ => { - return Err(Error::new(key.span(), "unnamed attribute")); - } - } - } - - Ok(arg) - } -} - -impl AttributeOption for AsOption { - #[inline] - fn parse(values: Values) -> Result { - Ok(AsOption(Some(T::parse(values)?))) - } -} - -macro_rules! attr_option_num { - ($($n:ty),*) => { - $( - impl AttributeOption for $n { - fn parse(values: Values) -> Result { - validate(&values, &[ValueKind::SingleList])?; - - Ok(match &values.literals[0].1 { - Lit::Int(l) => l.base10_parse::<$n>()?, - l => { - let s = l.to_str(); - // Use `as_str` to guide the compiler to use `&str`'s parse method. - // We don't want to use our `parse` method here (`impl AttributeOption for String`). - match s.as_str().parse::<$n>() { - Ok(n) => n, - Err(_) => return Err(Error::new(l.span(), "invalid integer")), - } - } - }) - } - } - - impl AttributeOption for Option<$n> { - #[inline] - fn parse(values: Values) -> Result { - <$n as AttributeOption>::parse(values).map(Some) - } - } - )* - } -} - -attr_option_num!(u16, u32, usize); diff --git a/regex_command_attr/src/consts.rs b/regex_command_attr/src/consts.rs deleted file mode 100644 index 9235297..0000000 --- a/regex_command_attr/src/consts.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod suffixes { - pub const COMMAND: &str = "COMMAND"; - pub const ARG: &str = "ARG"; -} - -pub use self::suffixes::*; diff --git a/regex_command_attr/src/lib.rs b/regex_command_attr/src/lib.rs deleted file mode 100644 index 2ae6b0f..0000000 --- a/regex_command_attr/src/lib.rs +++ /dev/null @@ -1,173 +0,0 @@ -#![deny(rust_2018_idioms)] -#![deny(broken_intra_doc_links)] - -use proc_macro::TokenStream; -use proc_macro2::Ident; -use quote::quote; -use syn::{parse::Error, parse_macro_input, parse_quote, spanned::Spanned, Lit}; - -pub(crate) mod attributes; -pub(crate) mod consts; -pub(crate) mod structures; - -#[macro_use] -pub(crate) mod util; - -use attributes::*; -use consts::*; -use structures::*; -use util::*; - -macro_rules! match_options { - ($v:expr, $values:ident, $options:ident, $span:expr => [$($name:ident);*]) => { - match $v { - $( - stringify!($name) => $options.$name = propagate_err!($crate::attributes::parse($values)), - )* - _ => { - return Error::new($span, format_args!("invalid attribute: {:?}", $v)) - .to_compile_error() - .into(); - }, - } - }; -} - -#[proc_macro_attribute] -pub fn command(attr: TokenStream, input: TokenStream) -> TokenStream { - let mut fun = parse_macro_input!(input as CommandFun); - - let _name = if !attr.is_empty() { - parse_macro_input!(attr as Lit).to_str() - } else { - fun.name.to_string() - }; - - let mut options = Options::new(); - - for attribute in &fun.attributes { - let span = attribute.span(); - let values = propagate_err!(parse_values(attribute)); - - let name = values.name.to_string(); - let name = &name[..]; - - match name { - "arg" => options - .cmd_args - .push(propagate_err!(attributes::parse(values))), - "example" => { - options - .examples - .push(propagate_err!(attributes::parse(values))); - } - "description" => { - let line: String = propagate_err!(attributes::parse(values)); - util::append_line(&mut options.description, line); - } - _ => { - match_options!(name, values, options, span => [ - aliases; - group; - required_permissions; - kind - ]); - } - } - } - - let Options { - aliases, - description, - group, - examples, - required_permissions, - kind, - mut cmd_args, - } = options; - - propagate_err!(create_declaration_validations(&mut fun)); - - let res = parse_quote!(serenity::framework::standard::CommandResult); - create_return_type_validation(&mut fun, res); - - let visibility = fun.visibility; - let name = fun.name.clone(); - let body = fun.body; - let ret = fun.ret; - - let n = name.with_suffix(COMMAND); - - let cooked = fun.cooked.clone(); - - let command_path = quote!(crate::framework::Command); - let arg_path = quote!(crate::framework::Arg); - - populate_fut_lifetimes_on_refs(&mut fun.args); - let args = fun.args; - - let arg_idents = cmd_args - .iter() - .map(|arg| { - n.with_suffix(arg.name.replace(" ", "_").replace("-", "_").as_str()) - .with_suffix(ARG) - }) - .collect::>(); - - let mut tokens = cmd_args - .iter_mut() - .map(|arg| { - let Arg { - name, - description, - kind, - required, - } = arg; - - let an = n.with_suffix(name.as_str()).with_suffix(ARG); - - quote! { - #(#cooked)* - #[allow(missing_docs)] - pub static #an: #arg_path = #arg_path { - name: #name, - description: #description, - kind: #kind, - required: #required, - }; - } - }) - .fold(quote! {}, |mut a, b| { - a.extend(b); - a - }); - - tokens.extend(quote! { - #(#cooked)* - #[allow(missing_docs)] - pub static #n: #command_path = #command_path { - fun: #name, - names: &[#_name, #(#aliases),*], - desc: #description, - group: #group, - examples: &[#(#examples),*], - required_permissions: #required_permissions, - kind: #kind, - args: &[#(&#arg_idents),*], - }; - - #(#cooked)* - #[allow(missing_docs)] - #visibility fn #name<'fut> (#(#args),*) -> ::serenity::futures::future::BoxFuture<'fut, #ret> { - use ::serenity::futures::future::FutureExt; - - async move { - let _output: #ret = { #(#body)* }; - #[allow(unreachable_code)] - _output - }.boxed() - } - }); - - tokens.into() -} diff --git a/regex_command_attr/src/structures.rs b/regex_command_attr/src/structures.rs deleted file mode 100644 index 0cab491..0000000 --- a/regex_command_attr/src/structures.rs +++ /dev/null @@ -1,359 +0,0 @@ -use proc_macro2::TokenStream as TokenStream2; -use quote::{quote, ToTokens}; -use syn::{ - braced, - parse::{Error, Parse, ParseStream, Result}, - spanned::Spanned, - Attribute, Block, FnArg, Ident, Pat, ReturnType, Stmt, Token, Type, Visibility, -}; - -use crate::util::{self, Argument, Parenthesised}; - -fn parse_argument(arg: FnArg) -> Result { - match arg { - FnArg::Typed(typed) => { - let pat = typed.pat; - let kind = typed.ty; - - match *pat { - Pat::Ident(id) => { - let name = id.ident; - let mutable = id.mutability; - - Ok(Argument { - mutable, - name, - kind: *kind, - }) - } - Pat::Wild(wild) => { - let token = wild.underscore_token; - - let name = Ident::new("_", token.spans[0]); - - Ok(Argument { - mutable: None, - name, - kind: *kind, - }) - } - _ => Err(Error::new( - pat.span(), - format_args!("unsupported pattern: {:?}", pat), - )), - } - } - FnArg::Receiver(_) => Err(Error::new( - arg.span(), - format_args!("`self` arguments are prohibited: {:?}", arg), - )), - } -} - -/// Test if the attribute is cooked. -fn is_cooked(attr: &Attribute) -> bool { - const COOKED_ATTRIBUTE_NAMES: &[&str] = &[ - "cfg", "cfg_attr", "derive", "inline", "allow", "warn", "deny", "forbid", - ]; - - COOKED_ATTRIBUTE_NAMES.iter().any(|n| attr.path.is_ident(n)) -} - -/// Removes cooked attributes from a vector of attributes. Uncooked attributes are left in the vector. -/// -/// # Return -/// -/// Returns a vector of cooked attributes that have been removed from the input vector. -fn remove_cooked(attrs: &mut Vec) -> Vec { - let mut cooked = Vec::new(); - - // FIXME: Replace with `Vec::drain_filter` once it is stable. - let mut i = 0; - while i < attrs.len() { - if !is_cooked(&attrs[i]) { - i += 1; - continue; - } - - cooked.push(attrs.remove(i)); - } - - cooked -} - -#[derive(Debug)] -pub struct CommandFun { - /// `#[...]`-style attributes. - pub attributes: Vec, - /// Populated cooked attributes. These are attributes outside of the realm of this crate's procedural macros - /// and will appear in generated output. - pub cooked: Vec, - pub visibility: Visibility, - pub name: Ident, - pub args: Vec, - pub ret: Type, - pub body: Vec, -} - -impl Parse for CommandFun { - fn parse(input: ParseStream<'_>) -> Result { - let mut attributes = input.call(Attribute::parse_outer)?; - - // Rename documentation comment attributes (`#[doc = "..."]`) to `#[description = "..."]`. - util::rename_attributes(&mut attributes, "doc", "description"); - - let cooked = remove_cooked(&mut attributes); - - let visibility = input.parse::()?; - - input.parse::()?; - - input.parse::()?; - let name = input.parse()?; - - // (...) - let Parenthesised(args) = input.parse::>()?; - - let ret = match input.parse::()? { - ReturnType::Type(_, t) => (*t).clone(), - ReturnType::Default => { - return Err(input - .error("expected a result type of either `CommandResult` or `CheckResult`")) - } - }; - - // { ... } - let bcont; - braced!(bcont in input); - let body = bcont.call(Block::parse_within)?; - - let args = args - .into_iter() - .map(parse_argument) - .collect::>>()?; - - Ok(Self { - attributes, - cooked, - visibility, - name, - args, - ret, - body, - }) - } -} - -impl ToTokens for CommandFun { - fn to_tokens(&self, stream: &mut TokenStream2) { - let Self { - attributes: _, - cooked, - visibility, - name, - args, - ret, - body, - } = self; - - stream.extend(quote! { - #(#cooked)* - #visibility async fn #name (#(#args),*) -> #ret { - #(#body)* - } - }); - } -} - -#[derive(Debug)] -pub enum PermissionLevel { - Unrestricted, - Managed, - Restricted, -} - -impl Default for PermissionLevel { - fn default() -> Self { - Self::Unrestricted - } -} - -impl PermissionLevel { - pub fn from_str(s: &str) -> Option { - Some(match s.to_uppercase().as_str() { - "UNRESTRICTED" => Self::Unrestricted, - "MANAGED" => Self::Managed, - "RESTRICTED" => Self::Restricted, - _ => return None, - }) - } -} - -impl ToTokens for PermissionLevel { - fn to_tokens(&self, stream: &mut TokenStream2) { - let path = quote!(crate::framework::PermissionLevel); - let variant; - - match self { - Self::Unrestricted => { - variant = quote!(Unrestricted); - } - - Self::Managed => { - variant = quote!(Managed); - } - - Self::Restricted => { - variant = quote!(Restricted); - } - } - - stream.extend(quote! { - #path::#variant - }); - } -} - -#[derive(Debug)] -pub enum CommandKind { - Slash, - Both, - Text, -} - -impl Default for CommandKind { - fn default() -> Self { - Self::Both - } -} - -impl CommandKind { - pub fn from_str(s: &str) -> Option { - Some(match s.to_uppercase().as_str() { - "SLASH" => Self::Slash, - "BOTH" => Self::Both, - "TEXT" => Self::Text, - _ => return None, - }) - } -} - -impl ToTokens for CommandKind { - fn to_tokens(&self, stream: &mut TokenStream2) { - let path = quote!(crate::framework::CommandKind); - let variant; - - match self { - Self::Slash => { - variant = quote!(Slash); - } - - Self::Both => { - variant = quote!(Both); - } - - Self::Text => { - variant = quote!(Text); - } - } - - stream.extend(quote! { - #path::#variant - }); - } -} - -#[derive(Debug)] -pub(crate) enum ApplicationCommandOptionType { - SubCommand, - SubCommandGroup, - String, - Integer, - Boolean, - User, - Channel, - Role, - Mentionable, - Unknown, -} - -impl ApplicationCommandOptionType { - pub fn from_str(s: String) -> Self { - match s.as_str() { - "SubCommand" => Self::SubCommand, - "SubCommandGroup" => Self::SubCommandGroup, - "String" => Self::String, - "Integer" => Self::Integer, - "Boolean" => Self::Boolean, - "User" => Self::User, - "Channel" => Self::Channel, - "Role" => Self::Role, - "Mentionable" => Self::Mentionable, - _ => Self::Unknown, - } - } -} - -impl ToTokens for ApplicationCommandOptionType { - fn to_tokens(&self, stream: &mut TokenStream2) { - let path = quote!( - serenity::model::interactions::application_command::ApplicationCommandOptionType - ); - let variant = match self { - ApplicationCommandOptionType::SubCommand => quote!(SubCommand), - ApplicationCommandOptionType::SubCommandGroup => quote!(SubCommandGroup), - ApplicationCommandOptionType::String => quote!(String), - ApplicationCommandOptionType::Integer => quote!(Integer), - ApplicationCommandOptionType::Boolean => quote!(Boolean), - ApplicationCommandOptionType::User => quote!(User), - ApplicationCommandOptionType::Channel => quote!(Channel), - ApplicationCommandOptionType::Role => quote!(Role), - ApplicationCommandOptionType::Mentionable => quote!(Mentionable), - ApplicationCommandOptionType::Unknown => quote!(Unknown), - }; - - stream.extend(quote! { - #path::#variant - }); - } -} - -#[derive(Debug)] -pub(crate) struct Arg { - pub name: String, - pub description: String, - pub kind: ApplicationCommandOptionType, - pub required: bool, -} - -impl Default for Arg { - fn default() -> Self { - Self { - name: String::new(), - description: String::new(), - kind: ApplicationCommandOptionType::String, - required: false, - } - } -} - -#[derive(Debug, Default)] -pub(crate) struct Options { - pub aliases: Vec, - pub description: String, - pub group: String, - pub examples: Vec, - pub required_permissions: PermissionLevel, - pub kind: CommandKind, - pub cmd_args: Vec, -} - -impl Options { - #[inline] - pub fn new() -> Self { - Self { - group: "Other".to_string(), - ..Default::default() - } - } -} diff --git a/regex_command_attr/src/util.rs b/regex_command_attr/src/util.rs deleted file mode 100644 index 12197d8..0000000 --- a/regex_command_attr/src/util.rs +++ /dev/null @@ -1,239 +0,0 @@ -use proc_macro::TokenStream; -use proc_macro2::Span; -use proc_macro2::TokenStream as TokenStream2; -use quote::{format_ident, quote, ToTokens}; -use syn::{ - braced, bracketed, parenthesized, - parse::{Error, Parse, ParseStream, Result as SynResult}, - parse_quote, - punctuated::Punctuated, - spanned::Spanned, - token::{Comma, Mut}, - Attribute, Ident, Lifetime, Lit, Path, PathSegment, Type, -}; - -use crate::structures::CommandFun; - -pub trait LitExt { - fn to_str(&self) -> String; - fn to_bool(&self) -> bool; - fn to_ident(&self) -> Ident; -} - -impl LitExt for Lit { - fn to_str(&self) -> String { - match self { - Lit::Str(s) => s.value(), - Lit::ByteStr(s) => unsafe { String::from_utf8_unchecked(s.value()) }, - Lit::Char(c) => c.value().to_string(), - Lit::Byte(b) => (b.value() as char).to_string(), - _ => panic!("values must be a (byte)string or a char"), - } - } - - fn to_bool(&self) -> bool { - if let Lit::Bool(b) = self { - b.value - } else { - self.to_str() - .parse() - .unwrap_or_else(|_| panic!("expected bool from {:?}", self)) - } - } - - #[inline] - fn to_ident(&self) -> Ident { - Ident::new(&self.to_str(), self.span()) - } -} - -pub trait IdentExt2: Sized { - fn to_uppercase(&self) -> Self; - fn with_suffix(&self, suf: &str) -> Ident; -} - -impl IdentExt2 for Ident { - #[inline] - fn to_uppercase(&self) -> Self { - format_ident!("{}", self.to_string().to_uppercase()) - } - - #[inline] - fn with_suffix(&self, suffix: &str) -> Ident { - format_ident!("{}_{}", self.to_string().to_uppercase(), suffix) - } -} - -#[inline] -pub fn into_stream(e: Error) -> TokenStream { - e.to_compile_error().into() -} - -macro_rules! propagate_err { - ($res:expr) => {{ - match $res { - Ok(v) => v, - Err(e) => return $crate::util::into_stream(e), - } - }}; -} - -#[derive(Debug)] -pub struct Bracketed(pub Punctuated); - -impl Parse for Bracketed { - fn parse(input: ParseStream<'_>) -> SynResult { - let content; - bracketed!(content in input); - - Ok(Bracketed(content.parse_terminated(T::parse)?)) - } -} - -#[derive(Debug)] -pub struct Braced(pub Punctuated); - -impl Parse for Braced { - fn parse(input: ParseStream<'_>) -> SynResult { - let content; - braced!(content in input); - - Ok(Braced(content.parse_terminated(T::parse)?)) - } -} - -#[derive(Debug)] -pub struct Parenthesised(pub Punctuated); - -impl Parse for Parenthesised { - fn parse(input: ParseStream<'_>) -> SynResult { - let content; - parenthesized!(content in input); - - Ok(Parenthesised(content.parse_terminated(T::parse)?)) - } -} - -#[derive(Debug)] -pub struct AsOption(pub Option); - -impl ToTokens for AsOption { - fn to_tokens(&self, stream: &mut TokenStream2) { - match &self.0 { - Some(o) => stream.extend(quote!(Some(#o))), - None => stream.extend(quote!(None)), - } - } -} - -impl Default for AsOption { - #[inline] - fn default() -> Self { - AsOption(None) - } -} - -#[derive(Debug)] -pub struct Argument { - pub mutable: Option, - pub name: Ident, - pub kind: Type, -} - -impl ToTokens for Argument { - fn to_tokens(&self, stream: &mut TokenStream2) { - let Argument { - mutable, - name, - kind, - } = self; - - stream.extend(quote! { - #mutable #name: #kind - }); - } -} - -#[inline] -pub fn generate_type_validation(have: Type, expect: Type) -> syn::Stmt { - parse_quote! { - serenity::static_assertions::assert_type_eq_all!(#have, #expect); - } -} - -pub fn create_declaration_validations(fun: &mut CommandFun) -> SynResult<()> { - if fun.args.len() > 3 { - return Err(Error::new( - fun.args.last().unwrap().span(), - format_args!("function's arity exceeds more than 3 arguments"), - )); - } - - let context: Type = parse_quote!(&serenity::client::Context); - let message: Type = parse_quote!(&(dyn crate::framework::CommandInvoke + Sync + Send)); - let args: Type = parse_quote!(crate::framework::Args); - - let mut index = 0; - - let mut spoof_or_check = |kind: Type, name: &str| { - match fun.args.get(index) { - Some(x) => fun - .body - .insert(0, generate_type_validation(x.kind.clone(), kind)), - None => fun.args.push(Argument { - mutable: None, - name: Ident::new(name, Span::call_site()), - kind, - }), - } - - index += 1; - }; - - spoof_or_check(context, "_ctx"); - spoof_or_check(message, "_msg"); - spoof_or_check(args, "_args"); - - Ok(()) -} - -#[inline] -pub fn create_return_type_validation(r#fn: &mut CommandFun, expect: Type) { - let stmt = generate_type_validation(r#fn.ret.clone(), expect); - r#fn.body.insert(0, stmt); -} - -#[inline] -pub fn populate_fut_lifetimes_on_refs(args: &mut Vec) { - for arg in args { - if let Type::Reference(reference) = &mut arg.kind { - reference.lifetime = Some(Lifetime::new("'fut", Span::call_site())); - } - } -} - -/// Renames all attributes that have a specific `name` to the `target`. -pub fn rename_attributes(attributes: &mut Vec, name: &str, target: &str) { - for attr in attributes { - if attr.path.is_ident(name) { - attr.path = Path::from(PathSegment::from(Ident::new(target, Span::call_site()))); - } - } -} - -pub fn append_line(desc: &mut String, mut line: String) { - if line.starts_with(' ') { - line.remove(0); - } - - match line.rfind("\\$") { - Some(i) => { - desc.push_str(line[..i].trim_end()); - desc.push(' '); - } - None => { - desc.push_str(&line); - desc.push('\n'); - } - } -} diff --git a/src/cmds/info.rs b/src/cmds/info.rs index 1931699..72bc8a5 100644 --- a/src/cmds/info.rs +++ b/src/cmds/info.rs @@ -1,201 +1,11 @@ -use std::{collections::HashMap, sync::Arc}; +use crate::{Context, Error, THEME_COLOR}; -use regex_command_attr::command; -use serenity::{client::Context, framework::standard::CommandResult}; +/// Get additional information about the bot +#[poise::command(slash_command, category = "Information")] +pub async fn info(ctx: Context<'_>) -> Result<(), Error> { + let current_user = ctx.discord().cache.current_user(); -use crate::{ - framework::{Args, CommandInvoke, CommandKind, CreateGenericResponse, RegexFramework}, - THEME_COLOR, -}; - -#[command] -#[group("Information")] -#[description("Get information on the commands of the bot")] -#[arg( - name = "command", - description = "Get help for a specific command", - kind = "String", - required = false -)] -#[example("`/help` - see all commands")] -#[example("`/help play` - get help about the `play` command")] -pub async fn help( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { - fn get_groups(framework: Arc) -> HashMap<&'static str, Vec<&'static str>> { - let mut groups = HashMap::new(); - - for command in &framework.commands_ { - let entry = groups.entry(command.group).or_insert(vec![]); - - entry.push(command.names[0]); - } - - groups - } - - let framework = ctx - .data - .read() - .await - .get::() - .cloned() - .unwrap(); - - if let Some(command_name) = args.named("command") { - if let Some(command) = framework.commands.get(command_name) { - let examples = if command.examples.is_empty() { - "".to_string() - } else { - format!( - "**Examples** -{}", - command - .examples - .iter() - .map(|e| format!(" • {}", e)) - .collect::>() - .join("\n") - ) - }; - - let args = if command.args.is_empty() { - "**Arguments** - • *This command has no arguments*" - .to_string() - } else { - format!( - "**Arguments** -{}", - command - .args - .iter() - .map(|a| format!( - " • `{}` {} - {}", - a.name, - if a.required { "" } else { "[optional]" }, - a.description - )) - .collect::>() - .join("\n") - ) - }; - - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().embed(|e| { - e.title(format!("{} Help", command_name)) - .color(THEME_COLOR) - .description(format!( - "**Available In** -`Slash Commands` {} -` Text Commands` {} - -**Aliases** -{} - -**Overview** - • {} -{} - -{}", - if command.kind != CommandKind::Text { - "✅" - } else { - "❎" - }, - if command.kind != CommandKind::Slash { - "✅" - } else { - "❎" - }, - command - .names - .iter() - .map(|n| format!("`{}`", n)) - .collect::>() - .join(" "), - command.desc, - args, - examples - )) - }), - ) - .await?; - } else { - let groups = get_groups(framework); - let groups_iter = groups.iter().map(|(name, commands)| { - ( - name, - commands - .iter() - .map(|c| format!("`{}`", c)) - .collect::>() - .join(" "), - true, - ) - }); - - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().embed(|e| { - e.title("Invalid Command") - .color(THEME_COLOR) - .description("Type `/help command` to view more about a command below:") - .fields(groups_iter) - }), - ) - .await?; - } - } else { - let groups = get_groups(framework); - let groups_iter = groups.iter().map(|(name, commands)| { - ( - name, - commands - .iter() - .map(|c| format!("`{}`", c)) - .collect::>() - .join(" "), - true, - ) - }); - - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().embed(|e| { - e.title("Help") - .color(THEME_COLOR) - .description("**Welcome to SoundFX!** -To get started, upload a sound with `/upload`, or use `/search` and `/play` to look at some of the public sounds - -Type `/help command` to view help about a command below:") - .fields(groups_iter) - }), - ) - .await?; - } - - Ok(()) -} - -#[command] -#[group("Information")] -#[aliases("invite")] -#[description("Get additional information on the bot")] -async fn info( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - _args: Args, -) -> CommandResult { - let current_user = ctx.cache.current_user(); - - invoke.respond(ctx.http.clone(), CreateGenericResponse::new() + ctx.send(|m| m .embed(|e| e .title("Info") .color(THEME_COLOR) @@ -211,15 +21,10 @@ Invite me: https://discord.com/api/oauth2/authorize?client_id={1}&permissions=31 Developer: <@203532103185465344> Find me on https://discord.jellywx.com/ and on https://github.com/JellyWX :) -**Sound Credits** -\"The rain falls against the parasol\" https://freesound.org/people/straget/ -\"Heavy Rain\" https://freesound.org/people/lebaston100/ -\"Rain on Windows, Interior, A\" https://freesound.org/people/InspectorJ/ -\"Seaside Waves, Close, A\" https://freesound.org/people/InspectorJ/ -\"Small River 1 - Fast - Close\" https://freesound.org/people/Pfannkuchn/ - **An online dashboard is available!** Visit https://soundfx.jellywx.com/dashboard -There is a maximum sound limit per user. This can be removed by subscribing at **https://patreon.com/jellywx**", current_user.name, current_user.id.as_u64())))).await?; +There is a maximum sound limit per user. This can be removed by subscribing at **https://patreon.com/jellywx**", + current_user.name, + current_user.id.as_u64())))).await?; Ok(()) } diff --git a/src/cmds/manage.rs b/src/cmds/manage.rs index 6406629..938619b 100644 --- a/src/cmds/manage.rs +++ b/src/cmds/manage.rs @@ -1,32 +1,15 @@ use std::time::Duration; -use regex_command_attr::command; -use serenity::{ - client::Context, - framework::standard::CommandResult, - model::id::{GuildId, RoleId}, -}; +use poise::serenity::model::id::{GuildId, RoleId}; -use crate::{ - framework::{Args, CommandInvoke, CreateGenericResponse}, - sound::Sound, - MySQL, MAX_SOUNDS, PATREON_GUILD, PATREON_ROLE, -}; +use crate::{sound::Sound, Context, Error, MAX_SOUNDS, PATREON_GUILD, PATREON_ROLE}; -#[command("upload")] -#[group("Manage")] -#[description("Upload a new sound to the bot")] -#[arg( - name = "name", - description = "Name to upload sound to", - kind = "String", - required = true -)] +/// Upload a new sound to the bot +#[poise::command(slash_command, rename = "upload", category = "Manage")] pub async fn upload_new_sound( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { + ctx: Context<'_>, + #[description = "Name to upload sound to"] name: String, +) -> Result<(), Error> { fn is_numeric(s: &String) -> bool { for char in s.chars() { if char.is_digit(10) { @@ -38,36 +21,27 @@ pub async fn upload_new_sound( true } - let new_name = args - .named("name") - .map(|n| n.to_string()) - .unwrap_or(String::new()); - - if !new_name.is_empty() && new_name.len() <= 20 { - if !is_numeric(&new_name) { - let pool = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("Could not get SQLPool from data"); + if !name.is_empty() && name.len() <= 20 { + if !is_numeric(&name) { + let pool = ctx.data().database.clone(); // need to check the name is not currently in use by the user let count_name = - Sound::count_named_user_sounds(invoke.author_id().0, &new_name, pool.clone()) - .await?; + Sound::count_named_user_sounds(ctx.author().id, &name, pool.clone()).await?; if count_name > 0 { - invoke.respond(ctx.http.clone(), CreateGenericResponse::new().content("You are already using that name. Please choose a unique name for your upload.")).await?; + ctx.say( + "You are already using that name. Please choose a unique name for your upload.", + ) + .await?; } else { // need to check how many sounds user currently has - let count = Sound::count_user_sounds(invoke.author_id().0, pool.clone()).await?; + let count = Sound::count_user_sounds(ctx.author().id, pool.clone()).await?; let mut permit_upload = true; // need to check if user is patreon or nah if count >= *MAX_SOUNDS { let patreon_guild_member = GuildId(*PATREON_GUILD) - .member(ctx, invoke.author_id()) + .member(ctx.discord(), ctx.author().id) .await; if let Ok(member) = patreon_guild_member { @@ -78,19 +52,13 @@ pub async fn upload_new_sound( } if permit_upload { - let attachment = if let Some(attachment) = invoke - .msg() - .map(|m| m.attachments.get(0).map(|a| a.url.clone())) - .flatten() - { - Some(attachment) - } else { - invoke.respond(ctx.http.clone(), CreateGenericResponse::new().content("Please now upload an audio file under 1MB in size (larger files will be automatically trimmed):")).await?; + let attachment = { + ctx.say("Please now upload an audio file under 1MB in size (larger files will be automatically trimmed):").await?; - let reply = invoke + let reply = ctx .channel_id() - .await_reply(&ctx) - .author_id(invoke.author_id()) + .await_reply(&ctx.discord()) + .author_id(ctx.author().id) .timeout(Duration::from_secs(120)) .await; @@ -99,20 +67,14 @@ pub async fn upload_new_sound( if let Some(attachment) = reply_msg.attachments.get(0) { Some(attachment.url.clone()) } else { - invoke.followup(ctx.http.clone(), CreateGenericResponse::new().content("Please upload 1 attachment following your upload command. Aborted")).await?; + ctx.say("Please upload 1 attachment following your upload command. Aborted").await?; None } } None => { - invoke - .followup( - ctx.http.clone(), - CreateGenericResponse::new() - .content("Upload timed out. Please redo the command"), - ) - .await?; + ctx.say("Upload timed out. Please redo the command").await?; None } @@ -121,91 +83,52 @@ pub async fn upload_new_sound( if let Some(url) = attachment { match Sound::create_anon( - &new_name, + &name, url.as_str(), - invoke.guild_id().unwrap().0, - invoke.author_id().0, + ctx.guild_id().unwrap(), + ctx.author().id, pool, ) .await { Ok(_) => { - invoke - .followup( - ctx.http.clone(), - CreateGenericResponse::new() - .content("Sound has been uploaded"), - ) - .await?; + ctx.say("Sound has been uploaded").await?; } Err(e) => { println!("Error occurred during upload: {:?}", e); - invoke - .followup( - ctx.http.clone(), - CreateGenericResponse::new() - .content("Sound failed to upload."), - ) - .await?; + ctx.say("Sound failed to upload.").await?; } } } } else { - invoke.respond( - ctx.http.clone(), - CreateGenericResponse::new().content(format!( + ctx.say(format!( "You have reached the maximum number of sounds ({}). Either delete some with `/delete` or join our Patreon for unlimited uploads at **https://patreon.com/jellywx**", *MAX_SOUNDS, - ))).await?; + )).await?; } } } else { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new() - .content("Please ensure the sound name contains a non-numerical character"), - ) + ctx.say("Please ensure the sound name contains a non-numerical character") .await?; } } else { - invoke.respond(ctx.http.clone(), CreateGenericResponse::new().content("Usage: `/upload `. Please ensure the name provided is less than 20 characters in length")).await?; + ctx.say("Usage: `/upload `. Please ensure the name provided is less than 20 characters in length").await?; } Ok(()) } -#[command("delete")] -#[group("Manage")] -#[description("Delete a sound you have uploaded")] -#[arg( - name = "query", - description = "Delete sound with the specified name or ID", - kind = "String", - required = true -)] -#[example("`/delete beep` - delete the sound with the name \"beep\"")] +/// Delete a sound you have uploaded +#[poise::command(slash_command, rename = "delete", category = "Manage")] pub async fn delete_sound( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { - let pool = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("Could not get SQLPool from data"); + ctx: Context<'_>, + #[description = "Name or ID of sound to delete"] name: String, +) -> Result<(), Error> { + let pool = ctx.data().database.clone(); - let uid = invoke.author_id().0; - let gid = invoke.guild_id().unwrap().0; - - let name = args - .named("query") - .map(|s| s.to_owned()) - .unwrap_or(String::new()); + let uid = ctx.author().id.0; + let gid = ctx.guild_id().unwrap().0; let sound_vec = Sound::search_for_sound(&name, gid, uid, pool.clone(), true).await?; let sound_result = sound_vec.first(); @@ -213,18 +136,12 @@ pub async fn delete_sound( match sound_result { Some(sound) => { if sound.uploader_id != Some(uid) && sound.server_id != gid { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content( - "You can only delete sounds from this guild or that you have uploaded.", - ), - ) + ctx.say("You can only delete sounds from this guild or that you have uploaded.") .await?; } else { let has_perms = { - if let Ok(member) = invoke.member(&ctx).await { - if let Ok(perms) = member.permissions(&ctx) { + if let Ok(member) = ctx.guild_id().unwrap().member(&ctx.discord(), uid).await { + if let Ok(perms) = member.permissions(&ctx.discord()) { perms.manage_guild() } else { false @@ -237,94 +154,49 @@ pub async fn delete_sound( if sound.uploader_id == Some(uid) || has_perms { sound.delete(pool).await?; - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content("Sound has been deleted"), - ) - .await?; + ctx.say("Sound has been deleted").await?; } else { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content( - "Only server admins can delete sounds uploaded by other users.", - ), - ) + ctx.say("Only server admins can delete sounds uploaded by other users.") .await?; } } } None => { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content("Sound could not be found by that name."), - ) - .await?; + ctx.say("Sound could not be found by that name.").await?; } } Ok(()) } -#[command("public")] -#[group("Manage")] -#[description("Change a sound between public and private")] -#[arg( - name = "query", - kind = "String", - description = "Sound name or ID to change the privacy setting of", - required = true -)] -#[example("`/public 12` - change sound with ID 12 to private")] -#[example("`/public 12` - change sound with ID 12 back to public")] +/// Change a sound between public and private +#[poise::command(slash_command, rename = "public", category = "Manage")] pub async fn change_public( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { - let pool = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("Could not get SQLPool from data"); + ctx: Context<'_>, + #[description = "Name or ID of sound to change privacy setting of"] name: String, +) -> Result<(), Error> { + let pool = ctx.data().database.clone(); - let uid = invoke.author_id().as_u64().to_owned(); + let uid = ctx.author().id.0; + let gid = ctx.guild_id().unwrap().0; - let name = args.named("query").unwrap(); - let gid = *invoke.guild_id().unwrap().as_u64(); - - let mut sound_vec = Sound::search_for_sound(name, gid, uid, pool.clone(), true).await?; + let mut sound_vec = Sound::search_for_sound(&name, gid, uid, pool.clone(), true).await?; let sound_result = sound_vec.first_mut(); match sound_result { Some(sound) => { if sound.uploader_id != Some(uid) { - invoke.respond(ctx.http.clone(), CreateGenericResponse::new().content("You can only change the visibility of sounds you have uploaded. Use `?list me` to view your sounds")).await?; + ctx.say("You can only change the visibility of sounds you have uploaded. Use `/list` to view your sounds").await?; } else { if sound.public { sound.public = false; - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new() - .content("Sound has been set to private 🔒"), - ) - .await?; + ctx.say("Sound has been set to private 🔒").await?; } else { sound.public = true; - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content("Sound has been set to public 🔓"), - ) - .await?; + ctx.say("Sound has been set to public 🔓").await?; } sound.commit(pool).await? @@ -332,12 +204,7 @@ pub async fn change_public( } None => { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content("Sound could not be found by that name."), - ) - .await?; + ctx.say("Sound could not be found by that name.").await?; } } diff --git a/src/cmds/mod.rs b/src/cmds/mod.rs index 1a8aa9c..ae5369c 100644 --- a/src/cmds/mod.rs +++ b/src/cmds/mod.rs @@ -1,6 +1,6 @@ pub mod info; pub mod manage; pub mod play; -pub mod search; -pub mod settings; -pub mod stop; +// pub mod search; +// pub mod settings; +// pub mod stop; diff --git a/src/cmds/play.rs b/src/cmds/play.rs index 397c518..0195784 100644 --- a/src/cmds/play.rs +++ b/src/cmds/play.rs @@ -1,389 +1,106 @@ -use std::{convert::TryFrom, time::Duration}; - -use regex_command_attr::command; -use serenity::{ - builder::CreateActionRow, - client::Context, - framework::standard::CommandResult, - model::interactions::{message_component::ButtonStyle, InteractionResponseType}, -}; -use songbird::{ - create_player, ffmpeg, - input::{cached::Memory, Input}, - Event, +use poise::serenity::{ + builder::CreateActionRow, model::interactions::message_component::ButtonStyle, }; -use crate::{ - event_handlers::RestartTrack, - framework::{Args, CommandInvoke, CreateGenericResponse}, - guild_data::CtxGuildData, - join_channel, play_from_query, - sound::Sound, - AudioIndex, MySQL, -}; +use crate::{play_from_query, sound::Sound, Context, Error}; -#[command] -#[aliases("p")] -#[required_permissions(Managed)] -#[group("Play")] -#[description("Play a sound in your current voice channel")] -#[arg( - name = "query", - description = "Play sound with the specified name or ID", - kind = "String", - required = true -)] -#[example("`/play ubercharge` - play sound with name \"ubercharge\" ")] -#[example("`/play 13002` - play sound with ID 13002")] +/// Play a sound in your current voice channel +#[poise::command(slash_command)] pub async fn play( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { - let guild = invoke.guild(ctx.cache.clone()).unwrap(); + ctx: Context<'_>, + #[description = "Name or ID of sound to play"] name: String, +) -> Result<(), Error> { + let guild = ctx.guild().unwrap(); - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new() - .content(play_from_query(ctx, guild, invoke.author_id(), args, false).await), - ) + ctx.say(play_from_query(&ctx, guild, ctx.author().id, &name, false).await) .await?; Ok(()) } -#[command("loop")] -#[required_permissions(Managed)] -#[group("Play")] -#[description("Play a sound on loop in your current voice channel")] -#[arg( - name = "query", - description = "Play sound with the specified name or ID", - kind = "String", - required = true -)] -#[example("`/loop rain` - loop sound with name \"rain\" ")] -#[example("`/loop 13002` - play sound with ID 13002")] +/// Loop a sound in your current voice channel +#[poise::command(slash_command)] pub async fn loop_play( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { - let guild = invoke.guild(ctx.cache.clone()).unwrap(); + ctx: Context<'_>, + #[description = "Name or ID of sound to loop"] name: String, +) -> Result<(), Error> { + let guild = ctx.guild().unwrap(); - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new() - .content(play_from_query(ctx, guild, invoke.author_id(), args, true).await), - ) + ctx.say(play_from_query(&ctx, guild, ctx.author().id, &name, true).await) .await?; Ok(()) } -#[command("ambience")] -#[required_permissions(Managed)] -#[group("Play")] -#[description("Play ambient sound in your current voice channel")] -#[arg( - name = "name", - description = "Play sound with the specified name", - kind = "String", - required = false -)] -#[example("`/ambience rain on tent` - play the ambient sound \"rain on tent\" ")] -pub async fn play_ambience( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { - let guild = invoke.guild(ctx.cache.clone()).unwrap(); - - let channel_to_join = guild - .voice_states - .get(&invoke.author_id()) - .and_then(|voice_state| voice_state.channel_id); - - match channel_to_join { - Some(user_channel) => { - let audio_index = ctx.data.read().await.get::().cloned().unwrap(); - - if let Some(search_name) = args.named("name") { - if let Some(filename) = audio_index.get(search_name) { - let (track, track_handler) = create_player( - Input::try_from( - Memory::new(ffmpeg(format!("audio/{}", filename)).await.unwrap()) - .unwrap(), - ) - .unwrap(), - ); - - let (call_handler, _) = join_channel(ctx, guild.clone(), user_channel).await; - let guild_data = ctx.guild_data(guild).await.unwrap(); - - { - let mut lock = call_handler.lock().await; - - lock.play(track); - } - - let _ = track_handler.set_volume(guild_data.read().await.volume as f32 / 100.0); - let _ = track_handler.add_event( - Event::Periodic( - track_handler.metadata().duration.unwrap() - Duration::from_millis(200), - None, - ), - RestartTrack {}, - ); - - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new() - .content(format!("Playing ambience **{}**", search_name)), - ) - .await?; - } else { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().embed(|e| { - e.title("Not Found").description(format!( - "Could not find ambience sound by name **{}** - -__Available ambience sounds:__ -{}", - search_name, - audio_index - .keys() - .into_iter() - .map(|i| i.as_str()) - .collect::>() - .join("\n") - )) - }), - ) - .await?; - } - } else { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().embed(|e| { - e.title("Available Sounds").description( - audio_index - .keys() - .into_iter() - .map(|i| i.as_str()) - .collect::>() - .join("\n"), - ) - }), - ) - .await?; - } - } - - None => { - invoke - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content("You are not in a voice chat!"), - ) - .await?; - } - } - - Ok(()) -} - -#[command("soundboard")] -#[required_permissions(Managed)] -#[group("Play")] -#[kind(Slash)] -#[description("Get a menu of sounds with buttons to play them")] -#[arg( - name = "1", - description = "Query for sound button 1", - kind = "String", - required = true -)] -#[arg( - name = "2", - description = "Query for sound button 2", - kind = "String", - required = false -)] -#[arg( - name = "3", - description = "Query for sound button 3", - kind = "String", - required = false -)] -#[arg( - name = "4", - description = "Query for sound button 4", - kind = "String", - required = false -)] -#[arg( - name = "5", - description = "Query for sound button 5", - kind = "String", - required = false -)] -#[arg( - name = "6", - description = "Query for sound button 6", - kind = "String", - required = false -)] -#[arg( - name = "7", - description = "Query for sound button 7", - kind = "String", - required = false -)] -#[arg( - name = "8", - description = "Query for sound button 8", - kind = "String", - required = false -)] -#[arg( - name = "9", - description = "Query for sound button 9", - kind = "String", - required = false -)] -#[arg( - name = "10", - description = "Query for sound button 10", - kind = "String", - required = false -)] -#[arg( - name = "11", - description = "Query for sound button 11", - kind = "String", - required = false -)] -#[arg( - name = "12", - description = "Query for sound button 12", - kind = "String", - required = false -)] -#[arg( - name = "13", - description = "Query for sound button 13", - kind = "String", - required = false -)] -#[arg( - name = "14", - description = "Query for sound button 14", - kind = "String", - required = false -)] -#[arg( - name = "15", - description = "Query for sound button 15", - kind = "String", - required = false -)] -#[arg( - name = "16", - description = "Query for sound button 16", - kind = "String", - required = false -)] -#[arg( - name = "17", - description = "Query for sound button 17", - kind = "String", - required = false -)] -#[arg( - name = "18", - description = "Query for sound button 18", - kind = "String", - required = false -)] -#[arg( - name = "19", - description = "Query for sound button 19", - kind = "String", - required = false -)] -#[arg( - name = "20", - description = "Query for sound button 20", - kind = "String", - required = false -)] -#[arg( - name = "21", - description = "Query for sound button 21", - kind = "String", - required = false -)] -#[arg( - name = "22", - description = "Query for sound button 22", - kind = "String", - required = false -)] -#[arg( - name = "23", - description = "Query for sound button 23", - kind = "String", - required = false -)] -#[arg( - name = "24", - description = "Query for sound button 24", - kind = "String", - required = false -)] -#[arg( - name = "25", - description = "Query for sound button 25", - kind = "String", - required = false -)] -#[example("`/soundboard ubercharge` - create a soundboard with a button for the \"ubercharge\" sound effect")] -#[example("`/soundboard 57000 24119 2 1002 13202` - create a soundboard with 5 buttons, for sounds with the IDs presented")] +/// Get a menu of sounds with buttons to play them +#[poise::command(slash_command, rename = "soundboard", category = "Play")] pub async fn soundboard( - ctx: &Context, - invoke: &(dyn CommandInvoke + Sync + Send), - args: Args, -) -> CommandResult { - if let Some(interaction) = invoke.interaction() { - let _ = interaction - .create_interaction_response(&ctx, |r| { - r.kind(InteractionResponseType::DeferredChannelMessageWithSource) - }) - .await; - } + ctx: Context<'_>, + #[description = "Name or ID of sound for button 1"] sound_1: String, + #[description = "Name or ID of sound for button 2"] sound_2: Option, + #[description = "Name or ID of sound for button 3"] sound_3: Option, + #[description = "Name or ID of sound for button 4"] sound_4: Option, + #[description = "Name or ID of sound for button 5"] sound_5: Option, + #[description = "Name or ID of sound for button 6"] sound_6: Option, + #[description = "Name or ID of sound for button 7"] sound_7: Option, + #[description = "Name or ID of sound for button 8"] sound_8: Option, + #[description = "Name or ID of sound for button 9"] sound_9: Option, + #[description = "Name or ID of sound for button 10"] sound_10: Option, + #[description = "Name or ID of sound for button 11"] sound_11: Option, + #[description = "Name or ID of sound for button 12"] sound_12: Option, + #[description = "Name or ID of sound for button 13"] sound_13: Option, + #[description = "Name or ID of sound for button 14"] sound_14: Option, + #[description = "Name or ID of sound for button 15"] sound_15: Option, + #[description = "Name or ID of sound for button 16"] sound_16: Option, + #[description = "Name or ID of sound for button 17"] sound_17: Option, + #[description = "Name or ID of sound for button 18"] sound_18: Option, + #[description = "Name or ID of sound for button 19"] sound_19: Option, + #[description = "Name or ID of sound for button 20"] sound_20: Option, + #[description = "Name or ID of sound for button 21"] sound_21: Option, + #[description = "Name or ID of sound for button 22"] sound_22: Option, + #[description = "Name or ID of sound for button 23"] sound_23: Option, + #[description = "Name or ID of sound for button 24"] sound_24: Option, + #[description = "Name or ID of sound for button 25"] sound_25: Option, +) -> Result<(), Error> { + ctx.defer().await?; - let pool = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("Could not get SQLPool from data"); + let pool = ctx.data().database.clone(); + + let query_terms = [ + Some(sound_1), + sound_2, + sound_3, + sound_4, + sound_5, + sound_6, + sound_7, + sound_8, + sound_9, + sound_10, + sound_11, + sound_12, + sound_13, + sound_14, + sound_15, + sound_16, + sound_17, + sound_18, + sound_19, + sound_20, + sound_21, + sound_22, + sound_23, + sound_24, + sound_25, + ]; let mut sounds = vec![]; - for n in 1..25 { + for sound in query_terms.iter().flatten() { let search = Sound::search_for_sound( - args.named(&n.to_string()).unwrap_or(&"".to_string()), - invoke.guild_id().unwrap(), - invoke.author_id(), + &sound, + ctx.guild_id().unwrap(), + ctx.author().id, pool.clone(), true, ) @@ -396,29 +113,25 @@ pub async fn soundboard( } } - invoke - .followup( - ctx.http.clone(), - CreateGenericResponse::new() - .content("**Play a sound:**") - .components(|c| { - for row in sounds.as_slice().chunks(5) { - let mut action_row: CreateActionRow = Default::default(); - for sound in row { - action_row.create_button(|b| { - b.style(ButtonStyle::Primary) - .label(&sound.name) - .custom_id(sound.id) - }); - } + ctx.send(|m| { + m.content("**Play a sound:**").components(|c| { + for row in sounds.as_slice().chunks(5) { + let mut action_row: CreateActionRow = Default::default(); + for sound in row { + action_row.create_button(|b| { + b.style(ButtonStyle::Primary) + .label(&sound.name) + .custom_id(sound.id) + }); + } - c.add_action_row(action_row); - } + c.add_action_row(action_row); + } - c - }), - ) - .await?; + c + }) + }) + .await?; Ok(()) } diff --git a/src/cmds/search.rs b/src/cmds/search.rs index 2fc468a..4e3a285 100644 --- a/src/cmds/search.rs +++ b/src/cmds/search.rs @@ -1,11 +1,4 @@ -use regex_command_attr::command; -use serenity::{client::Context, framework::standard::CommandResult}; - -use crate::{ - framework::{Args, CommandInvoke, CreateGenericResponse}, - sound::Sound, - MySQL, -}; +use crate::sound::Sound; fn format_search_results(search_results: Vec) -> CreateGenericResponse { let mut current_character_count = 0; diff --git a/src/event_handlers.rs b/src/event_handlers.rs index d39554e..42b5c08 100644 --- a/src/event_handlers.rs +++ b/src/event_handlers.rs @@ -1,26 +1,13 @@ use std::{collections::HashMap, env}; -use serenity::{ - async_trait, - client::{Context, EventHandler}, - model::{ - channel::Channel, - gateway::{Activity, Ready}, - guild::Guild, - id::GuildId, - interactions::{Interaction, InteractionResponseType}, - voice::VoiceState, - }, - utils::shard_id, -}; +use poise::serenity::{async_trait, model::channel::Channel, prelude::Context, utils::shard_id}; use songbird::{Event, EventContext, EventHandler as SongbirdEventHandler}; use crate::{ - framework::{Args, RegexFramework}, guild_data::CtxGuildData, - join_channel, play_audio, play_from_query, + join_channel, play_audio, sound::{JoinSoundCtx, Sound}, - MySQL, ReqwestClient, + Data, Error, }; pub struct RestartTrack; @@ -36,179 +23,111 @@ impl SongbirdEventHandler for RestartTrack { } } -pub struct Handler; +pub async fn listener(ctx: &Context, event: &poise::Event<'_>, data: &Data) -> Result<(), Error> { + match event { + poise::Event::GuildCreate { guild, is_new, .. } => { + if *is_new { + if let Ok(token) = env::var("DISCORDBOTS_TOKEN") { + let shard_count = ctx.cache.shard_count(); + let current_shard_id = shard_id(guild.id.as_u64().to_owned(), shard_count); -#[serenity::async_trait] -impl EventHandler for Handler { - async fn ready(&self, ctx: Context, _: Ready) { - ctx.set_activity(Activity::watching("for /play")).await; - } + let guild_count = ctx + .cache + .guilds() + .iter() + .filter(|g| { + shard_id(g.as_u64().to_owned(), shard_count) == current_shard_id + }) + .count() as u64; - async fn guild_create(&self, ctx: Context, guild: Guild, is_new: bool) { - if is_new { - if let Ok(token) = env::var("DISCORDBOTS_TOKEN") { - let shard_count = ctx.cache.shard_count(); - let current_shard_id = shard_id(guild.id.as_u64().to_owned(), shard_count); + let mut hm = HashMap::new(); + hm.insert("server_count", guild_count); + hm.insert("shard_id", current_shard_id); + hm.insert("shard_count", shard_count); - let guild_count = ctx - .cache - .guilds() - .iter() - .filter(|g| shard_id(g.as_u64().to_owned(), shard_count) == current_shard_id) - .count() as u64; - - let mut hm = HashMap::new(); - hm.insert("server_count", guild_count); - hm.insert("shard_id", current_shard_id); - hm.insert("shard_count", shard_count); - - let client = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("Could not get ReqwestClient from data"); - - let response = client - .post( - format!( - "https://top.gg/api/bots/{}/stats", - ctx.cache.current_user_id().as_u64() + let response = data + .http + .post( + format!( + "https://top.gg/api/bots/{}/stats", + ctx.cache.current_user_id().as_u64() + ) + .as_str(), ) - .as_str(), - ) - .header("Authorization", token) - .json(&hm) - .send() - .await; + .header("Authorization", token) + .json(&hm) + .send() + .await; - if let Err(res) = response { - println!("DiscordBots Response: {:?}", res); + if let Err(res) = response { + println!("DiscordBots Response: {:?}", res); + } } } } - } + poise::Event::VoiceStateUpdate { old, new, .. } => { + if let Some(past_state) = old { + if let (Some(guild_id), None) = (past_state.guild_id, new.channel_id) { + if let Some(channel_id) = past_state.channel_id { + if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) { + if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 { + let songbird = songbird::get(&ctx).await.unwrap(); - async fn voice_state_update( - &self, - ctx: Context, - guild_id_opt: Option, - old: Option, - new: VoiceState, - ) { - if let Some(past_state) = old { - if let (Some(guild_id), None) = (guild_id_opt, new.channel_id) { - if let Some(channel_id) = past_state.channel_id { - if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) { - if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 { - let songbird = songbird::get(&ctx).await.unwrap(); - - let _ = songbird.remove(guild_id).await; + let _ = songbird.remove(guild_id).await; + } } } } - } - } else if let (Some(guild_id), Some(user_channel)) = (guild_id_opt, new.channel_id) { - if let Some(guild) = ctx.cache.guild(guild_id) { - let pool = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("Could not get SQLPool from data"); + } else if let (Some(guild_id), Some(user_channel)) = (new.guild_id, new.channel_id) { + if let Some(guild) = ctx.cache.guild(guild_id) { + let pool = data.database.clone(); - let guild_data_opt = ctx.guild_data(guild.id).await; + let guild_data_opt = data.guild_data(guild.id).await; - if let Ok(guild_data) = guild_data_opt { - let volume; - let allowed_greets; + if let Ok(guild_data) = guild_data_opt { + let volume; + let allowed_greets; - { - let read = guild_data.read().await; + { + let read = guild_data.read().await; - volume = read.volume; - allowed_greets = read.allow_greets; - } + volume = read.volume; + allowed_greets = read.allow_greets; + } - if allowed_greets { - if let Some(join_id) = ctx.join_sound(new.user_id).await { - let mut sound = sqlx::query_as_unchecked!( - Sound, - " + if allowed_greets { + if let Some(join_id) = data.join_sound(new.user_id).await { + let mut sound = sqlx::query_as_unchecked!( + Sound, + " SELECT name, id, public, server_id, uploader_id FROM sounds WHERE id = ? ", - join_id - ) - .fetch_one(&pool) - .await - .unwrap(); + join_id + ) + .fetch_one(&pool) + .await + .unwrap(); - let (handler, _) = join_channel(&ctx, guild, user_channel).await; + let (handler, _) = join_channel(&ctx, guild, user_channel).await; - let _ = play_audio( - &mut sound, - volume, - &mut handler.lock().await, - pool, - false, - ) - .await; + let _ = play_audio( + &mut sound, + volume, + &mut handler.lock().await, + pool, + false, + ) + .await; + } } } } } } + _ => {} } - async fn interaction_create(&self, ctx: Context, interaction: Interaction) { - match interaction { - Interaction::ApplicationCommand(application_command) => { - if application_command.guild_id.is_none() { - return; - } - - let framework = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("RegexFramework not found in context"); - - framework.execute(ctx, application_command).await; - } - Interaction::MessageComponent(component) => { - if component.guild_id.is_none() { - return; - } - - let mut args = Args { - args: Default::default(), - }; - args.args - .insert("query".to_string(), component.data.custom_id.clone()); - - play_from_query( - &ctx, - component.guild_id.unwrap().to_guild_cached(&ctx).unwrap(), - component.user.id, - args, - false, - ) - .await; - - component - .create_interaction_response(ctx, |r| { - r.kind(InteractionResponseType::DeferredUpdateMessage) - }) - .await - .unwrap(); - } - _ => {} - } - } + Ok(()) } diff --git a/src/framework.rs b/src/framework.rs deleted file mode 100644 index 777fee9..0000000 --- a/src/framework.rs +++ /dev/null @@ -1,735 +0,0 @@ -use std::{ - collections::{HashMap, HashSet}, - env, fmt, - hash::{Hash, Hasher}, - sync::Arc, -}; - -use log::{debug, error, info, warn}; -use regex::{Match, Regex, RegexBuilder}; -use serde_json::Value; -use serenity::{ - async_trait, - builder::{CreateApplicationCommands, CreateComponents, CreateEmbed}, - cache::Cache, - client::Context, - framework::{standard::CommandResult, Framework}, - futures::prelude::future::BoxFuture, - http::Http, - model::{ - channel::{Channel, GuildChannel, Message}, - guild::{Guild, Member}, - id::{ChannelId, GuildId, RoleId, UserId}, - interactions::{ - application_command::{ - ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType, - }, - InteractionResponseType, - }, - }, - prelude::TypeMapKey, - Result as SerenityResult, -}; - -use crate::guild_data::CtxGuildData; - -type CommandFn = for<'fut> fn( - &'fut Context, - &'fut (dyn CommandInvoke + Sync + Send), - Args, -) -> BoxFuture<'fut, CommandResult>; - -pub struct Args { - pub args: HashMap, -} - -impl Args { - pub fn from(message: &str, arg_schema: &'static [&'static Arg]) -> Self { - // construct regex from arg schema - let mut re = arg_schema - .iter() - .map(|a| a.to_regex()) - .collect::>() - .join(r#"\s*"#); - - re.push_str("$"); - - let regex = Regex::new(&re).unwrap(); - let capture_names = regex.capture_names(); - let captures = regex.captures(message); - - let mut args = HashMap::new(); - - if let Some(captures) = captures { - for name in capture_names.filter(|n| n.is_some()).map(|n| n.unwrap()) { - if let Some(cap) = captures.name(name) { - args.insert(name.to_string(), cap.as_str().to_string()); - } - } - } - - Self { args } - } - - pub fn named(&self, name: D) -> Option<&String> { - let name = name.to_string(); - - self.args.get(&name) - } -} - -pub struct CreateGenericResponse { - content: String, - embed: Option, - components: Option, -} - -impl CreateGenericResponse { - pub fn new() -> Self { - Self { - content: "".to_string(), - embed: None, - components: None, - } - } - - pub fn content(mut self, content: D) -> Self { - self.content = content.to_string(); - - self - } - - pub fn embed &mut CreateEmbed>(mut self, f: F) -> Self { - let mut embed = CreateEmbed::default(); - f(&mut embed); - - self.embed = Some(embed); - self - } - - pub fn components &mut CreateComponents>( - mut self, - f: F, - ) -> Self { - let mut components = CreateComponents::default(); - f(&mut components); - - self.components = Some(components); - self - } -} - -#[async_trait] -pub trait CommandInvoke { - fn channel_id(&self) -> ChannelId; - fn guild_id(&self) -> Option; - fn guild(&self, cache: Arc) -> Option; - fn author_id(&self) -> UserId; - async fn member(&self, context: &Context) -> SerenityResult; - fn msg(&self) -> Option; - fn interaction(&self) -> Option; - async fn respond( - &self, - http: Arc, - generic_response: CreateGenericResponse, - ) -> SerenityResult<()>; - async fn followup( - &self, - http: Arc, - generic_response: CreateGenericResponse, - ) -> SerenityResult<()>; -} - -#[async_trait] -impl CommandInvoke for Message { - fn channel_id(&self) -> ChannelId { - self.channel_id - } - - fn guild_id(&self) -> Option { - self.guild_id - } - - fn guild(&self, cache: Arc) -> Option { - self.guild(cache) - } - - fn author_id(&self) -> UserId { - self.author.id - } - - async fn member(&self, context: &Context) -> SerenityResult { - self.member(context).await - } - - fn msg(&self) -> Option { - Some(self.clone()) - } - - fn interaction(&self) -> Option { - None - } - - async fn respond( - &self, - http: Arc, - generic_response: CreateGenericResponse, - ) -> SerenityResult<()> { - self.channel_id - .send_message(http, |m| { - m.content(generic_response.content); - - if let Some(embed) = generic_response.embed { - m.set_embed(embed.clone()); - } - - if let Some(components) = generic_response.components { - m.components(|c| { - *c = components; - c - }); - } - - m - }) - .await - .map(|_| ()) - } - - async fn followup( - &self, - http: Arc, - generic_response: CreateGenericResponse, - ) -> SerenityResult<()> { - self.channel_id - .send_message(http, |m| { - m.content(generic_response.content); - - if let Some(embed) = generic_response.embed { - m.set_embed(embed.clone()); - } - - if let Some(components) = generic_response.components { - m.components(|c| { - *c = components; - c - }); - } - - m - }) - .await - .map(|_| ()) - } -} - -#[async_trait] -impl CommandInvoke for ApplicationCommandInteraction { - fn channel_id(&self) -> ChannelId { - self.channel_id - } - - fn guild_id(&self) -> Option { - self.guild_id - } - - fn guild(&self, cache: Arc) -> Option { - if let Some(guild_id) = self.guild_id { - guild_id.to_guild_cached(cache) - } else { - None - } - } - - fn author_id(&self) -> UserId { - self.member.as_ref().unwrap().user.id - } - - async fn member(&self, _: &Context) -> SerenityResult { - Ok(self.member.clone().unwrap()) - } - - fn msg(&self) -> Option { - None - } - - fn interaction(&self) -> Option { - Some(self.clone()) - } - - async fn respond( - &self, - http: Arc, - generic_response: CreateGenericResponse, - ) -> SerenityResult<()> { - self.create_interaction_response(http, |r| { - r.kind(InteractionResponseType::ChannelMessageWithSource) - .interaction_response_data(|d| { - d.content(generic_response.content); - - if let Some(embed) = generic_response.embed { - d.add_embed(embed.clone()); - } - - if let Some(components) = generic_response.components { - d.components(|c| { - *c = components; - c - }); - } - - d - }) - }) - .await - .map(|_| ()) - } - - async fn followup( - &self, - http: Arc, - generic_response: CreateGenericResponse, - ) -> SerenityResult<()> { - self.create_followup_message(http, |d| { - d.content(generic_response.content); - - if let Some(embed) = generic_response.embed { - d.add_embed(embed.clone()); - } - - if let Some(components) = generic_response.components { - d.components(|c| { - *c = components; - c - }); - } - - d - }) - .await - .map(|_| ()) - } -} - -#[derive(Debug, PartialEq)] -pub enum PermissionLevel { - Unrestricted, - Managed, - Restricted, -} - -#[derive(Debug, PartialEq)] -pub enum CommandKind { - Slash, - Both, - Text, -} - -#[derive(Debug)] -pub struct Arg { - pub name: &'static str, - pub description: &'static str, - pub kind: ApplicationCommandOptionType, - pub required: bool, -} - -impl Arg { - pub fn to_regex(&self) -> String { - match self.kind { - ApplicationCommandOptionType::String => format!(r#"(?P<{}>.+?)"#, self.name), - ApplicationCommandOptionType::Integer => format!(r#"(?P<{}>\d+)"#, self.name), - ApplicationCommandOptionType::Boolean => format!(r#"(?P<{0}>{0})?"#, self.name), - ApplicationCommandOptionType::User => format!(r#"<(@|@!)(?P<{}>\d+)>"#, self.name), - ApplicationCommandOptionType::Channel => format!(r#"<#(?P<{}>\d+)>"#, self.name), - ApplicationCommandOptionType::Role => format!(r#"<@&(?P<{}>\d+)>"#, self.name), - ApplicationCommandOptionType::Mentionable => { - format!(r#"<(?P<{0}_pref>@|@!|@&|#)(?P<{0}>\d+)>"#, self.name) - } - _ => String::new(), - } - } -} - -pub struct Command { - pub fun: CommandFn, - - pub names: &'static [&'static str], - - pub desc: &'static str, - pub examples: &'static [&'static str], - pub group: &'static str, - - pub kind: CommandKind, - pub required_permissions: PermissionLevel, - pub args: &'static [&'static Arg], -} - -impl Hash for Command { - fn hash(&self, state: &mut H) { - self.names[0].hash(state) - } -} - -impl PartialEq for Command { - fn eq(&self, other: &Self) -> bool { - self.names[0] == other.names[0] - } -} - -impl Eq for Command {} - -impl Command { - async fn check_permissions(&self, ctx: &Context, guild: &Guild, member: &Member) -> bool { - if self.required_permissions == PermissionLevel::Unrestricted { - true - } else { - let permissions = guild.member_permissions(&ctx, &member.user).await.unwrap(); - - if permissions.manage_guild() { - return true; - } - - if self.required_permissions == PermissionLevel::Managed { - match ctx.guild_data(guild.id).await { - Ok(guild_data) => guild_data.read().await.allowed_role.map_or(true, |role| { - role == guild.id.0 || { - let role_id = RoleId(role); - - member.roles.contains(&role_id) - } - }), - - Err(e) => { - warn!("Unexpected error occurred querying roles: {:?}", e); - - false - } - } - } else { - false - } - } - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Command") - .field("name", &self.names[0]) - .field("required_permissions", &self.required_permissions) - .field("args", &self.args) - .finish() - } -} - -pub struct RegexFramework { - pub commands: HashMap, - pub commands_: HashSet<&'static Command>, - command_matcher: Regex, - default_prefix: String, - client_id: u64, - ignore_bots: bool, - case_insensitive: bool, -} - -impl TypeMapKey for RegexFramework { - type Value = Arc; -} - -impl RegexFramework { - pub fn new>(client_id: T) -> Self { - Self { - commands: HashMap::new(), - commands_: HashSet::new(), - command_matcher: Regex::new(r#"^$"#).unwrap(), - default_prefix: "".to_string(), - client_id: client_id.into(), - ignore_bots: true, - case_insensitive: true, - } - } - - pub fn case_insensitive(mut self, case_insensitive: bool) -> Self { - self.case_insensitive = case_insensitive; - - self - } - - pub fn default_prefix(mut self, new_prefix: T) -> Self { - self.default_prefix = new_prefix.to_string(); - - self - } - - pub fn ignore_bots(mut self, ignore_bots: bool) -> Self { - self.ignore_bots = ignore_bots; - - self - } - - pub fn add_command(mut self, command: &'static Command) -> Self { - self.commands_.insert(command); - - for name in command.names { - self.commands.insert(name.to_string(), command); - } - - self - } - - pub fn build(mut self) -> Self { - let command_names; - - { - let mut command_names_vec = self.commands.keys().map(|k| &k[..]).collect::>(); - - command_names_vec.sort_unstable_by(|a, b| b.len().cmp(&a.len())); - - command_names = command_names_vec.join("|"); - } - - debug!("Command names: {}", command_names); - - { - let match_string = r#"^(?:(?:<@ID>\s*)|(?:<@!ID>\s*)|(?P\S{1,5}?))(?PCOMMANDS)(?:$|\s+(?P.*))$"# - .replace("COMMANDS", command_names.as_str()) - .replace("ID", self.client_id.to_string().as_str()); - - self.command_matcher = RegexBuilder::new(match_string.as_str()) - .case_insensitive(self.case_insensitive) - .dot_matches_new_line(true) - .build() - .unwrap(); - } - - self - } - - fn _populate_commands<'a>( - &self, - commands: &'a mut CreateApplicationCommands, - ) -> &'a mut CreateApplicationCommands { - for command in &self.commands_ { - commands.create_application_command(|c| { - c.name(command.names[0]).description(command.desc); - - for arg in command.args { - c.create_option(|o| { - o.name(arg.name) - .description(arg.description) - .kind(arg.kind) - .required(arg.required) - }); - } - - c - }); - } - - commands - } - - pub async fn build_slash(&self, http: impl AsRef) { - info!("Building slash commands..."); - - match env::var("TEST_GUILD") - .map(|i| i.parse::().ok()) - .ok() - .flatten() - .map(|i| GuildId(i)) - { - None => { - ApplicationCommand::set_global_application_commands(&http, |c| { - self._populate_commands(c) - }) - .await - .unwrap(); - } - Some(debug_guild) => { - debug_guild - .set_application_commands(&http, |c| self._populate_commands(c)) - .await - .unwrap(); - } - } - - info!("Slash commands built!"); - } - - pub async fn execute(&self, ctx: Context, interaction: ApplicationCommandInteraction) { - let command = { - self.commands.get(&interaction.data.name).expect(&format!( - "Received invalid command: {}", - interaction.data.name - )) - }; - - if command - .check_permissions( - &ctx, - &interaction.guild(ctx.cache.clone()).unwrap(), - &interaction.clone().member.unwrap(), - ) - .await - { - let mut args = HashMap::new(); - - for arg in interaction - .data - .options - .iter() - .filter(|o| o.value.is_some()) - { - args.insert( - arg.name.clone(), - match arg.value.clone().unwrap() { - Value::Bool(b) => { - if b { - arg.name.clone() - } else { - String::new() - } - } - Value::Number(n) => n.to_string(), - Value::String(s) => s, - _ => String::new(), - }, - ); - } - - info!( - "[Shard {}] [Guild {}] /{} {:?}", - ctx.shard_id, - interaction.guild_id.unwrap(), - interaction.data.name, - args - ); - - (command.fun)(&ctx, &interaction, Args { args }) - .await - .unwrap(); - } else if command.required_permissions == PermissionLevel::Managed { - let _ = interaction - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content("You must either be an Admin or have a role specified by `/roles` to do this command") - ) - .await; - } else if command.required_permissions == PermissionLevel::Restricted { - let _ = interaction - .respond( - ctx.http.clone(), - CreateGenericResponse::new().content("You must be an Admin to do this command"), - ) - .await; - } - } -} - -enum PermissionCheck { - None, // No permissions - All, // Sufficient permissions -} - -#[async_trait] -impl Framework for RegexFramework { - async fn dispatch(&self, ctx: Context, msg: Message) { - async fn check_self_permissions( - ctx: &Context, - channel: &GuildChannel, - ) -> SerenityResult { - let user_id = ctx.cache.current_user_id(); - - let channel_perms = channel.permissions_for_user(ctx, user_id)?; - - Ok( - if channel_perms.send_messages() && channel_perms.embed_links() { - PermissionCheck::All - } else { - PermissionCheck::None - }, - ) - } - - async fn check_prefix(ctx: &Context, guild: &Guild, prefix_opt: Option>) -> bool { - if let Some(prefix) = prefix_opt { - match ctx.guild_data(guild.id).await { - Ok(guild_data) => prefix.as_str() == guild_data.read().await.prefix, - - Err(_) => prefix.as_str() == "?", - } - } else { - true - } - } - - // gate to prevent analysing messages unnecessarily - if msg.author.bot || msg.content.is_empty() { - } - // Guild Command - else if let (Some(guild), Ok(Channel::Guild(channel))) = - (msg.guild(&ctx), msg.channel(&ctx).await) - { - if let Some(full_match) = self.command_matcher.captures(&msg.content) { - if check_prefix(&ctx, &guild, full_match.name("prefix")).await { - match check_self_permissions(&ctx, &channel).await { - Ok(perms) => match perms { - PermissionCheck::All => { - let command = self - .commands - .get(&full_match.name("cmd").unwrap().as_str().to_lowercase()) - .unwrap(); - - if command.kind != CommandKind::Slash { - let args = full_match - .name("args") - .map(|m| m.as_str()) - .unwrap_or("") - .to_string(); - - let member = guild.member(&ctx, &msg.author).await.unwrap(); - - if command.check_permissions(&ctx, &guild, &member).await { - let _ = msg.channel_id.say( - &ctx, - format!( - "You **must** begin to switch to slash commands. All commands are available via slash commands now. If slash commands don't display in your server, please use this link: https://discord.com/api/oauth2/authorize?client_id={}&permissions=3165184&scope=applications.commands%20bot", - ctx.cache.current_user().id - ) - ).await; - - (command.fun)(&ctx, &msg, Args::from(&args, command.args)) - .await - .unwrap(); - } else if command.required_permissions - == PermissionLevel::Managed - { - let _ = msg.channel_id.say(&ctx, "You must either be an Admin or have a role specified in `?roles` to do this command").await; - } else if command.required_permissions - == PermissionLevel::Restricted - { - let _ = msg - .channel_id - .say(&ctx, "You must be an Admin to do this command") - .await; - } - } - } - - PermissionCheck::None => { - warn!("Missing enough permissions for guild {}", guild.id); - } - }, - - Err(e) => { - error!( - "Error occurred getting permissions in guild {}: {:?}", - guild.id, e - ); - } - } - } - } - } - } -} diff --git a/src/guild_data.rs b/src/guild_data.rs index 4dad567..2ab5efd 100644 --- a/src/guild_data.rs +++ b/src/guild_data.rs @@ -1,10 +1,10 @@ use std::sync::Arc; -use serenity::{async_trait, model::id::GuildId, prelude::Context}; +use poise::serenity::{async_trait, model::id::GuildId}; use sqlx::mysql::MySqlPool; use tokio::sync::RwLock; -use crate::{GuildDataCache, MySQL}; +use crate::{Context, Data}; #[derive(Clone)] pub struct GuildData { @@ -24,31 +24,33 @@ pub trait CtxGuildData { } #[async_trait] -impl CtxGuildData for Context { +impl CtxGuildData for Context<'_> { + async fn guild_data + Send + Sync>( + &self, + guild_id: G, + ) -> Result>, sqlx::Error> { + self.data().guild_data(guild_id).await + } +} + +#[async_trait] +impl CtxGuildData for Data { async fn guild_data + Send + Sync>( &self, guild_id: G, ) -> Result>, sqlx::Error> { let guild_id = guild_id.into(); - let guild_cache = self - .data - .read() - .await - .get::() - .cloned() - .unwrap(); - - let x = if let Some(guild_data) = guild_cache.get(&guild_id) { + let x = if let Some(guild_data) = self.guild_data_cache.get(&guild_id) { Ok(guild_data.clone()) } else { - let pool = self.data.read().await.get::().cloned().unwrap(); + let pool = self.database.clone(); match GuildData::from_id(guild_id, pool).await { Ok(d) => { let lock = Arc::new(RwLock::new(d)); - guild_cache.insert(guild_id, lock.clone()); + self.guild_data_cache.insert(guild_id, lock.clone()); Ok(lock) } diff --git a/src/main.rs b/src/main.rs index f2ca6e8..079671a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,65 +4,41 @@ extern crate lazy_static; mod cmds; mod error; mod event_handlers; -mod framework; mod guild_data; mod sound; -use std::{collections::HashMap, env, sync::Arc}; +use std::{env, sync::Arc}; use dashmap::DashMap; use dotenv::dotenv; -use log::info; -use serenity::{ - client::{bridge::gateway::GatewayIntents, Client, Context}, - http::Http, +use poise::serenity::{ + builder::CreateApplicationCommands, model::{ channel::Channel, + gateway::{Activity, GatewayIntents}, guild::Guild, id::{ChannelId, GuildId, UserId}, }, - prelude::{Mutex, TypeMapKey}, }; use songbird::{create_player, error::JoinResult, tracks::TrackHandle, Call, SerenityInit}; use sqlx::mysql::MySqlPool; -use tokio::sync::{MutexGuard, RwLock}; +use tokio::sync::{Mutex, MutexGuard, RwLock}; use crate::{ - event_handlers::Handler, - framework::{Args, RegexFramework}, + event_handlers::listener, guild_data::{CtxGuildData, GuildData}, sound::Sound, }; -struct MySQL; - -impl TypeMapKey for MySQL { - type Value = MySqlPool; +pub struct Data { + database: MySqlPool, + http: reqwest::Client, + guild_data_cache: DashMap>>, + join_sound_cache: DashMap>, } -struct ReqwestClient; - -impl TypeMapKey for ReqwestClient { - type Value = Arc; -} - -struct AudioIndex; - -impl TypeMapKey for AudioIndex { - type Value = Arc>; -} - -struct GuildDataCache; - -impl TypeMapKey for GuildDataCache { - type Value = Arc>>>; -} - -struct JoinSoundCache; - -impl TypeMapKey for JoinSoundCache { - type Value = Arc>>; -} +type Error = Box; +type Context<'a> = poise::Context<'a, Data, Error>; const THEME_COLOR: u32 = 0x00e0f3; @@ -96,7 +72,7 @@ async fn play_audio( } async fn join_channel( - ctx: &Context, + ctx: &poise::serenity_prelude::Context, guild: Guild, channel_id: ChannelId, ) -> (Arc>, JoinResult<()>) { @@ -139,10 +115,10 @@ async fn join_channel( } async fn play_from_query( - ctx: &Context, + ctx: &Context<'_>, guild: Guild, user_id: UserId, - args: Args, + query: &str, loop_: bool, ) -> String { let guild_id = guild.id; @@ -154,18 +130,10 @@ async fn play_from_query( match channel_to_join { Some(user_channel) => { - let search_term = args.named("query").unwrap(); - - let pool = ctx - .data - .read() - .await - .get::() - .cloned() - .expect("Could not get SQLPool from data"); + let pool = ctx.data().database.clone(); let mut sound_vec = - Sound::search_for_sound(search_term, guild_id, user_id, pool.clone(), true) + Sound::search_for_sound(query, guild_id, user_id, pool.clone(), true) .await .unwrap(); @@ -175,7 +143,7 @@ async fn play_from_query( Some(sound) => { { let (call_handler, _) = - join_channel(ctx, guild.clone(), user_channel).await; + join_channel(ctx.discord(), guild.clone(), user_channel).await; let guild_data = ctx.guild_data(guild_id).await.unwrap(); @@ -203,6 +171,36 @@ async fn play_from_query( } } +pub async fn register_application_commands( + ctx: &poise::serenity::client::Context, + framework: &poise::Framework, + guild_id: Option, +) -> Result<(), poise::serenity::Error> { + let mut commands_builder = CreateApplicationCommands::default(); + let commands = &framework.options().commands; + for command in commands { + if let Some(slash_command) = command.create_as_slash_command() { + commands_builder.add_application_command(slash_command); + } + if let Some(context_menu_command) = command.create_as_context_menu_command() { + commands_builder.add_application_command(context_menu_command); + } + } + let commands_builder = poise::serenity::json::Value::Array(commands_builder.0); + + if let Some(guild_id) = guild_id { + ctx.http + .create_guild_application_commands(guild_id.0, &commands_builder) + .await?; + } else { + ctx.http + .create_global_application_commands(&commands_builder) + .await?; + } + + Ok(()) +} + // entry point #[tokio::main] async fn main() -> Result<(), Box> { @@ -210,141 +208,63 @@ async fn main() -> Result<(), Box> { dotenv()?; - let token = env::var("DISCORD_TOKEN").expect("Missing DISCORD_TOKEN from environment"); + let discord_token = env::var("DISCORD_TOKEN").expect("Missing DISCORD_TOKEN from environment"); - let http = Http::new_with_token(&token); - - let logged_in_id = http.get_current_user().await?.id; - let application_id = http.get_current_application_info().await?.id; - - let audio_index = if let Ok(static_audio) = std::fs::read_to_string("audio/audio.json") { - if let Ok(json) = serde_json::from_str::>(&static_audio) { - Some(json) - } else { - println!( - "Invalid `audio.json` file. Not loading static audio or providing ambience command" - ); - - None - } - } else { - println!("No `audio.json` file. Not loading static audio or providing ambience command"); - - None + let options = poise::FrameworkOptions { + commands: vec![ + cmds::info::info(), + cmds::manage::change_public(), + cmds::manage::upload_new_sound(), + cmds::manage::delete_sound(), + cmds::play::play(), + cmds::play::loop_play(), + cmds::play::soundboard(), + ], + allowed_mentions: None, + listener: |ctx, event, _framework, data| Box::pin(listener(ctx, event, data)), + ..Default::default() }; - let mut framework = RegexFramework::new(logged_in_id) - .default_prefix("?") - .case_insensitive(true) - .ignore_bots(true) - // info commands - .add_command(&cmds::info::HELP_COMMAND) - .add_command(&cmds::info::INFO_COMMAND) - // play commands - .add_command(&cmds::play::LOOP_PLAY_COMMAND) - .add_command(&cmds::play::PLAY_COMMAND) - .add_command(&cmds::play::SOUNDBOARD_COMMAND) - .add_command(&cmds::stop::STOP_PLAYING_COMMAND) - .add_command(&cmds::stop::DISCONNECT_COMMAND) - // sound management commands - .add_command(&cmds::manage::UPLOAD_NEW_SOUND_COMMAND) - .add_command(&cmds::manage::DELETE_SOUND_COMMAND) - .add_command(&cmds::manage::CHANGE_PUBLIC_COMMAND) - // setting commands - .add_command(&cmds::settings::CHANGE_PREFIX_COMMAND) - .add_command(&cmds::settings::SET_ALLOWED_ROLES_COMMAND) - .add_command(&cmds::settings::CHANGE_VOLUME_COMMAND) - .add_command(&cmds::settings::ALLOW_GREET_SOUNDS_COMMAND) - .add_command(&cmds::settings::SET_GREET_SOUND_COMMAND) - // search commands - .add_command(&cmds::search::LIST_SOUNDS_COMMAND) - .add_command(&cmds::search::SEARCH_SOUNDS_COMMAND) - .add_command(&cmds::search::SHOW_RANDOM_SOUNDS_COMMAND); + let database = MySqlPool::connect(&env::var("DATABASE_URL").expect("No database URL provided")) + .await + .unwrap(); - if audio_index.is_some() { - framework = framework.add_command(&cmds::play::PLAY_AMBIENCE_COMMAND); - } + poise::Framework::build() + .token(discord_token) + .user_data_setup(move |ctx, _bot, framework| { + Box::pin(async move { + ctx.set_activity(Activity::watching("for /play")).await; - framework = framework.build(); - - let framework_arc = Arc::new(framework); - - let mut client = - Client::builder(&env::var("DISCORD_TOKEN").expect("Missing token from environment")) - .intents( - GatewayIntents::GUILD_VOICE_STATES - | GatewayIntents::GUILD_MESSAGES - | GatewayIntents::GUILDS, - ) - .framework_arc(framework_arc.clone()) - .application_id(application_id.0) - .event_handler(Handler) - .register_songbird() - .await - .expect("Error occurred creating client"); - - { - let mysql_pool = - MySqlPool::connect(&env::var("DATABASE_URL").expect("No database URL provided")) + register_application_commands( + ctx, + framework, + env::var("DEBUG_GUILD") + .map(|inner| GuildId(inner.parse().expect("DEBUG_GUILD not valid"))) + .ok(), + ) .await .unwrap(); - let guild_data_cache = Arc::new(DashMap::new()); - let join_sound_cache = Arc::new(DashMap::new()); - let mut data = client.data.write().await; - - data.insert::(guild_data_cache); - data.insert::(join_sound_cache); - data.insert::(mysql_pool); - data.insert::(framework_arc.clone()); - data.insert::(Arc::new(reqwest::Client::new())); - - if let Some(audio_index) = audio_index { - data.insert::(Arc::new(audio_index)); - } - } - - framework_arc.build_slash(&client.cache_and_http.http).await; - - if let Ok((Some(lower), Some(upper))) = env::var("SHARD_RANGE").map(|sr| { - let mut split = sr - .split(',') - .map(|val| val.parse::().expect("SHARD_RANGE not an integer")); - - (split.next(), split.next()) - }) { - let total_shards = env::var("SHARD_COUNT") - .map(|shard_count| shard_count.parse::().ok()) - .ok() - .flatten() - .expect("No SHARD_COUNT provided, but SHARD_RANGE was provided"); - - assert!( - lower < upper, - "SHARD_RANGE lower limit is not less than the upper limit" - ); - - info!( - "Starting client fragment with shards {}-{}/{}", - lower, upper, total_shards - ); - - client - .start_shard_range([lower, upper], total_shards) - .await?; - } else if let Ok(total_shards) = env::var("SHARD_COUNT").map(|shard_count| { - shard_count - .parse::() - .expect("SHARD_COUNT not an integer") - }) { - info!("Starting client with {} shards", total_shards); - - client.start_shards(total_shards).await?; - } else { - info!("Starting client as autosharded"); - - client.start_autosharded().await?; - } + Ok(Data { + http: reqwest::Client::new(), + database, + guild_data_cache: Default::default(), + join_sound_cache: Default::default(), + }) + }) + }) + .options(options) + .client_settings(move |client_builder| { + client_builder + .intents( + GatewayIntents::GUILD_VOICE_STATES + | GatewayIntents::GUILD_MESSAGES + | GatewayIntents::GUILDS, + ) + .register_songbird() + }) + .run_autosharded() + .await?; Ok(()) } diff --git a/src/sound.rs b/src/sound.rs index d44c426..b2041db 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -1,12 +1,12 @@ use std::{env, path::Path}; -use serenity::{async_trait, model::id::UserId, prelude::Context}; +use poise::serenity::{async_trait, model::id::UserId}; use songbird::input::restartable::Restartable; use sqlx::mysql::MySqlPool; use tokio::{fs::File, io::AsyncWriteExt, process::Command}; use super::error::ErrorTypes; -use crate::{JoinSoundCache, MySQL}; +use crate::Data; #[async_trait] pub trait JoinSoundCtx { @@ -19,22 +19,15 @@ pub trait JoinSoundCtx { } #[async_trait] -impl JoinSoundCtx for Context { +impl JoinSoundCtx for Data { async fn join_sound + Send + Sync>(&self, user_id: U) -> Option { let user_id = user_id.into(); - let join_sound_cache = self - .data - .read() - .await - .get::() - .cloned() - .unwrap(); - let x = if let Some(join_sound_id) = join_sound_cache.get(&user_id) { + let x = if let Some(join_sound_id) = self.join_sound_cache.get(&user_id) { join_sound_id.value().clone() } else { let join_sound_id = { - let pool = self.data.read().await.get::().cloned().unwrap(); + let pool = self.database.clone(); let join_id_res = sqlx::query!( " @@ -54,7 +47,7 @@ SELECT join_sound_id } }; - join_sound_cache.insert(user_id, join_sound_id); + self.join_sound_cache.insert(user_id, join_sound_id); join_sound_id }; @@ -68,17 +61,10 @@ SELECT join_sound_id join_id: Option, ) { let user_id = user_id.into(); - let join_sound_cache = self - .data - .read() - .await - .get::() - .cloned() - .unwrap(); - join_sound_cache.insert(user_id, join_id); + self.join_sound_cache.insert(user_id, join_id); - let pool = self.data.read().await.get::().cloned().unwrap(); + let pool = self.database.clone(); let _ = sqlx::query!( " @@ -260,10 +246,12 @@ SELECT src .expect("FFMPEG ERROR!")) } - pub async fn count_user_sounds( - user_id: u64, + pub async fn count_user_sounds>( + user_id: U, db_pool: MySqlPool, ) -> Result { + let user_id = user_id.into(); + let c = sqlx::query!( " SELECT COUNT(1) as count @@ -279,11 +267,13 @@ SELECT COUNT(1) as count Ok(c as u32) } - pub async fn count_named_user_sounds( - user_id: u64, + pub async fn count_named_user_sounds>( + user_id: U, name: &String, db_pool: MySqlPool, ) -> Result { + let user_id = user_id.into(); + let c = sqlx::query!( " SELECT COUNT(1) as count @@ -341,13 +331,16 @@ DELETE Ok(()) } - pub async fn create_anon( + pub async fn create_anon, U: Into>( name: &str, src_url: &str, - server_id: u64, - user_id: u64, + server_id: G, + user_id: U, db_pool: MySqlPool, ) -> Result<(), Box> { + let server_id = server_id.into(); + let user_id = user_id.into(); + async fn process_src(src_url: &str) -> Option> { let output = Command::new("ffmpeg") .kill_on_drop(true)