From e46f17468453d774b0ab1da39b6ffd65c49e52d8 Mon Sep 17 00:00:00 2001 From: Akinator31 Date: Mon, 17 Nov 2025 15:14:14 +0100 Subject: [PATCH 1/5] feat(shard): insert shard manager in client's data to be able to fetch discord's api latency --- rustmail/src/bot.rs | 16 +++++++++++++++- rustmail/src/config.rs | 20 +++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/rustmail/src/bot.rs b/rustmail/src/bot.rs index ce6f18b9..1f6248f8 100644 --- a/rustmail/src/bot.rs +++ b/rustmail/src/bot.rs @@ -7,8 +7,9 @@ use crate::prelude::panel_commands::*; use crate::prelude::types::*; use base64::Engine; use rand::RngCore; -use serenity::all::{ClientBuilder, GatewayIntents}; +use serenity::all::{ClientBuilder, GatewayIntents, ShardManager}; use serenity::cache::Settings as CacheSettings; +use serenity::prelude::TypeMapKey; use std::collections::HashMap; use std::process; use std::sync::Arc; @@ -16,6 +17,12 @@ use std::time::Duration; use tokio::sync::Mutex; use tokio::{select, spawn}; +pub struct ShardManagerKey; + +impl TypeMapKey for ShardManagerKey { + type Value = Arc; +} + pub async fn init_bot_state() -> Arc> { let pool = init_database().await.expect("An error occured!"); println!("Database connected!"); @@ -136,6 +143,7 @@ pub async fn run_bot( registry.register_command(LogsCommand); registry.register_command(TakeCommand); registry.register_command(ReleaseCommand); + registry.register_command(PingCommand); let registry = Arc::new(registry); @@ -174,6 +182,12 @@ pub async fn run_bot( state_lock.bot_http = Some(client.http.clone()); } + { + let mut data = client.data.write().await; + + data.insert::(client.shard_manager.clone()); + } + if let Err(e) = config.validate_servers(&client.http).await { eprintln!("Configuration validation error: {}", e); eprintln!( diff --git a/rustmail/src/config.rs b/rustmail/src/config.rs index d630a8be..2feb46fc 100644 --- a/rustmail/src/config.rs +++ b/rustmail/src/config.rs @@ -21,7 +21,8 @@ pub struct Config { pub db_pool: Option, pub error_handler: Option>, - pub thread_locks: Arc>>>>, + pub thread_locks: + Arc>>>>, } fn get_local_ip() -> Option { @@ -50,21 +51,30 @@ pub fn load_config(path: &str) -> Option { } if u64::from_str_radix(&config_response.thread.user_message_color, 16).is_err() { - eprintln!("Incorrect user message color in the config.toml! Please put a color in hex format!"); + eprintln!( + "Incorrect user message color in the config.toml! Please put a color in hex format!" + ); return None; } if u64::from_str_radix(&config_response.thread.staff_message_color, 16).is_err() { - eprintln!("Incorrect staff message color in the config.toml! Please put a color in hex format!"); + eprintln!( + "Incorrect staff message color in the config.toml! Please put a color in hex format!" + ); return None; } if u64::from_str_radix(&config_response.reminders.embed_color, 16).is_err() { - eprintln!("Incorrect reminder embed color in the config.toml! Please put a color in hex format!"); + eprintln!( + "Incorrect reminder embed color in the config.toml! Please put a color in hex format!" + ); return None; } - if !config_response.language.is_language_supported(config_response.language.get_default_language()) { + if !config_response + .language + .is_language_supported(config_response.language.get_default_language()) + { eprintln!( "Warning: Default language '{}' is not in supported languages list", config_response.language.default_language From 642a7bd347fdfb019704d0d52324b7b637b1b53b Mon Sep 17 00:00:00 2001 From: Akinator31 Date: Mon, 17 Nov 2025 15:14:29 +0100 Subject: [PATCH 2/5] feat(commands): add base for ping command --- rustmail/src/commands/mod.rs | 2 + rustmail/src/commands/ping/mod.rs | 5 ++ .../src/commands/ping/slash_command/mod.rs | 3 + .../src/commands/ping/slash_command/ping.rs | 77 +++++++++++++++++++ .../src/commands/ping/text_command/mod.rs | 3 + .../src/commands/ping/text_command/ping.rs | 30 ++++++++ .../src/handlers/guild_messages_handler.rs | 1 + rustmail/src/i18n/language/en.rs | 8 ++ rustmail/src/i18n/language/fr.rs | 8 ++ 9 files changed, 137 insertions(+) create mode 100644 rustmail/src/commands/ping/mod.rs create mode 100644 rustmail/src/commands/ping/slash_command/mod.rs create mode 100644 rustmail/src/commands/ping/slash_command/ping.rs create mode 100644 rustmail/src/commands/ping/text_command/mod.rs create mode 100644 rustmail/src/commands/ping/text_command/ping.rs diff --git a/rustmail/src/commands/mod.rs b/rustmail/src/commands/mod.rs index 273a77e3..c55f34b8 100644 --- a/rustmail/src/commands/mod.rs +++ b/rustmail/src/commands/mod.rs @@ -22,6 +22,7 @@ pub mod id; pub mod logs; pub mod move_thread; pub mod new_thread; +pub mod ping; pub mod recover; pub mod release; pub mod remove_reminder; @@ -42,6 +43,7 @@ pub use id::*; pub use logs::*; pub use move_thread::*; pub use new_thread::*; +pub use ping::*; pub use recover::*; pub use release::*; pub use remove_reminder::*; diff --git a/rustmail/src/commands/ping/mod.rs b/rustmail/src/commands/ping/mod.rs new file mode 100644 index 00000000..9317acfa --- /dev/null +++ b/rustmail/src/commands/ping/mod.rs @@ -0,0 +1,5 @@ +mod slash_command; +mod text_command; + +pub use slash_command::*; +pub use text_command::*; diff --git a/rustmail/src/commands/ping/slash_command/mod.rs b/rustmail/src/commands/ping/slash_command/mod.rs new file mode 100644 index 00000000..2df3c1c3 --- /dev/null +++ b/rustmail/src/commands/ping/slash_command/mod.rs @@ -0,0 +1,3 @@ +pub mod ping; + +pub use ping::*; diff --git a/rustmail/src/commands/ping/slash_command/ping.rs b/rustmail/src/commands/ping/slash_command/ping.rs new file mode 100644 index 00000000..a49dc10a --- /dev/null +++ b/rustmail/src/commands/ping/slash_command/ping.rs @@ -0,0 +1,77 @@ +use crate::bot::ShardManagerKey; +use crate::commands::{BoxFuture, CommunityRegistrable, RegistrableCommand}; +use crate::config::Config; +use crate::errors::ModmailResult; +use crate::handlers::InteractionHandler; +use crate::i18n::get_translated_message; +use serenity::FutureExt; +use serenity::all::{CommandInteraction, Context, CreateCommand, ResolvedOption}; +use std::sync::Arc; + +pub struct PingCommand; + +#[async_trait::async_trait] +impl RegistrableCommand for PingCommand { + fn as_community(&self) -> Option<&dyn CommunityRegistrable> { + None + } + + fn name(&self) -> &'static str { + "ping" + } + + fn doc<'a>(&self, config: &'a Config) -> BoxFuture<'a, String> { + async move { get_translated_message(config, "help.ping", None, None, None, None).await } + .boxed() + } + + fn register(&self, config: &Config) -> BoxFuture<'_, Vec> { + let config = config.clone(); + + Box::pin(async move { + let cmd_desc = get_translated_message( + &config, + "slash_command.ping_command_desc", + None, + None, + None, + None, + ) + .await; + + vec![CreateCommand::new(self.name()).description(cmd_desc)] + }) + } + + fn run( + &self, + ctx: &Context, + command: &CommandInteraction, + _options: &[ResolvedOption<'_>], + config: &Config, + _handler: Arc, + ) -> BoxFuture<'_, ModmailResult<()>> { + let ctx = ctx.clone(); + let command = command.clone(); + let config = config.clone(); + + Box::pin(async move { + let shard_manager = ctx + .data + .read() + .await + .get::() + .unwrap() + .clone(); + + let latency = { + let runners = shard_manager.runners.lock().await; + runners.get(&ctx.shard_id).and_then(|runner| runner.latency) + }; + + println!("Latency for shard {}: {:?}", ctx.shard_id, latency); + + Ok(()) + }) + } +} diff --git a/rustmail/src/commands/ping/text_command/mod.rs b/rustmail/src/commands/ping/text_command/mod.rs new file mode 100644 index 00000000..2df3c1c3 --- /dev/null +++ b/rustmail/src/commands/ping/text_command/mod.rs @@ -0,0 +1,3 @@ +pub mod ping; + +pub use ping::*; diff --git a/rustmail/src/commands/ping/text_command/ping.rs b/rustmail/src/commands/ping/text_command/ping.rs new file mode 100644 index 00000000..832e6e55 --- /dev/null +++ b/rustmail/src/commands/ping/text_command/ping.rs @@ -0,0 +1,30 @@ +use crate::bot::ShardManagerKey; +use crate::prelude::config::*; +use crate::prelude::errors::*; +use crate::prelude::handlers::*; +use serenity::all::{Context, Message}; +use std::sync::Arc; + +pub async fn ping( + ctx: Context, + msg: Message, + config: &Config, + _handler: Arc, +) -> ModmailResult<()> { + let shard_manager = ctx + .data + .read() + .await + .get::() + .unwrap() + .clone(); + + let latency = { + let runners = shard_manager.runners.lock().await; + runners.get(&ctx.shard_id).and_then(|runner| runner.latency) + }; + + println!("Latency for shard {}: {:?}", ctx.shard_id, latency); + + Ok(()) +} diff --git a/rustmail/src/handlers/guild_messages_handler.rs b/rustmail/src/handlers/guild_messages_handler.rs index 67faabc2..55ddf01a 100644 --- a/rustmail/src/handlers/guild_messages_handler.rs +++ b/rustmail/src/handlers/guild_messages_handler.rs @@ -77,6 +77,7 @@ impl GuildMessagesHandler { wrap_command!(lock, "logs", logs); wrap_command!(lock, "take", take); wrap_command!(lock, "release", release); + wrap_command!(lock, "ping", ping); drop(lock); h diff --git a/rustmail/src/i18n/language/en.rs b/rustmail/src/i18n/language/en.rs index 6f664dfd..395c8f95 100644 --- a/rustmail/src/i18n/language/en.rs +++ b/rustmail/src/i18n/language/en.rs @@ -883,6 +883,10 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) { "help.release".to_string(), DictionaryMessage::new("Releases ownership of a ticket previously taken with the `!take` command. To release a ticket, use `!release` in the ticket."), ); + dict.messages.insert( + "help.ping".to_string(), + DictionaryMessage::new("Show the actual latency of the Discord API."), + ); dict.messages.insert( "add_reminder.helper".to_string(), DictionaryMessage::new( @@ -928,4 +932,8 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) { "slash_command.help_command_argument_desc".to_string(), DictionaryMessage::new("The command to get help with"), ); + dict.messages.insert( + "slash_command.ping_command_desc".to_string(), + DictionaryMessage::new("Check the discord API latency"), + ); } diff --git a/rustmail/src/i18n/language/fr.rs b/rustmail/src/i18n/language/fr.rs index 4a817701..f19fa40c 100644 --- a/rustmail/src/i18n/language/fr.rs +++ b/rustmail/src/i18n/language/fr.rs @@ -904,6 +904,10 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) { "help.release".to_string(), DictionaryMessage::new("Permet de ne plus prendre en charge un ticket pris en charge via la commande `take`. Pour libérer un ticket, faites `!release` dans le ticket."), ); + dict.messages.insert( + "help.ping".to_string(), + DictionaryMessage::new("Permet d'afficher la latence actuelle de l'API Discord."), + ); dict.messages.insert( "add_reminder.helper".to_string(), DictionaryMessage::new("Format incorrect. Utilisation : `{prefix}remind ou {prefix}rem [contenu du rappel]`"), @@ -940,4 +944,8 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) { "slash_command.help_command_argument_desc".to_string(), DictionaryMessage::new("Le nom de la commande pour laquelle vous souhaitez de l'aide"), ); + dict.messages.insert( + "slash_command.ping_command_desc".to_string(), + DictionaryMessage::new("Afficher la latence actuelle de l'API Discord"), + ); } From a88d03e7bb0d618b3c3fda2bdb508175a8001139 Mon Sep 17 00:00:00 2001 From: Akinator31 Date: Mon, 17 Nov 2025 18:25:13 +0100 Subject: [PATCH 3/5] refactor(init): use rng instead of deprecated thread_rng --- rustmail/src/bot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustmail/src/bot.rs b/rustmail/src/bot.rs index 1f6248f8..922fad8f 100644 --- a/rustmail/src/bot.rs +++ b/rustmail/src/bot.rs @@ -28,7 +28,7 @@ pub async fn init_bot_state() -> Arc> { println!("Database connected!"); let mut bytes = [0u8; 32]; - rand::thread_rng().fill_bytes(&mut bytes); + rand::rng().fill_bytes(&mut bytes); let token = base64::engine::general_purpose::STANDARD.encode(&bytes); let config = load_config("config.toml"); From a21b34daa3693dbfbcd6f7ee95b9a60067d2a126 Mon Sep 17 00:00:00 2001 From: Akinator31 Date: Mon, 17 Nov 2025 22:02:53 +0100 Subject: [PATCH 4/5] feat(commands): add complete ping command --- rustmail/src/bot.rs | 1 - .../src/commands/ping/slash_command/ping.rs | 18 ++++++++++++++++-- .../src/commands/ping/text_command/ping.rs | 12 +++++++++++- rustmail/src/i18n/language/en.rs | 8 ++++++-- rustmail/src/i18n/language/fr.rs | 8 ++++++-- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/rustmail/src/bot.rs b/rustmail/src/bot.rs index 922fad8f..96c5b1eb 100644 --- a/rustmail/src/bot.rs +++ b/rustmail/src/bot.rs @@ -184,7 +184,6 @@ pub async fn run_bot( { let mut data = client.data.write().await; - data.insert::(client.shard_manager.clone()); } diff --git a/rustmail/src/commands/ping/slash_command/ping.rs b/rustmail/src/commands/ping/slash_command/ping.rs index a49dc10a..76165554 100644 --- a/rustmail/src/commands/ping/slash_command/ping.rs +++ b/rustmail/src/commands/ping/slash_command/ping.rs @@ -1,12 +1,15 @@ +use std::collections::HashMap; use crate::bot::ShardManagerKey; use crate::commands::{BoxFuture, CommunityRegistrable, RegistrableCommand}; use crate::config::Config; -use crate::errors::ModmailResult; +use crate::errors::{DiscordError, ModmailError, ModmailResult}; use crate::handlers::InteractionHandler; use crate::i18n::get_translated_message; use serenity::FutureExt; use serenity::all::{CommandInteraction, Context, CreateCommand, ResolvedOption}; use std::sync::Arc; +use std::time::Duration; +use crate::utils::{defer_response, MessageBuilder}; pub struct PingCommand; @@ -56,6 +59,8 @@ impl RegistrableCommand for PingCommand { let config = config.clone(); Box::pin(async move { + defer_response(&ctx, &command).await?; + let shard_manager = ctx .data .read() @@ -69,7 +74,16 @@ impl RegistrableCommand for PingCommand { runners.get(&ctx.shard_id).and_then(|runner| runner.latency) }; - println!("Latency for shard {}: {:?}", ctx.shard_id, latency); + let mut params = HashMap::new(); + params.insert("latency".to_string(), format!("{:?}", latency.unwrap_or(Duration::default()).as_millis())); + + let response = MessageBuilder::system_message(&ctx, &config) + .translated_content("slash_command.ping_command", Some(¶ms), None, None).await + .to_channel(command.channel_id) + .build_interaction_message_followup().await; + + command.create_followup(&ctx.http, response).await + .map_err(|e| ModmailError::Discord(DiscordError::ApiError(e.to_string())))?; Ok(()) }) diff --git a/rustmail/src/commands/ping/text_command/ping.rs b/rustmail/src/commands/ping/text_command/ping.rs index 832e6e55..4cc04866 100644 --- a/rustmail/src/commands/ping/text_command/ping.rs +++ b/rustmail/src/commands/ping/text_command/ping.rs @@ -1,9 +1,12 @@ +use std::collections::HashMap; use crate::bot::ShardManagerKey; use crate::prelude::config::*; use crate::prelude::errors::*; use crate::prelude::handlers::*; use serenity::all::{Context, Message}; use std::sync::Arc; +use std::time::Duration; +use crate::utils::MessageBuilder; pub async fn ping( ctx: Context, @@ -24,7 +27,14 @@ pub async fn ping( runners.get(&ctx.shard_id).and_then(|runner| runner.latency) }; - println!("Latency for shard {}: {:?}", ctx.shard_id, latency); + let mut params = HashMap::new(); + params.insert("latency".to_string(), format!("{:?}", latency.unwrap_or(Duration::default()).as_millis())); + + let _ = MessageBuilder::system_message(&ctx, &config) + .translated_content("slash_command.ping_command", Some(¶ms), None, None).await + .to_channel(msg.channel_id) + .send(true).await + .map_err(|e| ModmailError::Discord(DiscordError::ApiError(e.to_string())))?; Ok(()) } diff --git a/rustmail/src/i18n/language/en.rs b/rustmail/src/i18n/language/en.rs index 395c8f95..072e1b2d 100644 --- a/rustmail/src/i18n/language/en.rs +++ b/rustmail/src/i18n/language/en.rs @@ -885,7 +885,7 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) { ); dict.messages.insert( "help.ping".to_string(), - DictionaryMessage::new("Show the actual latency of the Discord API."), + DictionaryMessage::new("Show the actual latency of the bot."), ); dict.messages.insert( "add_reminder.helper".to_string(), @@ -934,6 +934,10 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) { ); dict.messages.insert( "slash_command.ping_command_desc".to_string(), - DictionaryMessage::new("Check the discord API latency"), + DictionaryMessage::new("Check the discord bot latency."), + ); + dict.messages.insert( + "slash_command.ping_command".to_string(), + DictionaryMessage::new("The Discord bot latency is **{latency}** ms."), ); } diff --git a/rustmail/src/i18n/language/fr.rs b/rustmail/src/i18n/language/fr.rs index f19fa40c..62c72837 100644 --- a/rustmail/src/i18n/language/fr.rs +++ b/rustmail/src/i18n/language/fr.rs @@ -906,7 +906,7 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) { ); dict.messages.insert( "help.ping".to_string(), - DictionaryMessage::new("Permet d'afficher la latence actuelle de l'API Discord."), + DictionaryMessage::new("Permet d'afficher la latence actuelle du bot."), ); dict.messages.insert( "add_reminder.helper".to_string(), @@ -946,6 +946,10 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) { ); dict.messages.insert( "slash_command.ping_command_desc".to_string(), - DictionaryMessage::new("Afficher la latence actuelle de l'API Discord"), + DictionaryMessage::new("Afficher la latence actuelle du bot."), + ); + dict.messages.insert( + "slash_command.ping_command".to_string(), + DictionaryMessage::new("La latence actuelle du bot est de **{latency}** ms."), ); } From 7978a8cd355df8e2d06ace11eec6ef6019c6a31c Mon Sep 17 00:00:00 2001 From: Akinator31 Date: Tue, 18 Nov 2025 08:59:09 +0100 Subject: [PATCH 5/5] refactor(ping): add more info in ping command --- .../src/commands/ping/slash_command/ping.rs | 50 +++++++++++++++---- .../src/commands/ping/text_command/ping.rs | 47 +++++++++++++---- rustmail/src/errors/dictionary.rs | 3 ++ rustmail/src/errors/types.rs | 2 + rustmail/src/i18n/language/en.rs | 10 ++-- rustmail/src/i18n/language/fr.rs | 6 ++- rustmail/src/utils/message/message_builder.rs | 3 ++ 7 files changed, 97 insertions(+), 24 deletions(-) diff --git a/rustmail/src/commands/ping/slash_command/ping.rs b/rustmail/src/commands/ping/slash_command/ping.rs index 76165554..d2197f46 100644 --- a/rustmail/src/commands/ping/slash_command/ping.rs +++ b/rustmail/src/commands/ping/slash_command/ping.rs @@ -1,15 +1,17 @@ -use std::collections::HashMap; use crate::bot::ShardManagerKey; use crate::commands::{BoxFuture, CommunityRegistrable, RegistrableCommand}; use crate::config::Config; use crate::errors::{DiscordError, ModmailError, ModmailResult}; use crate::handlers::InteractionHandler; use crate::i18n::get_translated_message; +use crate::utils::{MessageBuilder, defer_response}; +use chrono::Utc; use serenity::FutureExt; use serenity::all::{CommandInteraction, Context, CreateCommand, ResolvedOption}; +use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; -use crate::utils::{defer_response, MessageBuilder}; +use tokio::time::Instant; pub struct PingCommand; @@ -60,30 +62,58 @@ impl RegistrableCommand for PingCommand { Box::pin(async move { defer_response(&ctx, &command).await?; + let response = MessageBuilder::system_message(&ctx, &config) + .content("...") + .to_channel(command.channel_id) + .build_interaction_message_followup() + .await; let shard_manager = ctx .data .read() .await .get::() - .unwrap() - .clone(); + .cloned() + .ok_or(ModmailError::Discord(DiscordError::ShardManagerNotFound))?; - let latency = { + let time_before = Instant::now(); + let mut res = command.create_followup(&ctx.http, response).await?; + let msg_send_ping = time_before.elapsed().as_millis(); + + let gateway_ping = { let runners = shard_manager.runners.lock().await; runners.get(&ctx.shard_id).and_then(|runner| runner.latency) }; + let start = Instant::now(); + ctx.http.get_gateway().await?; + let api_ping = start.elapsed(); + let mut params = HashMap::new(); - params.insert("latency".to_string(), format!("{:?}", latency.unwrap_or(Duration::default()).as_millis())); + params.insert( + "gateway_latency".to_string(), + format!( + "{:?}", + gateway_ping.unwrap_or(Duration::default()).as_millis() + ), + ); + params.insert( + "api_latency".to_string(), + format!("{:?}", api_ping.as_millis()), + ); + params.insert( + "message_latency".to_string(), + format!("{:?}", msg_send_ping), + ); let response = MessageBuilder::system_message(&ctx, &config) - .translated_content("slash_command.ping_command", Some(¶ms), None, None).await + .translated_content("slash_command.ping_command", Some(¶ms), None, None) + .await .to_channel(command.channel_id) - .build_interaction_message_followup().await; + .build_edit_message() + .await; - command.create_followup(&ctx.http, response).await - .map_err(|e| ModmailError::Discord(DiscordError::ApiError(e.to_string())))?; + res.edit(&ctx.http, response).await?; Ok(()) }) diff --git a/rustmail/src/commands/ping/text_command/ping.rs b/rustmail/src/commands/ping/text_command/ping.rs index 4cc04866..d43a24e2 100644 --- a/rustmail/src/commands/ping/text_command/ping.rs +++ b/rustmail/src/commands/ping/text_command/ping.rs @@ -1,12 +1,14 @@ -use std::collections::HashMap; use crate::bot::ShardManagerKey; use crate::prelude::config::*; use crate::prelude::errors::*; use crate::prelude::handlers::*; +use crate::utils::MessageBuilder; +use chrono::Utc; use serenity::all::{Context, Message}; +use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; -use crate::utils::MessageBuilder; +use tokio::time::Instant; pub async fn ping( ctx: Context, @@ -19,22 +21,47 @@ pub async fn ping( .read() .await .get::() - .unwrap() - .clone(); + .cloned() + .ok_or(ModmailError::Discord(DiscordError::ShardManagerNotFound))?; - let latency = { + let time_before = Instant::now(); + let mut res = msg.reply(&ctx.http, "...").await?; + let msg_send_ping = time_before.elapsed().as_millis(); + + let gateway_ping = { let runners = shard_manager.runners.lock().await; runners.get(&ctx.shard_id).and_then(|runner| runner.latency) }; + let start = Instant::now(); + ctx.http.get_gateway().await?; + let api_ping = start.elapsed(); + let mut params = HashMap::new(); - params.insert("latency".to_string(), format!("{:?}", latency.unwrap_or(Duration::default()).as_millis())); + params.insert( + "gateway_latency".to_string(), + format!( + "{:?}", + gateway_ping.unwrap_or(Duration::default()).as_millis() + ), + ); + params.insert( + "api_latency".to_string(), + format!("{:?}", api_ping.as_millis()), + ); + params.insert( + "message_latency".to_string(), + format!("{:?}", msg_send_ping), + ); - let _ = MessageBuilder::system_message(&ctx, &config) - .translated_content("slash_command.ping_command", Some(¶ms), None, None).await + let edited_msg = MessageBuilder::system_message(&ctx, &config) + .translated_content("slash_command.ping_command", Some(¶ms), None, None) + .await .to_channel(msg.channel_id) - .send(true).await - .map_err(|e| ModmailError::Discord(DiscordError::ApiError(e.to_string())))?; + .build_edit_message() + .await; + + res.edit(&ctx.http, edited_msg).await?; Ok(()) } diff --git a/rustmail/src/errors/dictionary.rs b/rustmail/src/errors/dictionary.rs index 54e42c5b..d2f2278b 100644 --- a/rustmail/src/errors/dictionary.rs +++ b/rustmail/src/errors/dictionary.rs @@ -188,6 +188,9 @@ impl DictionaryManager { DiscordError::UserIsABot => ("discord.user_is_a_bot".to_string(), None), DiscordError::PermissionDenied => ("discord.permission_denied".to_string(), None), DiscordError::DmCreationFailed => ("discord.dm_creation_failed".to_string(), None), + DiscordError::ShardManagerNotFound => { + ("discord.shard_manager_not_found".to_string(), None) + } _ => ("discord.api_error".to_string(), None), }, ModmailError::Command(cmd_err) => match cmd_err { diff --git a/rustmail/src/errors/types.rs b/rustmail/src/errors/types.rs index 2ccca1d4..093ce033 100644 --- a/rustmail/src/errors/types.rs +++ b/rustmail/src/errors/types.rs @@ -56,6 +56,7 @@ pub enum DiscordError { DmCreationFailed, FailedToFetchCategories, FailedToMoveChannel, + ShardManagerNotFound, } #[derive(Debug, Clone)] @@ -198,6 +199,7 @@ impl fmt::Display for DiscordError { DiscordError::DmCreationFailed => write!(f, "Failed to create DM channel"), DiscordError::FailedToFetchCategories => write!(f, "Failed to fetch categories"), DiscordError::FailedToMoveChannel => write!(f, "Failed to move_thread channel"), + DiscordError::ShardManagerNotFound => write!(f, "Shard manager not found"), } } } diff --git a/rustmail/src/i18n/language/en.rs b/rustmail/src/i18n/language/en.rs index 072e1b2d..c61ec0f4 100644 --- a/rustmail/src/i18n/language/en.rs +++ b/rustmail/src/i18n/language/en.rs @@ -50,6 +50,10 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) { "discord.user_is_a_bot".to_string(), DictionaryMessage::new("The specified user is a rustmail."), ); + dict.messages.insert( + "discord.shard_manager_not_found".to_string(), + DictionaryMessage::new("Shard manager not found."), + ); dict.messages.insert( "command.invalid_format".to_string(), DictionaryMessage::new("Invalid command format") @@ -885,7 +889,7 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) { ); dict.messages.insert( "help.ping".to_string(), - DictionaryMessage::new("Show the actual latency of the bot."), + DictionaryMessage::new("Shows the actual latency of the bot."), ); dict.messages.insert( "add_reminder.helper".to_string(), @@ -934,10 +938,10 @@ pub fn load_english_messages(dict: &mut ErrorDictionary) { ); dict.messages.insert( "slash_command.ping_command_desc".to_string(), - DictionaryMessage::new("Check the discord bot latency."), + DictionaryMessage::new("Check the Discord bot latency."), ); dict.messages.insert( "slash_command.ping_command".to_string(), - DictionaryMessage::new("The Discord bot latency is **{latency}** ms."), + DictionaryMessage::new("## Latency\n\nGateway latency: **{gateway_latency}** ms\nMinimal REST latency (GET /gateway): **{api_latency}** ms\nREST latency (message send): **{message_latency}** ms"), ); } diff --git a/rustmail/src/i18n/language/fr.rs b/rustmail/src/i18n/language/fr.rs index 62c72837..783d9894 100644 --- a/rustmail/src/i18n/language/fr.rs +++ b/rustmail/src/i18n/language/fr.rs @@ -45,6 +45,10 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) { "discord.user_is_a_bot".to_string(), DictionaryMessage::new("L'utilisateur spécifié est un rustmail"), ); + dict.messages.insert( + "discord.shard_manager_not_found".to_string(), + DictionaryMessage::new("Shard manager non trouvé."), + ); dict.messages.insert( "command.invalid_format".to_string(), DictionaryMessage::new("Format de commande invalide") @@ -950,6 +954,6 @@ pub fn load_french_messages(dict: &mut ErrorDictionary) { ); dict.messages.insert( "slash_command.ping_command".to_string(), - DictionaryMessage::new("La latence actuelle du bot est de **{latency}** ms."), + DictionaryMessage::new("## Latence\n\nLatence Gateway : **{gateway_latency}** ms.\nLatence REST minimale (GET /gateway) : **{api_latency}** ms.\nLatence REST (envoi d'un message) : **{message_latency}** ms."), ); } diff --git a/rustmail/src/utils/message/message_builder.rs b/rustmail/src/utils/message/message_builder.rs index 201d87cf..59269655 100644 --- a/rustmail/src/utils/message/message_builder.rs +++ b/rustmail/src/utils/message/message_builder.rs @@ -531,6 +531,7 @@ impl<'a> MessageBuilder<'a> { if self.should_use_embed().await { message = message.embed(self.build_embed().await); + message = message.content(""); } else { let content = self.build_plain_message(); if !content.is_empty() { @@ -550,6 +551,7 @@ impl<'a> MessageBuilder<'a> { if self.should_use_embed().await { message = message.embed(self.build_embed().await); + message = message.content(""); } else { let content = self.build_plain_message(); if !content.is_empty() { @@ -571,6 +573,7 @@ impl<'a> MessageBuilder<'a> { if self.should_use_embed().await { message = message.embed(self.build_embed().await); + message = message.content(""); } else { let content = self.build_plain_message(); if !content.is_empty() {