It could be the brother of Option<Vec<T>>..

This commit is contained in:
Сырцев Вадим Игоревич 2024-07-04 21:50:20 +03:00
parent a8d490d0ae
commit 93aa829543
3 changed files with 31 additions and 49 deletions

View file

@ -59,29 +59,18 @@ async fn main() {
.await;
}
async fn error_handler(error: PublicError, deps: Option<DependencyMap>) {
async fn error_handler(error: PublicError, deps: 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
Note that you can access only initial dependencies, such as:
- Bot
- Update
- Me
- and the ones you've provided to the Dispatcher's dependencies
When an error is occured in one of your handlers, you can access only initial dependencies, such as:
- Update
- Bot
- Me
- and the ones you've provided to the Dispatcher's dependencies at the beginning
*/
let bot: Arc<Bot> = deps.get();
// It worth to note that in case of UpdateListener::Error there will be no
// Update value
let update: Arc<Update> = deps.get();
let chat_id = update.chat().map(|c| c.id);
@ -89,7 +78,7 @@ async fn error_handler(error: PublicError, deps: Option<DependencyMap>) {
PublicError::Dummy => {
// Some updates don't have a chat id
if let Some(chat_id) = chat_id {
// TODO, maybe retry queue?
// TODO, maybe retry queue? backon?
let _ = bot.send_message(chat_id, error.to_string()).await;
}
}

View file

@ -492,7 +492,7 @@ where
worker.tx.send(upd).await.expect("TX is dead");
}
Err(err) => err_handler.clone().handle_error(err, None).await,
Err(err) => err_handler.clone().handle_error(err, self.dependencies.clone()).await,
}
}
@ -649,7 +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(err, Some(deps)).await,
ControlFlow::Break(Err(err)) => error_handler.clone().handle_error(err, deps).await,
ControlFlow::Continue(deps) => {
let update = deps.get();
(default_handler)(update).await;

View file

@ -11,24 +11,16 @@ use futures::future::BoxFuture;
/// overview](crate::dispatching).
pub trait ErrorHandler<E> {
#[must_use]
fn handle_error(
self: Arc<Self>,
error: E,
deps: Option<DependencyMap>,
) -> BoxFuture<'static, ()>;
fn handle_error(self: Arc<Self>, error: E, deps: DependencyMap) -> BoxFuture<'static, ()>;
}
impl<E, F, Fut> ErrorHandler<E> for F
where
F: Fn(E, Option<DependencyMap>) -> Fut + Send + Sync + 'static,
F: Fn(E, DependencyMap) -> Fut + Send + Sync + 'static,
E: Send + 'static,
Fut: Future<Output = ()> + Send,
{
fn handle_error(
self: Arc<Self>,
error: E,
deps: Option<DependencyMap>,
) -> BoxFuture<'static, ()> {
fn handle_error(self: Arc<Self>, error: E, deps: DependencyMap) -> BoxFuture<'static, ()> {
Box::pin(async move { self(error, deps).await })
}
}
@ -93,7 +85,7 @@ where
{
Box::pin(async move {
if let Err(error) = self {
eh.handle_error(error, None).await;
eh.handle_error(error, DependencyMap::new()).await;
}
})
}
@ -108,9 +100,9 @@ where
/// use dptree::di::DependencyMap;
/// use teloxide::error_handlers::{ErrorHandler, IgnoringErrorHandler};
///
/// IgnoringErrorHandler::new().handle_error((), None).await;
/// IgnoringErrorHandler::new().handle_error(404, None).await;
/// IgnoringErrorHandler::new().handle_error("error", None).await;
/// IgnoringErrorHandler::new().handle_error((), DependencyMap::new()).await;
/// IgnoringErrorHandler::new().handle_error(404, DependencyMap::new()).await;
/// IgnoringErrorHandler::new().handle_error("error", DependencyMap::new()).await;
/// # }
/// ```
#[derive(Clone, Copy)]
@ -124,7 +116,7 @@ impl IgnoringErrorHandler {
}
impl<E> ErrorHandler<E> for IgnoringErrorHandler {
fn handle_error(self: Arc<Self>, _: E, _: Option<DependencyMap>) -> BoxFuture<'static, ()> {
fn handle_error(self: Arc<Self>, _: E, _: DependencyMap) -> BoxFuture<'static, ()> {
Box::pin(async {})
}
}
@ -138,15 +130,17 @@ impl<E> ErrorHandler<E> for IgnoringErrorHandler {
/// # async fn main_() {
/// use std::convert::{Infallible, TryInto};
///
/// use dptree::di::DependencyMap;
/// use teloxide::error_handlers::{ErrorHandler, IgnoringErrorHandlerSafe};
///
/// let result: Result<String, Infallible> = "str".try_into();
/// match result {
/// Ok(string) => println!("{}", string),
/// Err(inf) => IgnoringErrorHandlerSafe::new().handle_error(inf, None).await,
/// Err(inf) => IgnoringErrorHandlerSafe::new().handle_error(inf, DependencyMap::new()).await,
/// }
///
/// IgnoringErrorHandlerSafe::new().handle_error(return, None).await; // return type of `return` is `!` (aka never)
/// IgnoringErrorHandlerSafe::new().handle_error(return, DependencyMap::new()).await;
/// // return type of `return` is `!` (aka never)
/// # }
/// ```
///
@ -170,11 +164,7 @@ impl IgnoringErrorHandlerSafe {
#[allow(unreachable_code)]
impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
fn handle_error(
self: Arc<Self>,
_: Infallible,
_: Option<DependencyMap>,
) -> BoxFuture<'static, ()> {
fn handle_error(self: Arc<Self>, _: Infallible, _: DependencyMap) -> BoxFuture<'static, ()> {
Box::pin(async {})
}
}
@ -185,11 +175,14 @@ impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use dptree::di::DependencyMap;
/// use teloxide::error_handlers::{ErrorHandler, LoggingErrorHandler};
///
/// 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;
/// LoggingErrorHandler::new().handle_error((), DependencyMap::new()).await;
/// LoggingErrorHandler::with_custom_text("Omg1").handle_error(404, DependencyMap::new()).await;
/// LoggingErrorHandler::with_custom_text("Omg2")
/// .handle_error("Invalid data type!", DependencyMap::new())
/// .await;
/// # }
/// ```
pub struct LoggingErrorHandler {
@ -220,7 +213,7 @@ impl<E> ErrorHandler<E> for LoggingErrorHandler
where
E: Debug,
{
fn handle_error(self: Arc<Self>, error: E, _: Option<DependencyMap>) -> BoxFuture<'static, ()> {
fn handle_error(self: Arc<Self>, error: E, _: DependencyMap) -> BoxFuture<'static, ()> {
log::error!("{text}: {:?}", error, text = self.text);
Box::pin(async {})
}