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; .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 When an error is occured in one of your handlers, you can access only initial dependencies, such as:
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 - Update
- Bot
- Me - Me
- and the ones you've provided to the Dispatcher's dependencies - and the ones you've provided to the Dispatcher's dependencies at the beginning
*/ */
let bot: Arc<Bot> = deps.get(); 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 update: Arc<Update> = deps.get();
let chat_id = update.chat().map(|c| c.id); let chat_id = update.chat().map(|c| c.id);
@ -89,7 +78,7 @@ async fn error_handler(error: PublicError, deps: Option<DependencyMap>) {
PublicError::Dummy => { PublicError::Dummy => {
// Some updates don't have a chat id // Some updates don't have a chat id
if let Some(chat_id) = 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; 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"); 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 { match handler.dispatch(deps.clone()).await {
ControlFlow::Break(Ok(())) => {} 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) => { ControlFlow::Continue(deps) => {
let update = deps.get(); let update = deps.get();
(default_handler)(update).await; (default_handler)(update).await;

View file

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