diff --git a/crates/teloxide/examples/error_handler.rs b/crates/teloxide/examples/error_handler.rs index d2e1e9ac..3d66ce03 100644 --- a/crates/teloxide/examples/error_handler.rs +++ b/crates/teloxide/examples/error_handler.rs @@ -59,7 +59,18 @@ async fn main() { .await; } -async fn error_handler(deps: DependencyMap, error: PublicError) { +async fn error_handler(error: PublicError, deps: Option<DependencyMap>) { + /* + When the error is returned from one of the handlers, deps will contain actual initial_dependencies + + In this example it's not valuable to handle errors with no dependencies, so just log them and ignore + */ + if deps.is_none() { + log::error!("Error occured: {}", error); + return; + } + let deps = deps.unwrap(); + /* The Bot is always present in the dependencies, so it's safe to query it here diff --git a/crates/teloxide/src/dispatching/dispatcher.rs b/crates/teloxide/src/dispatching/dispatcher.rs index 9cf989b8..f2a8651c 100644 --- a/crates/teloxide/src/dispatching/dispatcher.rs +++ b/crates/teloxide/src/dispatching/dispatcher.rs @@ -3,7 +3,7 @@ use crate::{ distribution::default_distribution_function, DefaultKey, DpHandlerDescription, ShutdownToken, }, - error_handlers::{ErrorHandlerExt, LoggingErrorHandler}, + error_handlers::{ErrorHandler, LoggingErrorHandler}, requests::{Request, Requester}, types::{Update, UpdateKind}, update_listeners::{self, UpdateListener}, @@ -40,7 +40,7 @@ pub struct DispatcherBuilder<R, Err, Key> { dependencies: DependencyMap, handler: Arc<UpdateHandler<Err>>, default_handler: DefaultHandler, - error_handler: Arc<dyn ErrorHandlerExt<Err> + Send + Sync>, + error_handler: Arc<dyn ErrorHandler<Err> + Send + Sync>, ctrlc_handler: bool, distribution_f: fn(&Update) -> Option<Key>, worker_queue_size: usize, @@ -75,8 +75,8 @@ where /// /// By default, it is [`LoggingErrorHandler`]. #[must_use] - pub fn error_handler(self, handler: Arc<dyn ErrorHandlerExt<Err> + Send + Sync>) -> Self { - Self { error_handler: handler, ..self } + pub fn error_handler(self, error_handler: Arc<dyn ErrorHandler<Err> + Send + Sync>) -> Self { + Self { error_handler, ..self } } /// Specifies dependencies that can be used inside of handlers. @@ -265,7 +265,7 @@ pub struct Dispatcher<R, Err, Key> { // The default TX part that consume updates concurrently. default_worker: Option<Worker>, - error_handler: Arc<dyn ErrorHandlerExt<Err> + Send + Sync>, + error_handler: Arc<dyn ErrorHandler<Err> + Send + Sync>, state: ShutdownToken, } @@ -356,7 +356,7 @@ where update_listener_error_handler: Arc<Eh>, ) where UListener: UpdateListener + 'a, - Eh: ErrorHandlerExt<UListener::Err> + 'a, + Eh: ErrorHandler<UListener::Err> + 'a, UListener::Err: Debug, { self.try_dispatch_with_listener(update_listener, update_listener_error_handler) @@ -378,7 +378,7 @@ where ) -> Result<(), R::Err> where UListener: UpdateListener + 'a, - Eh: ErrorHandlerExt<UListener::Err> + 'a, + Eh: ErrorHandler<UListener::Err> + 'a, UListener::Err: Debug, { // FIXME: there should be a way to check if dependency is already inserted @@ -443,7 +443,7 @@ where update: Result<Update, LErr>, err_handler: &Arc<LErrHandler>, ) where - LErrHandler: ErrorHandlerExt<LErr>, + LErrHandler: ErrorHandler<LErr>, { match update { Ok(upd) => { @@ -492,7 +492,7 @@ where worker.tx.send(upd).await.expect("TX is dead"); } - Err(err) => err_handler.clone().handle_error_with_deps(DependencyMap::new(), err).await, + Err(err) => err_handler.clone().handle_error(err, None).await, } } @@ -572,7 +572,7 @@ fn spawn_worker<Err>( deps: DependencyMap, handler: Arc<UpdateHandler<Err>>, default_handler: DefaultHandler, - error_handler: Arc<dyn ErrorHandlerExt<Err> + Send + Sync>, + error_handler: Arc<dyn ErrorHandler<Err> + Send + Sync>, current_number_of_active_workers: Arc<AtomicU32>, max_number_of_active_workers: Arc<AtomicU32>, queue_size: usize, @@ -613,7 +613,7 @@ fn spawn_default_worker<Err>( deps: DependencyMap, handler: Arc<UpdateHandler<Err>>, default_handler: DefaultHandler, - error_handler: Arc<dyn ErrorHandlerExt<Err> + Send + Sync>, + error_handler: Arc<dyn ErrorHandler<Err> + Send + Sync>, queue_size: usize, ) -> Worker where @@ -640,7 +640,7 @@ async fn handle_update<Err>( deps: Arc<DependencyMap>, handler: Arc<UpdateHandler<Err>>, default_handler: DefaultHandler, - error_handler: Arc<dyn ErrorHandlerExt<Err> + Send + Sync>, + error_handler: Arc<dyn ErrorHandler<Err> + Send + Sync>, ) where Err: Send + Sync + 'static, { @@ -649,9 +649,7 @@ async fn handle_update<Err>( match handler.dispatch(deps.clone()).await { ControlFlow::Break(Ok(())) => {} - ControlFlow::Break(Err(err)) => { - error_handler.clone().handle_error_with_deps(deps, err).await - } + ControlFlow::Break(Err(err)) => error_handler.clone().handle_error(err, Some(deps)).await, ControlFlow::Continue(deps) => { let update = deps.get(); (default_handler)(update).await; diff --git a/crates/teloxide/src/error_handlers.rs b/crates/teloxide/src/error_handlers.rs index 5ee5e72a..14c2582b 100644 --- a/crates/teloxide/src/error_handlers.rs +++ b/crates/teloxide/src/error_handlers.rs @@ -5,48 +5,31 @@ use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc}; use dptree::di::DependencyMap; use futures::future::BoxFuture; -/// An asynchronous handler of an error. +/// An asynchronous handler of an error with dependencies /// /// See [the module-level documentation for the design /// overview](crate::dispatching). pub trait ErrorHandler<E> { #[must_use] - fn handle_error(self: Arc<Self>, error: E) -> BoxFuture<'static, ()>; + fn handle_error( + self: Arc<Self>, + error: E, + deps: Option<DependencyMap>, + ) -> BoxFuture<'static, ()>; } impl<E, F, Fut> ErrorHandler<E> for F where - F: Fn(E) -> Fut + Send + Sync + 'static, + F: Fn(E, Option<DependencyMap>) -> Fut + Send + Sync + 'static, E: Send + 'static, Fut: Future<Output = ()> + Send, { - fn handle_error(self: Arc<Self>, error: E) -> BoxFuture<'static, ()> { - Box::pin(async move { self(error).await }) - } -} - -/// An asynchronous handler of an error with dependencies -pub trait ErrorHandlerExt<E> { - #[must_use] - fn handle_error_with_deps( + fn handle_error( self: Arc<Self>, - deps: DependencyMap, - error: E, - ) -> BoxFuture<'static, ()>; -} - -impl<E, F, Fut> ErrorHandlerExt<E> for F -where - F: Fn(DependencyMap, E) -> Fut + Send + Sync + 'static, - E: Send + 'static, - Fut: Future<Output = ()> + Send, -{ - fn handle_error_with_deps( - self: Arc<Self>, - deps: DependencyMap, error: E, + deps: Option<DependencyMap>, ) -> BoxFuture<'static, ()> { - Box::pin(async move { self(deps, error).await }) + Box::pin(async move { self(error, deps).await }) } } @@ -110,7 +93,7 @@ where { Box::pin(async move { if let Err(error) = self { - eh.handle_error(error).await; + eh.handle_error(error, None).await; } }) } @@ -122,11 +105,12 @@ where /// ``` /// # #[tokio::main] /// # async fn main_() { +/// use dptree::di::DependencyMap; /// use teloxide::error_handlers::{ErrorHandler, IgnoringErrorHandler}; /// -/// IgnoringErrorHandler::new().handle_error(()).await; -/// IgnoringErrorHandler::new().handle_error(404).await; -/// IgnoringErrorHandler::new().handle_error("error").await; +/// IgnoringErrorHandler::new().handle_error((), None).await; +/// IgnoringErrorHandler::new().handle_error(404, None).await; +/// IgnoringErrorHandler::new().handle_error("error", None).await; /// # } /// ``` #[derive(Clone, Copy)] @@ -140,17 +124,7 @@ impl IgnoringErrorHandler { } impl<E> ErrorHandler<E> for IgnoringErrorHandler { - fn handle_error(self: Arc<Self>, _: E) -> BoxFuture<'static, ()> { - Box::pin(async {}) - } -} - -impl<E> ErrorHandlerExt<E> for IgnoringErrorHandler { - fn handle_error_with_deps( - self: Arc<Self>, - _deps: DependencyMap, - _: E, - ) -> BoxFuture<'static, ()> { + fn handle_error(self: Arc<Self>, _: E, _: Option<DependencyMap>) -> BoxFuture<'static, ()> { Box::pin(async {}) } } @@ -196,17 +170,10 @@ impl IgnoringErrorHandlerSafe { #[allow(unreachable_code)] impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe { - fn handle_error(self: Arc<Self>, _: Infallible) -> BoxFuture<'static, ()> { - Box::pin(async {}) - } -} - -#[allow(unreachable_code)] -impl ErrorHandlerExt<Infallible> for IgnoringErrorHandlerSafe { - fn handle_error_with_deps( + fn handle_error( self: Arc<Self>, - _deps: DependencyMap, _: Infallible, + _: Option<DependencyMap>, ) -> BoxFuture<'static, ()> { Box::pin(async {}) } @@ -220,9 +187,9 @@ impl ErrorHandlerExt<Infallible> for IgnoringErrorHandlerSafe { /// # async fn main_() { /// use teloxide::error_handlers::{ErrorHandler, LoggingErrorHandler}; /// -/// LoggingErrorHandler::new().handle_error(()).await; -/// LoggingErrorHandler::with_custom_text("Omg1").handle_error(404).await; -/// LoggingErrorHandler::with_custom_text("Omg2").handle_error("Invalid data type!").await; +/// LoggingErrorHandler::new().handle_error((), None).await; +/// LoggingErrorHandler::with_custom_text("Omg1").handle_error(404, None).await; +/// LoggingErrorHandler::with_custom_text("Omg2").handle_error("Invalid data type!", None).await; /// # } /// ``` pub struct LoggingErrorHandler { @@ -253,21 +220,7 @@ impl<E> ErrorHandler<E> for LoggingErrorHandler where E: Debug, { - fn handle_error(self: Arc<Self>, error: E) -> BoxFuture<'static, ()> { - log::error!("{text}: {:?}", error, text = self.text); - Box::pin(async {}) - } -} - -impl<E> ErrorHandlerExt<E> for LoggingErrorHandler -where - E: Debug, -{ - fn handle_error_with_deps( - self: Arc<Self>, - _deps: DependencyMap, - error: E, - ) -> BoxFuture<'static, ()> { + fn handle_error(self: Arc<Self>, error: E, _: Option<DependencyMap>) -> BoxFuture<'static, ()> { log::error!("{text}: {:?}", error, text = self.text); Box::pin(async {}) }