From 7ef33c7419cd768e21fdf549c89dab465e151c75 Mon Sep 17 00:00:00 2001 From: AnandajithS Date: Mon, 9 Mar 2026 21:26:36 +0530 Subject: [PATCH 1/4] feat: add command to ping random members --- Cargo.lock | 310 ++++++++++++++++++++++++++++++++++++----- Cargo.toml | 3 +- src/commands/mod.rs | 4 +- src/commands/random.rs | 32 +++++ src/ids.rs | 3 + 5 files changed, 316 insertions(+), 36 deletions(-) create mode 100644 src/commands/random.rs diff --git a/Cargo.lock b/Cargo.lock index b8cb852..53a9650 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,6 +45,7 @@ dependencies = [ "imap", "mailparse", "poise", + "rand 0.10.0", "reqwest 0.12.23", "serde", "serde_json", @@ -86,7 +87,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -225,6 +226,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.0", +] + [[package]] name = "charset" version = "0.1.5" @@ -295,6 +307,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -350,7 +371,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -361,7 +382,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -423,7 +444,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -488,6 +509,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -566,7 +593,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -629,6 +656,20 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core 0.10.0", + "wasip2", + "wasip3", +] + [[package]] name = "gimli" version = "0.31.1" @@ -690,6 +731,9 @@ name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] [[package]] name = "heck" @@ -697,6 +741,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "html2text" version = "0.12.6" @@ -721,7 +771,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -1047,9 +1097,15 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -1111,6 +1167,7 @@ checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", + "serde", ] [[package]] @@ -1162,6 +1219,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "levenshtein" version = "1.0.5" @@ -1400,7 +1463,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -1438,11 +1501,11 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -1509,7 +1572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared 0.11.3", - "rand", + "rand 0.8.5", ] [[package]] @@ -1574,7 +1637,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -1598,6 +1661,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "proc-macro2" version = "1.0.93" @@ -1615,7 +1688,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", "version_check", "yansi", ] @@ -1646,6 +1719,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.8.5" @@ -1654,7 +1733,18 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom 0.4.2", + "rand_core 0.10.0", ] [[package]] @@ -1664,7 +1754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -1673,9 +1763,15 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + [[package]] name = "redox_syscall" version = "0.5.8" @@ -1806,7 +1902,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -2031,7 +2127,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -2103,7 +2199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest", ] @@ -2246,9 +2342,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.96" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2278,7 +2374,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -2337,7 +2433,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", - "getrandom", + "getrandom 0.2.15", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2371,7 +2467,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -2451,7 +2547,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -2589,7 +2685,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -2655,7 +2751,7 @@ dependencies = [ "http 1.2.0", "httparse", "log", - "rand", + "rand 0.8.5", "rustls 0.22.4", "rustls-pki-types", "sha1", @@ -2702,7 +2798,7 @@ checksum = "536b6812192bda8551cfa0e52524e328c6a951b48e66529ee4522d6c721243d6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -2723,6 +2819,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" @@ -2808,6 +2910,24 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -2830,7 +2950,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -2865,7 +2985,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2879,6 +2999,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasm-streams" version = "0.4.2" @@ -2892,6 +3034,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.8.0", + "hashbrown 0.15.2", + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.77" @@ -3134,6 +3288,94 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.8.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "write16" version = "1.0.0" @@ -3172,7 +3414,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", "synstructure", ] @@ -3194,7 +3436,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] [[package]] @@ -3214,7 +3456,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", "synstructure", ] @@ -3243,5 +3485,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.117", ] diff --git a/Cargo.toml b/Cargo.toml index 12a811c..e48d6db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,4 +19,5 @@ poise = "0.6.1" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } imap = "3.0.0-alpha.12" mailparse = "0.15" -html2text = "0.12" \ No newline at end of file +html2text = "0.12" +rand = "0.10" \ No newline at end of file diff --git a/src/commands/mod.rs b/src/commands/mod.rs index b114346..12daea8 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,5 +1,7 @@ +mod random; mod set_log_level; +use crate::commands::random::random; use crate::commands::set_log_level::set_log_level; use serenity::all::RoleId; use tracing::{debug, instrument}; @@ -31,7 +33,7 @@ async fn amdctl(ctx: Context<'_>) -> Result<(), Error> { /// Returns a vector containg [Poise Commands][`poise::Command`] pub fn get_commands() -> Vec> { - let commands = vec![amdctl(), set_log_level()]; + let commands = vec![amdctl(), set_log_level(), random()]; debug!(commands = ?commands.iter().map(|c| &c.name).collect::>()); commands } diff --git a/src/commands/random.rs b/src/commands/random.rs new file mode 100644 index 0000000..db19f67 --- /dev/null +++ b/src/commands/random.rs @@ -0,0 +1,32 @@ +use crate::{ + ids::{FIRST_YEAR_ROLE_ID, SECOND_YEAR_ROLE_ID}, + Context, Error, +}; +use rand::seq::IteratorRandom; +use serenity::all::{Mentionable as _, RoleId}; + +#[poise::command(prefix_command)] +pub async fn random(ctx: Context<'_>) -> Result<(), Error> { + let guild = ctx.guild_id().ok_or("No guild id")?; + let members = guild.members(ctx.http(), None, None).await?; + + let selected: Vec<_> = members + .into_iter() + .filter(|m| { + !m.user.bot + && (m.roles.contains(&RoleId::new(FIRST_YEAR_ROLE_ID)) + || m.roles.contains(&RoleId::new(SECOND_YEAR_ROLE_ID))) + }) + .sample(&mut rand::rng(), 5); + + let ping_message = selected + .iter() + .map(|m| m.user.mention().to_string()) + .collect::>() + .join("\n"); + + ctx.say(format!("Pinging 5 members: {}", ping_message)) + .await?; + + Ok(()) +} diff --git a/src/ids.rs b/src/ids.rs index df3780d..220f8eb 100644 --- a/src/ids.rs +++ b/src/ids.rs @@ -47,3 +47,6 @@ pub const GROUP_ONE_STATUS_UPDATE_CHANNEL_ID: u64 = 1225098248293716008; pub const GROUP_TWO_STATUS_UPDATE_CHANNEL_ID: u64 = 1225098298935738489; pub const GROUP_THREE_STATUS_UPDATE_CHANNEL_ID: u64 = 1225098353378070710; pub const GROUP_FOUR_STATUS_UPDATE_CHANNEL_ID: u64 = 1225098407216156712; + +pub const FIRST_YEAR_ROLE_ID: u64 = 1283689015450669108; +pub const SECOND_YEAR_ROLE_ID: u64 = 1288903184990994522; From 08dcde9336b1e2bfe0b36f6fe6cf10f3f9464a38 Mon Sep 17 00:00:00 2001 From: AnandajithS Date: Wed, 17 Jun 2026 21:42:46 +0530 Subject: [PATCH 2/4] fix: convert random to slash command --- src/commands/random.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/random.rs b/src/commands/random.rs index db19f67..ee975f2 100644 --- a/src/commands/random.rs +++ b/src/commands/random.rs @@ -5,7 +5,7 @@ use crate::{ use rand::seq::IteratorRandom; use serenity::all::{Mentionable as _, RoleId}; -#[poise::command(prefix_command)] +#[poise::command(slash_command)] pub async fn random(ctx: Context<'_>) -> Result<(), Error> { let guild = ctx.guild_id().ok_or("No guild id")?; let members = guild.members(ctx.http(), None, None).await?; From df10f431e291715e6811fbe2db24cf8a32eb339e Mon Sep 17 00:00:00 2001 From: AnandajithS Date: Wed, 17 Jun 2026 21:58:04 +0530 Subject: [PATCH 3/4] feat: avoid recently selected members --- Cargo.lock | 261 ++--------------------------------------- Cargo.toml | 2 +- src/commands/random.rs | 75 ++++++++++-- src/main.rs | 7 +- 4 files changed, 85 insertions(+), 260 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53a9650..e795852 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,7 +45,7 @@ dependencies = [ "imap", "mailparse", "poise", - "rand 0.10.0", + "rand", "reqwest 0.12.23", "serde", "serde_json", @@ -226,17 +226,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chacha20" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "rand_core 0.10.0", -] - [[package]] name = "charset" version = "0.1.5" @@ -307,15 +296,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpufeatures" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" -dependencies = [ - "libc", -] - [[package]] name = "crc32fast" version = "1.4.2" @@ -509,12 +489,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foreign-types" version = "0.3.2" @@ -656,20 +630,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "rand_core 0.10.0", - "wasip2", - "wasip3", -] - [[package]] name = "gimli" version = "0.31.1" @@ -731,9 +691,6 @@ name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -dependencies = [ - "foldhash", -] [[package]] name = "heck" @@ -741,12 +698,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - [[package]] name = "html2text" version = "0.12.6" @@ -1100,12 +1051,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -1167,7 +1112,6 @@ checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", - "serde", ] [[package]] @@ -1219,12 +1163,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "levenshtein" version = "1.0.5" @@ -1501,7 +1439,7 @@ version = "0.18.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -1572,7 +1510,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared 0.11.3", - "rand 0.8.5", + "rand", ] [[package]] @@ -1661,16 +1599,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - [[package]] name = "proc-macro2" version = "1.0.93" @@ -1719,12 +1647,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "640c9bd8497b02465aeef5375144c26062e0dcd5939dfcbb0f5db76cb8c17c73" -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - [[package]] name = "rand" version = "0.8.5" @@ -1733,18 +1655,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" -dependencies = [ - "chacha20", - "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core", ] [[package]] @@ -1754,7 +1665,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -1763,15 +1674,9 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom", ] -[[package]] -name = "rand_core" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" - [[package]] name = "redox_syscall" version = "0.5.8" @@ -1902,7 +1807,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", "spin", "untrusted", @@ -2199,7 +2104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures 0.2.17", + "cpufeatures", "digest", ] @@ -2433,7 +2338,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", - "getrandom 0.2.15", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2751,7 +2656,7 @@ dependencies = [ "http 1.2.0", "httparse", "log", - "rand 0.8.5", + "rand", "rustls 0.22.4", "rustls-pki-types", "sha1", @@ -2819,12 +2724,6 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "untrusted" version = "0.9.0" @@ -2910,24 +2809,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -2999,28 +2880,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - [[package]] name = "wasm-streams" version = "0.4.2" @@ -3034,18 +2893,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.8.0", - "hashbrown 0.15.2", - "indexmap", - "semver", -] - [[package]] name = "web-sys" version = "0.3.77" @@ -3288,94 +3135,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.8.0", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - [[package]] name = "write16" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index e48d6db..ca65bce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,4 @@ tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } imap = "3.0.0-alpha.12" mailparse = "0.15" html2text = "0.12" -rand = "0.10" \ No newline at end of file +rand = "0.8.5" \ No newline at end of file diff --git a/src/commands/random.rs b/src/commands/random.rs index ee975f2..e21f9ce 100644 --- a/src/commands/random.rs +++ b/src/commands/random.rs @@ -3,21 +3,66 @@ use crate::{ Context, Error, }; use rand::seq::IteratorRandom; -use serenity::all::{Mentionable as _, RoleId}; +use serenity::all::{Mentionable as _, RoleId, UserId}; +use std::collections::HashSet; #[poise::command(slash_command)] pub async fn random(ctx: Context<'_>) -> Result<(), Error> { let guild = ctx.guild_id().ok_or("No guild id")?; let members = guild.members(ctx.http(), None, None).await?; - let selected: Vec<_> = members + let first_year_role = RoleId::new(FIRST_YEAR_ROLE_ID); + let second_year_role = RoleId::new(SECOND_YEAR_ROLE_ID); + let eligible_members: Vec<_> = members // Filtering out bots and other ineligible members .into_iter() .filter(|m| { !m.user.bot - && (m.roles.contains(&RoleId::new(FIRST_YEAR_ROLE_ID)) - || m.roles.contains(&RoleId::new(SECOND_YEAR_ROLE_ID))) + && (m.roles.contains(&first_year_role) || m.roles.contains(&second_year_role)) }) - .sample(&mut rand::rng(), 5); + .collect(); + + if eligible_members.is_empty() { + ctx.say("No eligible members found.").await?; + return Ok(()); + } + + let recent_picks = { + // Accessing recently picked members to avoid repetition + let data = ctx.data(); + let recent_random_picks = data.recent_random_picks.lock().unwrap(); + recent_random_picks.clone() + }; + + let available_members: Vec<_> = eligible_members // Members who haven't been picked recently + .iter() + .filter(|member| !recent_picks.contains(&member.user.id)) + .collect(); + + /* Since ThreadRng is not Send, keeping it alive across an .await causes command future to become non-Send. + So, we are enclosing the selection in it's own scope so the ThreadRng is dropped before we hit any .await, + allowing the command future to remain Send + */ + + let selected = { + let mut rng = rand::thread_rng(); + + let mut selected: Vec<_> = available_members.into_iter().choose_multiple(&mut rng, 5); + + if selected.len() < 5 { + // If not enough members are available, fetch recently picked members + let remaining_needed = 5 - selected.len(); + + let selected_ids: HashSet = selected.iter().map(|m| m.user.id).collect(); + + let additional: Vec<_> = eligible_members + .iter() + .filter(|m| !selected_ids.contains(&m.user.id)) + .choose_multiple(&mut rng, remaining_needed); + + selected.extend(additional); + } + selected + }; let ping_message = selected .iter() @@ -25,8 +70,24 @@ pub async fn random(ctx: Context<'_>) -> Result<(), Error> { .collect::>() .join("\n"); - ctx.say(format!("Pinging 5 members: {}", ping_message)) - .await?; + { + let data = ctx.data(); + let mut recent_random_picks = data.recent_random_picks.lock().unwrap(); + recent_random_picks.extend(selected.iter().map(|m| m.user.id)); // Adding selected members to recently picked set + + let eligible_ids: HashSet = eligible_members.iter().map(|m| m.user.id).collect(); + recent_random_picks.retain(|user_id| eligible_ids.contains(user_id)); + if recent_random_picks.len() >= eligible_ids.len() { + // If all eligible members have been picked atleast once, clear the recently picked set + recent_random_picks.clear(); + } + } + ctx.say(format!( + "Pinging {} members: {}", + selected.len(), + ping_message + )) + .await?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index ca94b3a..59fed8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,10 @@ use serenity::{ use trace::{setup_tracing, ReloadHandle}; use tracing::{debug, info, instrument}; -use std::collections::HashMap; +use std::{ + collections::{HashMap, HashSet}, + sync::{Arc, Mutex}, +}; type Error = Box; type Context<'a> = PoiseContext<'a, Data, Error>; @@ -49,6 +52,7 @@ type Context<'a> = PoiseContext<'a, Data, Error>; #[derive(Clone)] struct Data { reaction_roles: HashMap, + recent_random_picks: Arc>>, log_reload_handle: ReloadHandle, graphql_client: GraphQLClient, } @@ -58,6 +62,7 @@ impl Data { fn new(reload_handle: ReloadHandle, root_url: String, api_key: String) -> Self { Data { reaction_roles: HashMap::new(), + recent_random_picks: Arc::new(Mutex::new(HashSet::new())), log_reload_handle: reload_handle, graphql_client: GraphQLClient::new(root_url, api_key), } From 487732d9c9c136e9e7e4da3a02764ea1a48cb5ee Mon Sep 17 00:00:00 2001 From: AnandajithS Date: Fri, 17 Jul 2026 00:49:31 +0530 Subject: [PATCH 4/4] feat: Add role based random selection and persistent recent picks --- .env.sample | 1 + src/commands/random.rs | 45 ++++++++++++++++++++++++++++++------------ src/config.rs | 3 +++ src/main.rs | 33 +++++++++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 15 deletions(-) diff --git a/.env.sample b/.env.sample index e7ce847..1101911 100644 --- a/.env.sample +++ b/.env.sample @@ -3,6 +3,7 @@ ROOT_URL=https://root.amfoss.in/ OWNER_ID= DEBUG=true ENABLE_DEBUG_LIBRARIES=false +RECENT_PICKS_PATH= AMD_API_KEY= AMD_APP_PASSWORD= AMD_EMAIL_ID= diff --git a/src/commands/random.rs b/src/commands/random.rs index e21f9ce..43cf149 100644 --- a/src/commands/random.rs +++ b/src/commands/random.rs @@ -1,24 +1,40 @@ use crate::{ - ids::{FIRST_YEAR_ROLE_ID, SECOND_YEAR_ROLE_ID}, + ids::{FIRST_YEAR_ROLE_ID, SECOND_YEAR_ROLE_ID, THIRD_YEAR_ROLE_ID}, Context, Error, }; use rand::seq::IteratorRandom; -use serenity::all::{Mentionable as _, RoleId, UserId}; +use serenity::all::{Mentionable as _, Role, RoleId, UserId}; use std::collections::HashSet; #[poise::command(slash_command)] -pub async fn random(ctx: Context<'_>) -> Result<(), Error> { +pub async fn random( + ctx: Context<'_>, + count: Option, + role1: Option, + role2: Option, + role3: Option, +) -> Result<(), Error> { let guild = ctx.guild_id().ok_or("No guild id")?; let members = guild.members(ctx.http(), None, None).await?; - let first_year_role = RoleId::new(FIRST_YEAR_ROLE_ID); - let second_year_role = RoleId::new(SECOND_YEAR_ROLE_ID); + let count = count.unwrap_or(3) as usize; + let mut selected_roles: HashSet = [role1, role2, role3] + .into_iter() + .flatten() + .map(|role| role.id) + .collect(); + + if selected_roles.is_empty() { + selected_roles.extend([ + RoleId::new(FIRST_YEAR_ROLE_ID), + RoleId::new(SECOND_YEAR_ROLE_ID), + RoleId::new(THIRD_YEAR_ROLE_ID), + ]); + } + let eligible_members: Vec<_> = members // Filtering out bots and other ineligible members .into_iter() - .filter(|m| { - !m.user.bot - && (m.roles.contains(&first_year_role) || m.roles.contains(&second_year_role)) - }) + .filter(|m| !m.user.bot && (m.roles.iter().any(|role| selected_roles.contains(role)))) .collect(); if eligible_members.is_empty() { @@ -46,11 +62,13 @@ pub async fn random(ctx: Context<'_>) -> Result<(), Error> { let selected = { let mut rng = rand::thread_rng(); - let mut selected: Vec<_> = available_members.into_iter().choose_multiple(&mut rng, 5); + let mut selected: Vec<_> = available_members + .into_iter() + .choose_multiple(&mut rng, count); - if selected.len() < 5 { + if selected.len() < count { // If not enough members are available, fetch recently picked members - let remaining_needed = 5 - selected.len(); + let remaining_needed = count - selected.len(); let selected_ids: HashSet = selected.iter().map(|m| m.user.id).collect(); @@ -81,7 +99,8 @@ pub async fn random(ctx: Context<'_>) -> Result<(), Error> { // If all eligible members have been picked atleast once, clear the recently picked set recent_random_picks.clear(); } - } + } // guard dropped here, mutex unlocked + ctx.data().save_recent_picks(); ctx.say(format!( "Pinging {} members: {}", selected.len(), diff --git a/src/config.rs b/src/config.rs index ad63e4f..66df091 100644 --- a/src/config.rs +++ b/src/config.rs @@ -35,6 +35,7 @@ pub struct Config { pub prefix_string: String, pub root_url: String, pub api_key: String, + pub recent_picks_path: String, } impl Default for Config { @@ -48,6 +49,8 @@ impl Default for Config { prefix_string: String::from("$"), root_url: std::env::var("ROOT_URL").expect("ROOT_URL was not found in env"), api_key: std::env::var("AMD_API_KEY").expect("AMD_API_KEY was not found in env"), + recent_picks_path: std::env::var("RECENT_PICKS_PATH") + .unwrap_or_else(|_| String::from("data/recent_picks.json")), } } } diff --git a/src/main.rs b/src/main.rs index 59fed8b..de181b5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,7 @@ use tracing::{debug, info, instrument}; use std::{ collections::{HashMap, HashSet}, + path::PathBuf, sync::{Arc, Mutex}, }; @@ -53,20 +54,47 @@ type Context<'a> = PoiseContext<'a, Data, Error>; struct Data { reaction_roles: HashMap, recent_random_picks: Arc>>, + recent_picks_path: PathBuf, log_reload_handle: ReloadHandle, graphql_client: GraphQLClient, } impl Data { /// Returns a new [`Data`] with an empty `reaction_roles` field and the passed-in `reload_handle`. - fn new(reload_handle: ReloadHandle, root_url: String, api_key: String) -> Self { + fn new( + reload_handle: ReloadHandle, + root_url: String, + api_key: String, + recent_picks_path: String, + ) -> Self { + let recent_picks_path = PathBuf::from(recent_picks_path); + let recent_random_picks = Arc::new(Mutex::new(Self::load_recent_picks(&recent_picks_path))); Data { reaction_roles: HashMap::new(), - recent_random_picks: Arc::new(Mutex::new(HashSet::new())), + recent_random_picks, + recent_picks_path, log_reload_handle: reload_handle, graphql_client: GraphQLClient::new(root_url, api_key), } } + + fn load_recent_picks(path: &PathBuf) -> HashSet { + std::fs::read_to_string(path) + .ok() + .and_then(|s| serde_json::from_str(&s).ok()) + .unwrap_or_default() + } + + fn save_recent_picks(&self) { + let picks = self.recent_random_picks.lock().unwrap(); + + if let Some(parent) = self.recent_picks_path.parent() { + std::fs::create_dir_all(parent).unwrap(); + } + + let json = serde_json::to_string(&*picks).unwrap(); + std::fs::write(&self.recent_picks_path, json).unwrap(); + } } /// Builds a [`poise::Framework`] with the given arguments and commands from [`commands::get_commands`]. @@ -104,6 +132,7 @@ fn prepare_data(config: &Config, reload_handle: ReloadHandle) -> Data { reload_handle, config.root_url.clone(), config.api_key.clone(), + config.recent_picks_path.clone(), ); data.populate_with_reaction_roles(); data