From c1ab3424bd85217414fa5b55b99db4af6e7a4979 Mon Sep 17 00:00:00 2001 From: Stachelbeere1248 Date: Tue, 12 Nov 2024 01:00:22 +0100 Subject: [PATCH] rewrite errors --- .idea/inspectionProfiles/Project_Default.xml | 5 + src/commands/accountv2.rs | 117 ++++++++----------- src/commands/bots.rs | 11 +- src/commands/command_helper.rs | 24 +--- src/commands/helpstart.rs | 3 +- src/commands/lfg.rs | 3 +- src/commands/xd.rs | 3 +- src/error.rs | 46 ++++++++ src/handlers/bot_interaction.rs | 2 +- src/handlers/message.rs | 2 +- src/handlers/thread.rs | 2 +- src/main.rs | 20 +++- 12 files changed, 135 insertions(+), 103 deletions(-) create mode 100644 src/error.rs diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index c5e1cad..89a18de 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -2,5 +2,10 @@ \ No newline at end of file diff --git a/src/commands/accountv2.rs b/src/commands/accountv2.rs index db6ab86..8596cae 100644 --- a/src/commands/accountv2.rs +++ b/src/commands/accountv2.rs @@ -15,7 +15,8 @@ use serenity::{ }; use sqlx::{Pool, query_as, Sqlite}; -use crate::{Context, Error}; +use crate::Context; +use crate::error::Error; #[derive(Deserialize)] struct Links { @@ -53,7 +54,12 @@ impl Uuid { async fn fetch(ign: &str) -> Result { let url: String = format!("https://api.mojang.com/users/profiles/minecraft/{ign}"); let response: Response = reqwest::get(url).await?; - match response.error_for_status() { + let response_text = response.error_for_status()?.text().await.unwrap(); + let uuid = (serde_json::from_str(response_text.as_str()) + as Result) + .map(|mojang_player: MojangPlayer| Uuid { uuid: mojang_player.id })?; + Ok(uuid) + /*match response.error_for_status() { Ok(res) => { let response_text = res.text().await.unwrap(); let uuid = (serde_json::from_str(response_text.as_str()) @@ -64,7 +70,7 @@ impl Uuid { Err(why) => Err(Error::from(format!( "Mojang returned an error. Please make sure to enter a valid Minecraft username.\n\n\ Details: {}", why).as_str())), - } + }*/ } } #[derive(PartialEq)] @@ -75,19 +81,11 @@ impl DiscordId { async fn matches_fetch(user: &User, uuid: &str, client: &Client) -> Result { let url: String = format!("https://api.hypixel.net/v2/player?uuid={}", uuid); let response: Response = client.get(url).send().await?; - match response.error_for_status() { - Ok(res) => { - let response_text = res.text().await.unwrap(); - let matches = (serde_json::from_str(response_text.as_str()) - as Result) - .map(|hypixel_response: HypixelResponse| user.name == hypixel_response.player.social_media.links.discord)?; - Ok(matches) - } - Err(why) => { - println!("Hypixel issue: {}", why); - Err(Error::from("Hypixel returned an error.")) - } - } + let response_text = response.error_for_status()?.text().await.unwrap(); + let matches = (serde_json::from_str(response_text.as_str()) + as Result) + .map(|hypixel_response: HypixelResponse| user.name == hypixel_response.player.social_media.links.discord)?; + Ok(matches) } } impl<'a, R: sqlx::Row> sqlx::FromRow<'a, R> for DiscordId @@ -116,17 +114,17 @@ impl Link { minecraft_accounts: vec![], } } - async fn minecraft(mut self, pool: &Pool) -> Self { + async fn minecraft(mut self, pool: &Pool) -> Result { let link_id: i16 = self.link_id.cast_signed(); self.minecraft_accounts = query_as(format!("SELECT minecraft_uuid AS uuid FROM minecraft_links WHERE link_id = {link_id};").as_str()) - .fetch_all(pool).await.expect("Error getting Minecraft UUIDs."); - self + .fetch_all(pool).await?; + Ok(self) } - async fn discord(mut self, pool: &Pool) -> Self { + async fn discord(mut self, pool: &Pool) -> Result { let link_id: i16 = self.link_id.cast_signed(); self.discord_ids = query_as(format!("SELECT discord_id FROM discord_links WHERE link_id = {link_id};").as_str()) - .fetch_all(pool).await.expect("Error getting Discord IDs."); - self + .fetch_all(pool).await?; + Ok(self) } } #[poise::command(slash_command, subcommands("add", "list"))] @@ -148,26 +146,23 @@ pub(crate) async fn add<'a>( ctx.defer_ephemeral().await?; let user = user.unwrap_or(ctx.author().clone()); let uuid = Uuid::fetch(ign.as_str()).await?; - let valid = DiscordId::matches_fetch(&user, uuid.get(), &ctx.data().hypixel_api_client).await - .expect("This Minecraft account does not have a Discord account linked."); - match valid { + match DiscordId::matches_fetch(&user, uuid.get(), &ctx.data().hypixel_api_client).await? { true => { - let r = CreateReply::default().ephemeral(false); let pool: Pool = ctx.data().sqlite_pool.clone(); let (status, link_id) = match link_id_from_minecraft(&pool, uuid.get()).await { None => { match link_id_from_discord(&pool, user.id.get()).await { None => { - let id = new_link_id(&pool).await; + let id = new_link_id(&pool).await?; sqlx::query(format!("INSERT INTO discord_links VALUES ({}, {});", id.cast_signed(), user.id.get()).as_str()) - .execute(&pool).await.expect("Database Error: inserting new minecraft value"); + .execute(&pool).await?; sqlx::query(format!("INSERT INTO minecraft_links VALUES ({}, \"{}\");", id.cast_signed(), uuid.get()).as_str()) - .execute(&pool).await.expect("Database Error: inserting new minecraft value"); + .execute(&pool).await?; ("Linked your Discord and Minecraft account.", id) } Some(dc_id) => { sqlx::query(format!("INSERT INTO minecraft_links VALUES ({}, \"{}\");", dc_id.cast_signed(), uuid.get()).as_str()) - .execute(&pool).await.expect("Database Error: inserting new minecraft value"); + .execute(&pool).await?; ("Your Discord account has previously had an account linked. Added the new link.", dc_id) } } @@ -176,22 +171,21 @@ pub(crate) async fn add<'a>( match link_id_from_discord(&pool, user.id.get()).await { None => { sqlx::query(format!("INSERT INTO discord_links VALUES ({}, {});", mc_id.cast_signed(), user.id.get()).as_str()) - .execute(&pool).await.expect("Database Error: inserting new minecraft value"); + .execute(&pool).await?; ("Your Minecraft account has previously had an account linked. Added the new link.", mc_id) } Some(dc_id) => { sqlx::query(format!("UPDATE minecraft_links SET link_id = {} WHERE link_id = {};", mc_id.cast_signed(), dc_id.cast_signed()).as_str()) - .execute(&pool).await.expect("Database Error: Merging Minecraft Accounts."); + .execute(&pool).await?; sqlx::query(format!("UPDATE discord_links SET link_id = {} WHERE link_id = {};", mc_id.cast_signed(), dc_id.cast_signed()).as_str()) - .execute(&pool).await.expect("Database Error: Merging Discord Accounts."); + .execute(&pool).await?; ("Both your Discord and Minecraft account had linked accounts. Merged all account links.", mc_id) } } } }; - ctx.send(r.content(status)).await?; - let link = Link::new(link_id).minecraft(&pool).await.discord(&pool).await; - let s = list_string(link, user.id.get()).await; + let link = Link::new(link_id).minecraft(&pool).await?.discord(&pool).await?; + let s = list_string(link, user.id.get()); ChannelId::new(1257776992497959075).send_message( ctx, CreateMessage::new() @@ -202,15 +196,14 @@ pub(crate) async fn add<'a>( CreateButton::new("deny_verification").emoji(ReactionType::from('❌')), ])]), ).await?; - } + ctx.send(CreateReply::default().ephemeral(false).content(status)).await?; + Ok(()) + }, false => { - let r = CreateReply::default().ephemeral(true) - .content(format!("The Discord account linked on Hypixel does not seem to match the specified account.\n\ - Expected account link: `{}`", user.name)); - ctx.send(r).await?; + Err(Error::Other(format!("The Discord account linked on Hypixel does not match the specified discord account.\n\ + Please set your linked Discord account on Hypixel to `{}`.", user.name))) } } - Ok(()) } #[poise::command(slash_command)] @@ -223,18 +216,18 @@ pub(crate) async fn list( let r = CreateReply::default().ephemeral(false); let pool: Pool = ctx.data().sqlite_pool.clone(); let link_id = link_id_from_discord(&pool, user.id.get()).await.expect("This user has no linked accounts"); - let link = Link::new(link_id).minecraft(&pool).await.discord(&pool).await; - let s = list_string(link, user.id.get()).await; + let link = Link::new(link_id).minecraft(&pool).await?.discord(&pool).await?; + let s = list_string(link, user.id.get()); ctx.send(r.content(s).allowed_mentions(CreateAllowedMentions::new().empty_roles().empty_users())).await?; Ok(()) } #[poise::command(slash_command)] pub(crate) async fn remove(_ctx: Context<'_>) -> Result<(), Error> { - unreachable!() + unimplemented!() } -async fn list_string(link: Link, user_id: u64) -> String { +fn list_string(link: Link, user_id: u64) -> String { let mut discord_list = String::from("### Discord:"); for dc in link.discord_ids { discord_list.push_str(format!("\n- <@{}>", dc.id).as_str()); @@ -247,26 +240,16 @@ async fn list_string(link: Link, user_id: u64) -> String { } async fn link_id_from_minecraft(pool: &Pool, minecraft_uuid: &str) -> Option { - return query_as( - format!( - "SELECT link_id FROM minecraft_links WHERE minecraft_uuid = \"{minecraft_uuid}\" LIMIT 1;" - ) - .as_str(), - ) + query_as(format!("SELECT link_id FROM minecraft_links WHERE minecraft_uuid = \"{minecraft_uuid}\" LIMIT 1;").as_str()) .fetch_optional(pool) - .await - .expect("Database error: fetching link id by uuid") - .map(|link_id: LinkId| link_id.link_id.cast_unsigned()); + .await.expect("Database error: fetching link id by uuid") + .map(|link_id: LinkId| link_id.link_id.cast_unsigned()) } async fn link_id_from_discord(pool: &Pool, snowflake: u64) -> Option { - let discord_id: i64 = snowflake.cast_signed(); - return query_as( - format!("SELECT link_id FROM discord_links WHERE discord_id = {discord_id} LIMIT 1;").as_str(), - ) + query_as(format!("SELECT link_id FROM discord_links WHERE discord_id = {} LIMIT 1;", snowflake.cast_signed()).as_str()) .fetch_optional(pool) - .await - .expect("Database error: fetching link id by discord") - .map(|link_id: LinkId| link_id.link_id.cast_unsigned()); + .await.expect("Database error: fetching link id by discord") + .map(|link_id: LinkId| link_id.link_id.cast_unsigned()) } #[derive(sqlx::FromRow)] @@ -274,11 +257,9 @@ struct LinkId { link_id: i16, } -async fn new_link_id(pool: &Pool) -> u16 { - let result: Result = query_as("SELECT MAX(link_id) AS link_id FROM minecraft_links;") +async fn new_link_id(pool: &Pool) -> Result { + let result: LinkId = query_as("SELECT MAX(link_id) AS link_id FROM minecraft_links;") .fetch_one(pool) - .await; - result - .expect("Database error: fetching new id") - .link_id.cast_unsigned() + 1 + .await?; + Ok(result.link_id.cast_unsigned() + 1) } \ No newline at end of file diff --git a/src/commands/bots.rs b/src/commands/bots.rs index 6b34203..d6ee489 100644 --- a/src/commands/bots.rs +++ b/src/commands/bots.rs @@ -1,7 +1,7 @@ use std::string::String; - -use crate::{Context, Error}; -use crate::commands::command_helper; +use poise::CreateReply; +use crate::Context; +use crate::error::Error; #[poise::command(slash_command, guild_only, owners_only)] pub(crate) async fn bots( @@ -12,6 +12,7 @@ pub(crate) async fn bots( ) -> Result<(), Error> { ctx.defer_ephemeral().await?; *ctx.data().bots.write().await = bots; - let reply = format!("{} bots are now registered as available", bots).to_string(); - command_helper::send_simple(ctx, reply).await + let content = format!("{} bots are now registered as available", bots).to_string(); + ctx.send(CreateReply::default().content(content).ephemeral(true)).await?; + Ok(()) } diff --git a/src/commands/command_helper.rs b/src/commands/command_helper.rs index 6ec34c8..adf37ce 100644 --- a/src/commands/command_helper.rs +++ b/src/commands/command_helper.rs @@ -1,25 +1,7 @@ use std::time::Duration; -use crate::{Context, Error}; - -pub(crate) async fn send_simple(ctx: Context<'_>, reply: String) -> Result<(), Error> { - if let Err(why) = ctx - .send(poise::CreateReply { - content: Some(reply), - embeds: vec![], - attachments: vec![], - ephemeral: Some(true), - components: None, - allowed_mentions: None, - reply: false, - __non_exhaustive: (), - }) - .await - { - println!("Error sending message: {:?}", why) - } - Ok(()) -} +use crate::Context; +use crate::error::Error; pub(crate) fn cooldown(ctx: &Context, user: u64, guild: u64) -> Result<(), Error> { let mut cooldown_tracker = ctx.command().cooldowns.lock().unwrap(); @@ -35,7 +17,7 @@ pub(crate) fn cooldown(ctx: &Context, user: u64, guild: u64) -> Result<(), Error Ok(()) } else { match cooldown_tracker.remaining_cooldown((*ctx).cooldown_context(), &cooldown_durations) { - Some(remaining) => Err(format!("Please wait {} seconds", remaining.as_secs()).into()), + Some(remaining) => Err(Error::OnCooldown(remaining)), None => Ok(cooldown_tracker.start_cooldown((*ctx).cooldown_context())), } } diff --git a/src/commands/helpstart.rs b/src/commands/helpstart.rs index c390ffa..b0d06b1 100644 --- a/src/commands/helpstart.rs +++ b/src/commands/helpstart.rs @@ -1,8 +1,9 @@ use poise::CreateReply; use serenity::all::CreateAllowedMentions; -use crate::{Context, Error}; +use crate::Context; use crate::commands::command_helper; +use crate::error::Error; #[poise::command(slash_command, guild_only)] pub(crate) async fn helpstart( diff --git a/src/commands/lfg.rs b/src/commands/lfg.rs index 7daf9e6..11ab79e 100644 --- a/src/commands/lfg.rs +++ b/src/commands/lfg.rs @@ -1,13 +1,14 @@ use poise::{ChoiceParameter, CreateReply}; use serenity::all::{CreateAllowedMentions, RoleId}; -use crate::{Context, Error}; +use crate::Context; //from main.rs use crate::commands::command_helper::cooldown; // use crate::commands::lfg::Difficulty::Normal; use crate::commands::lfg::Map::*; use crate::commands::lfg::Mode::*; +use crate::error::Error; #[derive(Debug, poise::ChoiceParameter, PartialEq)] pub enum Map { diff --git a/src/commands/xd.rs b/src/commands/xd.rs index e7d191a..19c03a0 100644 --- a/src/commands/xd.rs +++ b/src/commands/xd.rs @@ -1,4 +1,5 @@ -use crate::{Context, Error}; +use crate::Context; +use crate::error::Error; const XD: &str = "⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⡿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣿⡿⠿⠿⠿⠿⠿⠿⠿⢿⡿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣧⣄⡀⠀⠀⠀⢀⣠⣼⣿⣿⣿⣿⣧⣄⡀⠀⠀⠀⣀⣤⣼⣷⣦⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠻⣿⣿⣿⣿⣿⣿⠟⠀⠀⢀⣼⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣶⣦⣄⡀⠀⠀⠙⢿⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠙⣿⣿⣿⣿⠋⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠈⢿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠈⢿⡿⠁⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⢸⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡗⠀⠀⠀⠐⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠀⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⣠⡀⠀⠀⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⣰⣿⣷⡄⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⣾⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⢀⣼⣿⣿⣿⣿⣆⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⢀⣼⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⠋⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠙⣿⣿⣿⣿⣿⣿⡇⠀⠀⢸⣿⣿⣿⣿⣿⣿⠿⠛⠁⠀⠀⣠⣾⣿⣿⣿⣿⣿\n⣿⣿⣿⠿⠛⠁⠀⠀⠀⠙⠻⣿⣿⣿⣿⣿⡿⠟⠋⠀⠀⠀⠈⠛⠻⡿⠟⠛⠁⠀⠀⠈⠉⠉⠉⠉⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣿⣿⣿⣿⣿⣷⣶⣶⣶⣶⣶⣶⣶⣶⣷⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n"; diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..57b8d6f --- /dev/null +++ b/src/error.rs @@ -0,0 +1,46 @@ +#[derive(Debug)] +pub enum Error { + SqlxError(sqlx::Error), + HttpsError(reqwest::Error), + ParsingError(serde_json::Error), + SerenityError(serenity::Error), + OnCooldown(std::time::Duration), + Other(String) +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Error::SqlxError(e) => write!(f, "SQLx Error: {}", e), + Error::HttpsError(e) => write!(f, "HTTPS Error (Hypixel / Mojang API):\n{}", e), + Error::ParsingError(e) => write!(f, "Parsing Error:\n {}", e), + Error::SerenityError(e) => write!(f, "Serenity Error:\n {}", e), + Error::OnCooldown(d) => write!(f, "This command is on cooldown. {}s remaining.", d.as_secs()), + Error::Other(s) => write!(f, "{}", s), + } + } +} + +impl From for Error { + fn from(error: sqlx::Error) -> Self { + Error::SqlxError(error) + } +} + +impl From for Error { + fn from(error: reqwest::Error) -> Self { + Error::HttpsError(error) + } +} + +impl From for Error { + fn from(error: serde_json::Error) -> Self { + Error::ParsingError(error) + } +} + +impl From for Error { + fn from(error: serenity::Error) -> Self { + Error::SerenityError(error) + } +} \ No newline at end of file diff --git a/src/handlers/bot_interaction.rs b/src/handlers/bot_interaction.rs index ffb36d2..227a01b 100644 --- a/src/handlers/bot_interaction.rs +++ b/src/handlers/bot_interaction.rs @@ -1,6 +1,6 @@ use serenity::all::{ComponentInteraction, ComponentInteractionDataKind, Context, CreateMessage, EditMessage, GuildId, Interaction, RoleId}; -use crate::Error; +use crate::error::Error; pub(crate) async fn component(ctx: &Context, interaction: &Interaction) -> Result<(), Error> { let component = interaction.clone().message_component().unwrap(); diff --git a/src/handlers/message.rs b/src/handlers/message.rs index 881e2b2..b302db4 100644 --- a/src/handlers/message.rs +++ b/src/handlers/message.rs @@ -1,6 +1,6 @@ use serenity::all::{Context, Message}; -use crate::Error; +use crate::error::Error; pub(crate) async fn on_create(ctx: &Context, msg: &Message) -> Result<(), Error> { match msg.guild_id.map(|g| g.get()) { diff --git a/src/handlers/thread.rs b/src/handlers/thread.rs index ebb57d8..bb8a053 100644 --- a/src/handlers/thread.rs +++ b/src/handlers/thread.rs @@ -1,7 +1,7 @@ use serenity::all::{Context, GuildChannel}; use serenity::builder::EditThread; -use crate::Error; +use crate::error::Error; pub(crate) async fn on_create(ctx: &Context, thread: &GuildChannel) -> Result<(), Error> { match thread.parent_id.map(|parent| parent.get()) { diff --git a/src/main.rs b/src/main.rs index 78ac607..745e44b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,22 +5,25 @@ use std::convert::Into; use std::sync::Arc; use std::time::Duration; -use poise::serenity_prelude as serenity; +use poise::{CreateReply, FrameworkError, serenity_prelude as serenity}; use serenity::{FullEvent, model::id::UserId}; use serenity::all::{ActivityData, InteractionType, RoleId}; use serenity::prelude::GatewayIntents; use sqlx::Sqlite; use tokio::sync::RwLock; +use error::Error; mod commands; mod handlers; +mod error; struct Data { bots: Arc>, sqlite_pool: sqlx::Pool, hypixel_api_client: reqwest::Client, } // User data, which is stored and accessible in all command invocations -type Error = Box; + + type Context<'a> = poise::Context<'a, Data, Error>; #[tokio::main] async fn main() { @@ -59,7 +62,18 @@ async fn main() { on_error: |error| { Box::pin(async move { match error { - other => poise::builtins::on_error(other).await.unwrap(), + FrameworkError::CommandStructureMismatch { description, ctx, .. } => { + if let Err(e) = ctx.send(CreateReply::default() + .content(format!("# Command arguments did not match. The command probably has been updated recently. Try reloading Discord. Description:\n{}", description))) + .await { + tracing::error!("Fatal error while sending error message: {}", e); + } + } + other => { + if let Err(e) = poise::builtins::on_error(other).await { + tracing::error!("Fatal error while sending error message: {}", e); + } + } } }) },