1
0
Fork 0
mirror of https://github.com/teloxide/teloxide.git synced 2025-04-13 09:24:34 +02:00

Allow optional deps in ErrorHandler::handle_error

This commit is contained in:
Сырцев Вадим Игоревич 2024-07-04 21:18:02 +03:00
parent 1e8636a76a
commit 6e74e5e087
3 changed files with 47 additions and 85 deletions
crates/teloxide

View file

@ -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

View file

@ -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;

View file

@ -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 {})
}