diff --git a/src/callbacks.rs b/src/callbacks.rs index 77d508b..9e1fe0f 100644 --- a/src/callbacks.rs +++ b/src/callbacks.rs @@ -10,7 +10,7 @@ crate::export_handlers!( change_locale ); -use crate::{errors::InvalidCommand, locales::LocaleTypeExt}; +use crate::{errors::InvalidCommand, handle_error, locales::LocaleTypeExt}; use base64::{engine::general_purpose::STANDARD_NO_PAD as B64_ENGINE, Engine as _}; use entity::locale::LocaleType; use std::str::FromStr; @@ -40,10 +40,7 @@ pub enum CallbackCommand { impl CallbackCommand { pub fn from_query(q: CallbackQuery) -> Option { q.message?; - q.data? - .parse() - .inspect_err(|err| log::error!("{err:?}")) - .ok() + q.data?.parse().map_err(handle_error).ok() } } diff --git a/src/callbacks/alter.rs b/src/callbacks/alter.rs index 97fd0ee..9bd78d2 100644 --- a/src/callbacks/alter.rs +++ b/src/callbacks/alter.rs @@ -60,7 +60,7 @@ async fn get_master_pass( Ok(true) => locale.success.as_str(), Ok(false) => &locale.account_not_found, Err(err) => { - log::error!("{err:?}"); + handle_error(err); &locale.something_went_wrong } }; diff --git a/src/callbacks/change_locale.rs b/src/callbacks/change_locale.rs index 8fc6fd4..1e023de 100644 --- a/src/callbacks/change_locale.rs +++ b/src/callbacks/change_locale.rs @@ -15,7 +15,7 @@ pub async fn change_locale( let is_successful = new_locale .update(user_id, &db) .await - .inspect_err(|err| log::error!("{err:?}")) + .map_err(handle_error) .unwrap_or(false); if !is_successful { diff --git a/src/commands/delete_all.rs b/src/commands/delete_all.rs index 044a62b..2b3b44b 100644 --- a/src/commands/delete_all.rs +++ b/src/commands/delete_all.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use log::error; /// Gets the master password, deletes the accounts and the master password from DB. /// Although it doesn't use the master password, we get it to be sure that it's the user who used that command @@ -27,8 +26,10 @@ async fn get_master_pass( &locale.everything_was_deleted } (Err(err), _) | (_, Err(err)) => { - error!("{:?}", crate::Error::from(err)); - txn.rollback().await?; + handle_error(err); + if let Err(err) = txn.rollback().await { + handle_error(err); + } &locale.something_went_wrong } }; diff --git a/src/errors.rs b/src/errors.rs index 689ac26..ec43ea6 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,5 @@ +use std::fmt::{Debug, Display}; + #[derive(thiserror::Error, Debug)] #[error("No user info found")] pub struct NoUserInfo; @@ -17,3 +19,24 @@ pub enum InvalidCommand { #[error("Unknown locale passed into callback")] UnknownLocale, } + +#[inline] +pub fn handle_error(error: T) +where + T: Debug + Display, +{ + log::error!("{error}\n{error:?}"); +} + +pub struct ErrorHandler; + +impl teloxide::error_handlers::ErrorHandler for ErrorHandler { + #[inline] + fn handle_error( + self: std::sync::Arc, + error: crate::Error, + ) -> futures::prelude::future::BoxFuture<'static, ()> { + handle_error(error); + Box::pin(async {}) + } +} diff --git a/src/locales.rs b/src/locales.rs index 6d03eae..e3b1653 100644 --- a/src/locales.rs +++ b/src/locales.rs @@ -1,6 +1,5 @@ use crate::prelude::*; use entity::locale::LocaleType; -use log::error; use std::future::Future; use std::sync::OnceLock; @@ -152,7 +151,7 @@ impl LocaleTypeExt for LocaleType { match Self::get_from_db(from.id.0, db).await { Ok(Some(locale)) => return locale, Ok(None) => (), - Err(err) => error!("{err:?}"), + Err(err) => handle_error(err), } from.language_code diff --git a/src/main.rs b/src/main.rs index b03ddb7..f4ce110 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ mod state; use anyhow::{Error, Result}; use dotenvy::dotenv; use prelude::*; -use std::env; +use std::{env, sync::Arc}; use teloxide::{adaptors::throttle::Limits, dispatching::dialogue::InMemStorage, filter_command}; use crate::callbacks::CallbackCommand; @@ -80,6 +80,7 @@ fn get_dispatcher( Dispatcher::builder(bot, handler) .dependencies(deps![db, InMemStorage::::new()]) + .error_handler(Arc::from(errors::ErrorHandler)) .enable_ctrlc_handler() .build() } diff --git a/src/prelude.rs b/src/prelude.rs index 3fc1108..c1fd2be 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,6 +1,6 @@ pub use crate::{ commands::Command, - errors::*, + errors::{handle_error, NoUserInfo}, first_handler, handler, locales::{Locale, LocaleRef}, markups::*, diff --git a/src/state/generic.rs b/src/state/generic.rs index 7fc8741..ca57211 100644 --- a/src/state/generic.rs +++ b/src/state/generic.rs @@ -1,4 +1,4 @@ -use crate::prelude::*; +use crate::{errors::HandlerUsed, prelude::*}; use futures::future::BoxFuture; /// A generic state handler. It checks for "/cancel" messages and runs the provided validation function diff --git a/src/state/get_master_pass.rs b/src/state/get_master_pass.rs index 851ecdb..a90bdb9 100644 --- a/src/state/get_master_pass.rs +++ b/src/state/get_master_pass.rs @@ -1,6 +1,5 @@ use crate::prelude::*; use cryptography::hashing::HashedBytes; -use log::error; use tokio::task::spawn_blocking; /// Returns true if the provided master password is valid @@ -13,12 +12,9 @@ async fn check_master_pass( ) -> crate::Result> { let user_id = msg.from().ok_or(NoUserInfo)?.id.0; let Some(model) = MasterPass::get(user_id, db).await? else { - error!( - "{:?}", - anyhow::anyhow!( - "User was put into the GetMasterPass state with no master password set" - ) - ); + handle_error(anyhow::anyhow!( + "User was put into the GetMasterPass state with no master password set" + )); return Ok(Some(locale.master_password_is_not_set.to_owned())); }; diff --git a/src/state/get_user.rs b/src/state/get_user.rs index dd2cb9c..1884e1d 100644 --- a/src/state/get_user.rs +++ b/src/state/get_user.rs @@ -1,4 +1,4 @@ -use crate::prelude::*; +use crate::{errors::HandlerUsed, prelude::*}; use futures::TryFutureExt; use itertools::Itertools; use std::{borrow::Cow, fmt::Write, path::Path}; diff --git a/src/state/handler.rs b/src/state/handler.rs index 5de983b..77d6f60 100644 --- a/src/state/handler.rs +++ b/src/state/handler.rs @@ -47,7 +47,7 @@ impl MessageIds { let result = join!(self.delete(bot), send_request.send()); if let Err(err) = result.0 { - log::error!("{err:?}"); + handle_error(err); } *self = Self::from(&result.1?); Ok(())