diff --git a/Cargo.lock b/Cargo.lock index e3c6f52..5a4c974 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,6 +185,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "bytecount" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" + [[package]] name = "bytemuck" version = "1.14.0" @@ -203,6 +209,37 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.83" @@ -254,7 +291,7 @@ dependencies = [ [[package]] name = "command_attr" version = "0.5.0" -source = "git+https://github.com/GnomedDev/serenity?branch=typesize#01f16c1d7563fdc4b8881f9917218167bd162b49" +source = "git+https://github.com/GnomedDev/serenity?branch=typesize#45e8aa2c86028a1b172c405b4d4c267c10fc1beb" dependencies = [ "proc-macro2", "quote", @@ -528,6 +565,7 @@ dependencies = [ "tokio", "toml", "tracing", + "typesize", ] [[package]] @@ -644,6 +682,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + [[package]] name = "etcetera" version = "0.8.0" @@ -872,6 +919,12 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "h2" version = "0.3.22" @@ -1241,6 +1294,21 @@ dependencies = [ "unicase", ] +[[package]] +name = "mini-moka" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e0b72e7c9042467008b10279fc732326bd605459ae03bda88825909dd19b56" +dependencies = [ + "crossbeam-channel", + "crossbeam-utils", + "dashmap", + "skeptic", + "smallvec", + "tagptr", + "triomphe", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1580,6 +1648,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + [[package]] name = "quote" version = "1.0.33" @@ -1917,6 +1996,15 @@ dependencies = [ "cipher", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.22" @@ -1981,11 +2069,20 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + [[package]] name = "serde" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] @@ -2013,9 +2110,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.192" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", @@ -2068,7 +2165,7 @@ dependencies = [ [[package]] name = "serenity" version = "0.12.0-rc" -source = "git+https://github.com/GnomedDev/serenity?branch=typesize#01f16c1d7563fdc4b8881f9917218167bd162b49" +source = "git+https://github.com/GnomedDev/serenity?branch=typesize#45e8aa2c86028a1b172c405b4d4c267c10fc1beb" dependencies = [ "arrayvec", "async-trait", @@ -2103,7 +2200,7 @@ dependencies = [ [[package]] name = "serenity-voice-model" version = "0.1.1" -source = "git+https://github.com/GnomedDev/serenity?branch=typesize#01f16c1d7563fdc4b8881f9917218167bd162b49" +source = "git+https://github.com/GnomedDev/serenity?branch=typesize#45e8aa2c86028a1b172c405b4d4c267c10fc1beb" dependencies = [ "bitflags 2.4.1", "num-traits", @@ -2152,6 +2249,21 @@ dependencies = [ "libc", ] +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + [[package]] name = "slab" version = "0.4.9" @@ -2599,6 +2711,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tempfile" version = "3.8.1" @@ -2915,6 +3033,12 @@ dependencies = [ "strength_reduce", ] +[[package]] +name = "triomphe" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee8098afad3fb0c54a9007aab6804558410503ad676d4633f9c2559a00ac0f" + [[package]] name = "try-lock" version = "0.2.4" @@ -3019,13 +3143,15 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typesize" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca73864118741e554b48344182b9b8a76332e9899976c0319118d8139dbde5c" +checksum = "3e43a952445d2d9df648a822545093c01699df209ceda4df5ac78fef8969c61c" dependencies = [ "chrono", "dashmap", "hashbrown", + "mini-moka", + "parking_lot", "secrecy", "serde_json", "time", @@ -3035,11 +3161,10 @@ dependencies = [ [[package]] name = "typesize-derive" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952e2645c35faf5f361c03b235a068caace146d889dc3fc464efde95cc5f2260" +checksum = "5274e4d582fd16b83bf7949cc44d6610d3b0290e441d9e5c337fdda9a003849f" dependencies = [ - "either", "proc-macro2", "quote", "syn 2.0.39", @@ -3160,6 +3285,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -3311,6 +3446,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 803c543..4e9d678 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ strum_macros = "0.25" arrayvec = "0.7.4" bitflags = "2.4.1" paste = "1.0.14" +typesize = "0.1.2" [dependencies.symphonia] features = ["mp3", "ogg", "wav", "pcm"] diff --git a/src/commands/owner.rs b/src/commands/owner.rs index d8bef00..4a2614f 100644 --- a/src/commands/owner.rs +++ b/src/commands/owner.rs @@ -14,14 +14,22 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::{borrow::Cow, collections::HashSet, num::NonZeroU16, sync::atomic::Ordering::SeqCst}; +use std::{ + borrow::Cow, + collections::{HashMap, HashSet}, + num::NonZeroU16, + sync::atomic::Ordering::SeqCst, +}; use self::serenity::builder::*; use num_format::{Locale, ToFormattedString}; use poise::{futures_util::TryStreamExt, serenity_prelude as serenity, CreateReply}; +use rand::{rngs::ThreadRng, Rng}; +use typesize::TypeSize; use crate::{ funcs::dm_generic, + opt_ext::OptionTryUnwrap, structs::{Command, CommandResult, Context, PrefixContext, TTSModeChoice}, }; @@ -327,28 +335,96 @@ pub async fn leave(ctx: Context<'_>) -> CommandResult { .map_err(Into::into) } +fn choose_random<'a, T>(rng: &mut ThreadRng, container: &'a [T]) -> &'a T { + let index = rng.gen_range(0..container.len()); + &container[index] +} + +fn choose_random_map<'a, K: std::hash::Hash + Eq, V>( + rng: &mut ThreadRng, + map: &'a HashMap, +) -> Option<&'a V> { + map.get(map.keys().nth(rng.gen_range(0..map.len()))?) +} + +fn random_guild<'a>( + rng: &mut ThreadRng, + cache: &'a serenity::Cache, +) -> Option> { + cache.guild(choose_random(rng, &cache.guilds())) +} + #[poise::command(prefix_command, owners_only)] -pub async fn cache_info(ctx: Context<'_>) -> CommandResult { - let mut embed = CreateEmbed::default().title("Cache Statistics"); - for cache in ctx.cache().get_statistics() { - let size = (cache.size / 1000).to_formatted_string(&Locale::en); - let (count, size_per) = if cache.count == 0 { - (Cow::Borrowed("0"), Cow::Borrowed("N/A")) - } else { - let count = cache.count.to_formatted_string(&Locale::en); - let mut size_per = (cache.size / cache.count).to_formatted_string(&Locale::en); - size_per.push('b'); +pub async fn cache_info(ctx: Context<'_>, kind: Option) -> CommandResult { + struct Field { + name: String, + size: usize, + value: String, + is_collection: bool, + } - (Cow::Owned(count), Cow::Owned(size_per)) + let serenity_cache = ctx.cache(); + let cache_stats = { + let mut rng = rand::thread_rng(); + match kind.as_deref() { + Some("guild") => random_guild(&mut rng, serenity_cache) + .try_unwrap()? + .get_size_details(), + Some("channel") => { + let guild = random_guild(&mut rng, serenity_cache).try_unwrap()?; + choose_random_map(&mut rng, &guild.channels) + .try_unwrap()? + .get_size_details() + } + Some("role") => { + let guild = random_guild(&mut rng, serenity_cache).try_unwrap()?; + choose_random_map(&mut rng, &guild.roles) + .try_unwrap()? + .get_size_details() + } + _ => serenity_cache.get_size_details(), + } + }; + + let mut fields = Vec::new(); + for field in cache_stats { + let name = format!("`{}`", field.name); + let size = field.size.to_formatted_string(&Locale::en); + if let Some(count) = field.collection_items { + let (count, size_per) = if count == 0 { + (Cow::Borrowed("0"), Cow::Borrowed("N/A")) + } else { + let count_fmt = count.to_formatted_string(&Locale::en); + let mut size_per = (field.size / count).to_formatted_string(&Locale::en); + size_per.push('b'); + + (Cow::Owned(count_fmt), Cow::Owned(size_per)) + }; + + fields.push(Field { + name, + size: field.size, + is_collection: true, + value: format!("Size: `{size}b`\nCount: `{count}`\nSize per model: `{size_per}`"), + }); + } else { + fields.push(Field { + name, + size: field.size, + is_collection: false, + value: format!("Size: `{size}b`"), + }); }; - - embed = embed.field( - cache.name, - format!("Size: `{size}kb`\nCount: `{count}`\nSize per model: `{size_per}`"), - false, - ); } + fields.sort_by_key(|field| field.size); + fields.sort_by_key(|field| field.is_collection); + fields.reverse(); + + let embed = CreateEmbed::default() + .title("Cache Statistics") + .fields(fields.into_iter().map(|f| (f.name, f.value, true))); + ctx.send(CreateReply::default().embed(embed)).await?; Ok(()) }