Fix error handlers

This commit is contained in:
Temirkhan Myrzamadi 2020-02-18 06:19:50 +06:00
parent d23b226e86
commit f20932a730
6 changed files with 159 additions and 162 deletions

View file

@ -47,25 +47,25 @@ where
///
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
#[must_use]
pub fn new(handler: H) -> Arc<Self> {
Arc::new(Self {
pub fn new(handler: H) -> Self {
Self {
storage: InMemStorage::new(),
handler: Arc::new(handler),
senders: Arc::new(Map::new()),
})
}
}
/// Creates a dispatcher with the specified `handler` and `storage`.
#[must_use]
pub fn with_storage<Stg>(handler: H, storage: Arc<Stg>) -> Arc<Self>
pub fn with_storage<Stg>(handler: H, storage: Arc<Stg>) -> Self
where
Stg: Storage<D> + Send + Sync + 'static,
{
Arc::new(Self {
Self {
storage,
handler: Arc::new(handler),
senders: Arc::new(Map::new()),
})
}
}
#[must_use]

View file

@ -1,6 +1,5 @@
use std::pin::Pin;
use crate::prelude::{DialogueDispatcherHandlerCtx, DialogueStage};
use futures::future::BoxFuture;
use std::{future::Future, sync::Arc};
/// An asynchronous handler of an update used in [`DialogueDispatcher`].
@ -14,7 +13,7 @@ pub trait DialogueDispatcherHandler<Upd, D> {
fn handle(
self: Arc<Self>,
ctx: DialogueDispatcherHandlerCtx<Upd, D>,
) -> Pin<Box<dyn Future<Output = DialogueStage<D>> + Send + 'static>>
) -> BoxFuture<'static, DialogueStage<D>>
where
DialogueDispatcherHandlerCtx<Upd, D>: Send + 'static;
}
@ -27,7 +26,7 @@ where
fn handle(
self: Arc<Self>,
ctx: DialogueDispatcherHandlerCtx<Upd, D>,
) -> Pin<Box<dyn Future<Output = Fut::Output> + Send + 'static>>
) -> BoxFuture<'static, Fut::Output>
where
DialogueDispatcherHandlerCtx<Upd, D>: Send + 'static,
{

View file

@ -211,7 +211,7 @@ impl Dispatcher {
pub async fn dispatch(&self) {
self.dispatch_with_listener(
update_listeners::polling_default(Arc::clone(&self.bot)),
&LoggingErrorHandler::new("An error from the update listener"),
LoggingErrorHandler::new("An error from the update listener"),
)
.await;
}
@ -221,7 +221,7 @@ impl Dispatcher {
pub async fn dispatch_with_listener<'a, UListener, ListenerE, Eh>(
&'a self,
update_listener: UListener,
update_listener_error_handler: &'a Eh,
update_listener_error_handler: Arc<Eh>,
) where
UListener: UpdateListener<ListenerE> + 'a,
Eh: ErrorHandler<ListenerE> + 'a,
@ -230,105 +230,112 @@ impl Dispatcher {
let update_listener = Box::pin(update_listener);
update_listener
.for_each(move |update| async move {
log::trace!("Dispatcher received an update: {:?}", update);
.for_each(move |update| {
let update_listener_error_handler =
Arc::clone(&update_listener_error_handler);
let update = match update {
Ok(update) => update,
Err(error) => {
update_listener_error_handler.handle_error(error).await;
return;
}
};
async move {
log::trace!("Dispatcher received an update: {:?}", update);
match update.kind {
UpdateKind::Message(message) => {
send!(
&self.bot,
&self.messages_queue,
message,
UpdateKind::Message
);
}
UpdateKind::EditedMessage(message) => {
send!(
&self.bot,
&self.edited_messages_queue,
message,
UpdateKind::EditedMessage
);
}
UpdateKind::ChannelPost(post) => {
send!(
&self.bot,
&self.channel_posts_queue,
post,
UpdateKind::ChannelPost
);
}
UpdateKind::EditedChannelPost(post) => {
send!(
&self.bot,
&self.edited_channel_posts_queue,
post,
UpdateKind::EditedChannelPost
);
}
UpdateKind::InlineQuery(query) => {
send!(
&self.bot,
&self.inline_queries_queue,
query,
UpdateKind::InlineQuery
);
}
UpdateKind::ChosenInlineResult(result) => {
send!(
&self.bot,
&self.chosen_inline_results_queue,
result,
UpdateKind::ChosenInlineResult
);
}
UpdateKind::CallbackQuery(query) => {
send!(
&self.bot,
&self.callback_queries_queue,
query,
UpdateKind::CallbackQuer
);
}
UpdateKind::ShippingQuery(query) => {
send!(
&self.bot,
&self.shipping_queries_queue,
query,
UpdateKind::ShippingQuery
);
}
UpdateKind::PreCheckoutQuery(query) => {
send!(
&self.bot,
&self.pre_checkout_queries_queue,
query,
UpdateKind::PreCheckoutQuery
);
}
UpdateKind::Poll(poll) => {
send!(
&self.bot,
&self.polls_queue,
poll,
UpdateKind::Poll
);
}
UpdateKind::PollAnswer(answer) => {
send!(
&self.bot,
&self.poll_answers_queue,
answer,
UpdateKind::PollAnswer
);
let update = match update {
Ok(update) => update,
Err(error) => {
Arc::clone(&update_listener_error_handler)
.handle_error(error)
.await;
return;
}
};
match update.kind {
UpdateKind::Message(message) => {
send!(
&self.bot,
&self.messages_queue,
message,
UpdateKind::Message
);
}
UpdateKind::EditedMessage(message) => {
send!(
&self.bot,
&self.edited_messages_queue,
message,
UpdateKind::EditedMessage
);
}
UpdateKind::ChannelPost(post) => {
send!(
&self.bot,
&self.channel_posts_queue,
post,
UpdateKind::ChannelPost
);
}
UpdateKind::EditedChannelPost(post) => {
send!(
&self.bot,
&self.edited_channel_posts_queue,
post,
UpdateKind::EditedChannelPost
);
}
UpdateKind::InlineQuery(query) => {
send!(
&self.bot,
&self.inline_queries_queue,
query,
UpdateKind::InlineQuery
);
}
UpdateKind::ChosenInlineResult(result) => {
send!(
&self.bot,
&self.chosen_inline_results_queue,
result,
UpdateKind::ChosenInlineResult
);
}
UpdateKind::CallbackQuery(query) => {
send!(
&self.bot,
&self.callback_queries_queue,
query,
UpdateKind::CallbackQuer
);
}
UpdateKind::ShippingQuery(query) => {
send!(
&self.bot,
&self.shipping_queries_queue,
query,
UpdateKind::ShippingQuery
);
}
UpdateKind::PreCheckoutQuery(query) => {
send!(
&self.bot,
&self.pre_checkout_queries_queue,
query,
UpdateKind::PreCheckoutQuery
);
}
UpdateKind::Poll(poll) => {
send!(
&self.bot,
&self.polls_queue,
poll,
UpdateKind::Poll
);
}
UpdateKind::PollAnswer(answer) => {
send!(
&self.bot,
&self.poll_answers_queue,
answer,
UpdateKind::PollAnswer
);
}
}
}
})

View file

@ -1,6 +1,7 @@
use std::{future::Future, pin::Pin};
use std::future::Future;
use crate::dispatching::{DispatcherHandlerCtx, DispatcherHandlerRx};
use futures::future::BoxFuture;
/// An asynchronous handler of a stream of updates used in [`Dispatcher`].
///
@ -13,7 +14,7 @@ pub trait DispatcherHandler<Upd> {
fn handle(
self,
updates: DispatcherHandlerRx<Upd>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>
) -> BoxFuture<'static, ()>
where
DispatcherHandlerCtx<Upd>: Send + 'static;
}
@ -23,10 +24,7 @@ where
F: FnOnce(DispatcherHandlerRx<Upd>) -> Fut + Send + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
fn handle(
self,
updates: DispatcherHandlerRx<Upd>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>>
fn handle(self, updates: DispatcherHandlerRx<Upd>) -> BoxFuture<'static, ()>
where
DispatcherHandlerCtx<Upd>: Send + 'static,
{

View file

@ -1,4 +1,5 @@
use std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};
use futures::future::BoxFuture;
use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc};
/// An asynchronous handler of an error.
///
@ -6,26 +7,16 @@ use std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};
/// overview](crate::dispatching).
pub trait ErrorHandler<E> {
#[must_use]
fn handle_error<'a>(
&'a self,
error: E,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
E: 'a;
fn handle_error(self: Arc<Self>, error: E) -> BoxFuture<'static, ()>;
}
impl<E, F, Fut> ErrorHandler<E> for F
where
F: Fn(E) -> Fut,
Fut: Future<Output = ()>,
F: Fn(E) -> Fut + Send + Sync + 'static,
E: Send + 'static,
Fut: Future<Output = ()> + Send,
{
fn handle_error<'a>(
&'a self,
error: E,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
E: 'a,
{
fn handle_error(self: Arc<Self>, error: E) -> BoxFuture<'static, ()> {
Box::pin(async move { self(error).await })
}
}
@ -38,21 +29,22 @@ where
/// # async fn main_() {
/// use teloxide::dispatching::{ErrorHandler, IgnoringErrorHandler};
///
/// IgnoringErrorHandler.handle_error(()).await;
/// IgnoringErrorHandler.handle_error(404).await;
/// IgnoringErrorHandler.handle_error("error").await;
/// IgnoringErrorHandler::new().handle_error(()).await;
/// IgnoringErrorHandler::new().handle_error(404).await;
/// IgnoringErrorHandler::new().handle_error("error").await;
/// # }
/// ```
pub struct IgnoringErrorHandler;
impl IgnoringErrorHandler {
#[must_use]
pub fn new() -> Arc<Self> {
Arc::new(Self)
}
}
impl<E> ErrorHandler<E> for IgnoringErrorHandler {
fn handle_error<'a>(
&'a self,
_: E,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
E: 'a,
{
fn handle_error(self: Arc<Self>, _: E) -> BoxFuture<'static, ()> {
Box::pin(async {})
}
}
@ -71,10 +63,10 @@ impl<E> ErrorHandler<E> for IgnoringErrorHandler {
/// let result: Result<String, Infallible> = "str".try_into();
/// match result {
/// Ok(string) => println!("{}", string),
/// Err(inf) => IgnoringErrorHandlerSafe.handle_error(inf).await,
/// Err(inf) => IgnoringErrorHandlerSafe::new().handle_error(inf).await,
/// }
///
/// IgnoringErrorHandlerSafe.handle_error(return).await; // return type of `return` is `!` (aka never)
/// IgnoringErrorHandlerSafe::new().handle_error(return).await; // return type of `return` is `!` (aka never)
/// # }
/// ```
///
@ -88,15 +80,16 @@ impl<E> ErrorHandler<E> for IgnoringErrorHandler {
/// [`Infallible`]: std::convert::Infallible
pub struct IgnoringErrorHandlerSafe;
impl IgnoringErrorHandlerSafe {
#[must_use]
pub fn new() -> Arc<Self> {
Arc::new(Self)
}
}
#[allow(unreachable_code)]
impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
fn handle_error<'a>(
&'a self,
_: Infallible,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
Infallible: 'a,
{
fn handle_error(self: Arc<Self>, _: Infallible) -> BoxFuture<'static, ()> {
Box::pin(async {})
}
}
@ -109,14 +102,13 @@ impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
/// # async fn main_() {
/// use teloxide::dispatching::{ErrorHandler, LoggingErrorHandler};
///
/// LoggingErrorHandler::default().handle_error(()).await;
/// LoggingErrorHandler::empty().handle_error(()).await;
/// LoggingErrorHandler::new("error").handle_error(404).await;
/// LoggingErrorHandler::new("error")
/// .handle_error("Invalid data type!")
/// .await;
/// # }
/// ```
#[derive(Default)]
pub struct LoggingErrorHandler {
text: String,
}
@ -126,11 +118,17 @@ impl LoggingErrorHandler {
///
/// The logs will be printed in this format: `{text}: {:?}`.
#[must_use]
pub fn new<T>(text: T) -> Self
pub fn new<T>(text: T) -> Arc<Self>
where
T: Into<String>,
{
Self { text: text.into() }
Arc::new(Self { text: text.into() })
}
/// A shortcut for `LoggingErrorHandler::new("Error".to_owned())`.
#[must_use]
pub fn empty() -> Arc<Self> {
Self::new("Error".to_owned())
}
}
@ -138,13 +136,7 @@ impl<E> ErrorHandler<E> for LoggingErrorHandler
where
E: Debug,
{
fn handle_error<'a>(
&'a self,
error: E,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
E: 'a,
{
fn handle_error(self: Arc<Self>, error: E) -> BoxFuture<'static, ()> {
log::error!("{text}: {:?}", error, text = self.text);
Box::pin(async {})
}

View file

@ -6,7 +6,8 @@ pub use crate::{
exit, next, DialogueDispatcher, DialogueDispatcherHandlerCtx,
DialogueStage, GetChatId,
},
Dispatcher, DispatcherHandlerCtx, DispatcherHandlerRx, LoggingErrorHandler, ErrorHandler
Dispatcher, DispatcherHandlerCtx, DispatcherHandlerRx, ErrorHandler,
LoggingErrorHandler,
},
requests::{Request, ResponseResult},
types::{Message, Update},