Rework handlers (failing now)

This commit is contained in:
Temirkhan Myrzamadi 2020-02-08 00:06:41 +06:00
parent ab8dae9213
commit e6bf25b3bf
4 changed files with 203 additions and 184 deletions

View file

@ -2,19 +2,24 @@ use crate::{
dispatching::{ dispatching::{
error_handlers::ErrorHandler, update_listeners, error_handlers::ErrorHandler, update_listeners,
update_listeners::UpdateListener, CtxHandler, DispatcherHandlerCtx, update_listeners::UpdateListener, CtxHandler, DispatcherHandlerCtx,
LoggingErrorHandler, Middleware, DispatcherHandlerResult, LoggingErrorHandler,
}, },
types::{ types::{
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll, CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
PreCheckoutQuery, ShippingQuery, Update, UpdateKind, PollAnswer, PreCheckoutQuery, ShippingQuery, Update, UpdateKind,
}, },
Bot, Bot,
}; };
use futures::{stream, StreamExt}; use futures::{stream, StreamExt};
use std::{fmt::Debug, sync::Arc}; use std::{fmt::Debug, future::Future, sync::Arc};
type H<'a, Upd, HandlerE> = Option< type Handlers<'a, Upd, HandlerE> = Vec<
Box<dyn CtxHandler<DispatcherHandlerCtx<Upd>, Result<(), HandlerE>> + 'a>, Box<
dyn CtxHandler<
DispatcherHandlerCtx<Upd>,
DispatcherHandlerResult<Upd, HandlerE>,
> + 'a,
>,
>; >;
/// One dispatcher to rule them all. /// One dispatcher to rule them all.
@ -24,20 +29,20 @@ type H<'a, Upd, HandlerE> = Option<
pub struct Dispatcher<'a, HandlerE> { pub struct Dispatcher<'a, HandlerE> {
bot: Arc<Bot>, bot: Arc<Bot>,
middlewares: Vec<Box<dyn Middleware<Update> + 'a>>,
handlers_error_handler: Box<dyn ErrorHandler<HandlerE> + 'a>, handlers_error_handler: Box<dyn ErrorHandler<HandlerE> + 'a>,
message_handler: H<'a, Message, HandlerE>, update_handlers: Handlers<'a, Update, HandlerE>,
edited_message_handler: H<'a, Message, HandlerE>, message_handlers: Handlers<'a, Message, HandlerE>,
channel_post_handler: H<'a, Message, HandlerE>, edited_message_handlers: Handlers<'a, Message, HandlerE>,
edited_channel_post_handler: H<'a, Message, HandlerE>, channel_post_handlers: Handlers<'a, Message, HandlerE>,
inline_query_handler: H<'a, InlineQuery, HandlerE>, edited_channel_post_handlers: Handlers<'a, Message, HandlerE>,
chosen_inline_result_handler: H<'a, ChosenInlineResult, HandlerE>, inline_query_handlers: Handlers<'a, InlineQuery, HandlerE>,
callback_query_handler: H<'a, CallbackQuery, HandlerE>, chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, HandlerE>,
shipping_query_handler: H<'a, ShippingQuery, HandlerE>, callback_query_handlers: Handlers<'a, CallbackQuery, HandlerE>,
pre_checkout_query_handler: H<'a, PreCheckoutQuery, HandlerE>, shipping_query_handlers: Handlers<'a, ShippingQuery, HandlerE>,
poll_handler: H<'a, Poll, HandlerE>, pre_checkout_query_handlers: Handlers<'a, PreCheckoutQuery, HandlerE>,
poll_handlers: Handlers<'a, Poll, HandlerE>,
poll_answer_handlers: Handlers<'a, PollAnswer, HandlerE>,
} }
impl<'a, HandlerE> Dispatcher<'a, HandlerE> impl<'a, HandlerE> Dispatcher<'a, HandlerE>
@ -49,37 +54,24 @@ where
pub fn new(bot: Bot) -> Self { pub fn new(bot: Bot) -> Self {
Self { Self {
bot: Arc::new(bot), bot: Arc::new(bot),
middlewares: Vec::new(),
handlers_error_handler: Box::new(LoggingErrorHandler::new( handlers_error_handler: Box::new(LoggingErrorHandler::new(
"An error from a Dispatcher's handler", "An error from a Dispatcher's handler",
)), )),
message_handler: None, update_handlers: Vec::new(),
edited_message_handler: None, message_handlers: Vec::new(),
channel_post_handler: None, edited_message_handlers: Vec::new(),
edited_channel_post_handler: None, channel_post_handlers: Vec::new(),
inline_query_handler: None, edited_channel_post_handlers: Vec::new(),
chosen_inline_result_handler: None, inline_query_handlers: Vec::new(),
callback_query_handler: None, chosen_inline_result_handlers: Vec::new(),
shipping_query_handler: None, callback_query_handlers: Vec::new(),
pre_checkout_query_handler: None, shipping_query_handlers: Vec::new(),
poll_handler: None, pre_checkout_query_handlers: Vec::new(),
poll_handlers: Vec::new(),
poll_answer_handlers: Vec::new(),
} }
} }
/// Appends a middleware.
///
/// If a middleware has returned `None`, an update will not be handled by a
/// next middleware or an appropriate handler (if it's the last middleware).
/// Otherwise, an update in `Some(update)` is passed further.
#[must_use]
pub fn middleware<M>(mut self, val: M) -> Self
where
M: Middleware<Update> + 'a,
{
self.middlewares.push(Box::new(val));
self
}
/// Registers a handler of errors, produced by other handlers. /// Registers a handler of errors, produced by other handlers.
#[must_use] #[must_use]
pub fn handlers_error_handler<T>(mut self, val: T) -> Self pub fn handlers_error_handler<T>(mut self, val: T) -> Self
@ -90,106 +82,125 @@ where
self self
} }
#[must_use] /// Registers a single handler.
pub fn message_handler<H>(mut self, h: H) -> Self fn register_handler<Upd, H, I>(
where handlers: &mut Handlers<'a, Upd, HandlerE>,
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a, h: H,
) where
H: CtxHandler<DispatcherHandlerCtx<Upd>, I> + 'a,
I: Into<DispatcherHandlerResult<Upd, HandlerE>>,
{ {
self.message_handler = Some(Box::new(h)); handlers
.push(Box::new(move |ctx| map_fut(h.handle_ctx(ctx), Into::into)));
}
#[must_use]
pub fn message_handler<H, I>(mut self, h: H) -> Self
where
H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
I: Into<DispatcherHandlerResult<Message, HandlerE>>,
{
Self::register_handler(&mut self.message_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn edited_message_handler<H>(mut self, h: H) -> Self pub fn edited_message_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
I: Into<DispatcherHandlerResult<Message, HandlerE>>,
{ {
self.edited_message_handler = Some(Box::new(h)); Self::register_handler(&mut self.edited_message_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn channel_post_handler<H>(mut self, h: H) -> Self pub fn channel_post_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
I: Into<DispatcherHandlerResult<Message, HandlerE>>,
{ {
self.channel_post_handler = Some(Box::new(h)); Self::register_handler(&mut self.channel_post_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn edited_channel_post_handler<H>(mut self, h: H) -> Self pub fn edited_channel_post_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Message>, I> + 'a,
I: Into<DispatcherHandlerResult<Message, HandlerE>>,
{ {
self.edited_channel_post_handler = Some(Box::new(h)); Self::register_handler(&mut self.edited_channel_post_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn inline_query_handler<H>(mut self, h: H) -> Self pub fn inline_query_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler<DispatcherHandlerCtx<InlineQuery>, Result<(), HandlerE>> H: CtxHandler<DispatcherHandlerCtx<InlineQuery>, I> + 'a,
+ 'a, I: Into<DispatcherHandlerResult<InlineQuery, HandlerE>>,
{ {
self.inline_query_handler = Some(Box::new(h)); Self::register_handler(&mut self.inline_query_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn chosen_inline_result_handler<H>(mut self, h: H) -> Self pub fn chosen_inline_result_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler< H: CtxHandler<DispatcherHandlerCtx<ChosenInlineResult>, I> + 'a,
DispatcherHandlerCtx<ChosenInlineResult>, I: Into<DispatcherHandlerResult<ChosenInlineResult, HandlerE>>,
Result<(), HandlerE>,
> + 'a,
{ {
self.chosen_inline_result_handler = Some(Box::new(h)); Self::register_handler(&mut self.chosen_inline_result_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn callback_query_handler<H>(mut self, h: H) -> Self pub fn callback_query_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler< H: CtxHandler<DispatcherHandlerCtx<CallbackQuery>, I> + 'a,
DispatcherHandlerCtx<CallbackQuery>, I: Into<DispatcherHandlerResult<CallbackQuery, HandlerE>>,
Result<(), HandlerE>,
> + 'a,
{ {
self.callback_query_handler = Some(Box::new(h)); Self::register_handler(&mut self.callback_query_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn shipping_query_handler<H>(mut self, h: H) -> Self pub fn shipping_query_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler< H: CtxHandler<DispatcherHandlerCtx<ShippingQuery>, I> + 'a,
DispatcherHandlerCtx<ShippingQuery>, I: Into<DispatcherHandlerResult<ShippingQuery, HandlerE>>,
Result<(), HandlerE>,
> + 'a,
{ {
self.shipping_query_handler = Some(Box::new(h)); Self::register_handler(&mut self.shipping_query_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn pre_checkout_query_handler<H>(mut self, h: H) -> Self pub fn pre_checkout_query_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler< H: CtxHandler<DispatcherHandlerCtx<PreCheckoutQuery>, I> + 'a,
DispatcherHandlerCtx<PreCheckoutQuery>, I: Into<DispatcherHandlerResult<PreCheckoutQuery, HandlerE>>,
Result<(), HandlerE>,
> + 'a,
{ {
self.pre_checkout_query_handler = Some(Box::new(h)); Self::register_handler(&mut self.pre_checkout_query_handlers, h);
self self
} }
#[must_use] #[must_use]
pub fn poll_handler<H>(mut self, h: H) -> Self pub fn poll_handler<H, I>(mut self, h: H) -> Self
where where
H: CtxHandler<DispatcherHandlerCtx<Poll>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Poll>, I> + 'a,
I: Into<DispatcherHandlerResult<Poll, HandlerE>>,
{ {
self.poll_handler = Some(Box::new(h)); Self::register_handler(&mut self.poll_handlers, h);
self
}
#[must_use]
pub fn poll_answer_handler<H, I>(mut self, h: H) -> Self
where
H: CtxHandler<DispatcherHandlerCtx<PollAnswer>, I> + 'a,
I: Into<DispatcherHandlerResult<PollAnswer, HandlerE>>,
{
Self::register_handler(&mut self.poll_answer_handlers, h);
self self
} }
@ -228,59 +239,52 @@ where
} }
}; };
let update = stream::iter(&self.middlewares) let update =
.fold(Some(update), |acc, middleware| async move { match self.handle(&self.update_handlers, update).await {
// Option::and_then is not working here, because Some(update) => update,
// Middleware::handle is asynchronous. None => return,
match acc { };
Some(update) => middleware.handle(update).await,
None => None,
}
})
.await;
if let Some(update) = update {
match update.kind { match update.kind {
UpdateKind::Message(message) => { UpdateKind::Message(message) => {
self.handle(&self.message_handler, message).await self.handle(&self.message_handlers, message).await;
} }
UpdateKind::EditedMessage(message) => { UpdateKind::EditedMessage(message) => {
self.handle(&self.edited_message_handler, message) self.handle(&self.edited_message_handlers, message)
.await .await;
} }
UpdateKind::ChannelPost(post) => { UpdateKind::ChannelPost(post) => {
self.handle(&self.channel_post_handler, post).await self.handle(&self.channel_post_handlers, post).await;
} }
UpdateKind::EditedChannelPost(post) => { UpdateKind::EditedChannelPost(post) => {
self.handle(&self.edited_channel_post_handler, post) self.handle(&self.edited_channel_post_handlers, post)
.await .await;
} }
UpdateKind::InlineQuery(query) => { UpdateKind::InlineQuery(query) => {
self.handle(&self.inline_query_handler, query).await self.handle(&self.inline_query_handlers, query).await;
} }
UpdateKind::ChosenInlineResult(result) => { UpdateKind::ChosenInlineResult(result) => {
self.handle( self.handle(
&self.chosen_inline_result_handler, &self.chosen_inline_result_handlers,
result, result,
) )
.await .await;
} }
UpdateKind::CallbackQuery(query) => { UpdateKind::CallbackQuery(query) => {
self.handle(&self.callback_query_handler, query) self.handle(&self.callback_query_handlers, query).await;
.await
} }
UpdateKind::ShippingQuery(query) => { UpdateKind::ShippingQuery(query) => {
self.handle(&self.shipping_query_handler, query) self.handle(&self.shipping_query_handlers, query).await;
.await
} }
UpdateKind::PreCheckoutQuery(query) => { UpdateKind::PreCheckoutQuery(query) => {
self.handle(&self.pre_checkout_query_handler, query) self.handle(&self.pre_checkout_query_handlers, query)
.await .await;
} }
UpdateKind::Poll(poll) => { UpdateKind::Poll(poll) => {
self.handle(&self.poll_handler, poll).await self.handle(&self.poll_handlers, poll).await;
} }
_ => unreachable!(), UpdateKind::PollAnswer(answer) => {
self.handle(&self.poll_answer_handlers, answer).await;
} }
} }
}) })
@ -288,17 +292,40 @@ where
} }
// Handles a single update. // Handles a single update.
async fn handle<Upd>(&self, handler: &H<'a, Upd, HandlerE>, update: Upd) { #[allow(clippy::ptr_arg)]
if let Some(handler) = &handler { async fn handle<Upd>(
if let Err(error) = handler &self,
handlers: &Handlers<'a, Upd, HandlerE>,
update: Upd,
) -> Option<Upd> {
stream::iter(handlers)
.fold(Some(update), |acc, handler| async move {
// Option::and_then is not working here, because
// Middleware::handle is asynchronous.
match acc {
Some(update) => {
let DispatcherHandlerResult { next, result } = handler
.handle_ctx(DispatcherHandlerCtx { .handle_ctx(DispatcherHandlerCtx {
bot: Arc::clone(&self.bot), bot: Arc::clone(&self.bot),
update, update,
}) })
.await;
if let Err(error) = result {
self.handlers_error_handler
.handle_error(error)
.await .await
{
self.handlers_error_handler.handle_error(error).await;
} }
next
} }
None => None,
}
})
.await
} }
} }
async fn map_fut<T, U>(fut: impl Future<Output = T>, f: impl Fn(T) -> U) -> U {
f(fut.await)
}

View file

@ -0,0 +1,23 @@
/// A result of a handler in [`Dispatcher`].
///
/// See [the module-level documentation for the design
/// overview](crate::dispatching).
///
/// [`Dispatcher`]: crate::dispatching::Dispatcher
pub struct DispatcherHandlerResult<Upd, E> {
next: Option<Upd>,
result: Result<(), E>,
}
impl<Upd, E> DispatcherHandlerResult<Upd, E> {
/// Creates new `DispatcherHandlerResult`.
pub fn new(next: Option<Upd>, result: Result<(), E>) -> Self {
Self { next, result }
}
}
impl<Upd, E> From<Result<(), E>> for DispatcherHandlerResult<Upd, E> {
fn from(result: Result<(), E>) -> Self {
Self::new(None, result)
}
}

View file

@ -1,31 +0,0 @@
use std::{future::Future, pin::Pin};
/// An asynchronous middleware.
///
/// See [the module-level documentation for the design
/// overview](crate::dispatching).
pub trait Middleware<T> {
#[must_use]
fn handle<'a>(
&'a self,
val: T,
) -> Pin<Box<dyn Future<Output = Option<T>> + 'a>>
where
T: 'a;
}
impl<T, F, Fut> Middleware<T> for F
where
F: Fn(T) -> Fut,
Fut: Future<Output = Option<T>>,
{
fn handle<'a>(
&'a self,
val: T,
) -> Pin<Box<dyn Future<Output = Fut::Output> + 'a>>
where
T: 'a,
{
Box::pin(async move { self(val).await })
}
}

View file

@ -45,15 +45,15 @@ mod ctx_handlers;
pub mod dialogue; pub mod dialogue;
mod dispatcher; mod dispatcher;
mod dispatcher_handler_ctx; mod dispatcher_handler_ctx;
mod dispatcher_handler_result;
mod error_handlers; mod error_handlers;
mod middleware;
pub mod update_listeners; pub mod update_listeners;
pub use ctx_handlers::CtxHandler; pub use ctx_handlers::CtxHandler;
pub use dispatcher::Dispatcher; pub use dispatcher::Dispatcher;
pub use dispatcher_handler_ctx::DispatcherHandlerCtx; pub use dispatcher_handler_ctx::DispatcherHandlerCtx;
pub use dispatcher_handler_result::DispatcherHandlerResult;
pub use error_handlers::{ pub use error_handlers::{
ErrorHandler, IgnoringErrorHandler, IgnoringErrorHandlerSafe, ErrorHandler, IgnoringErrorHandler, IgnoringErrorHandlerSafe,
LoggingErrorHandler, LoggingErrorHandler,
}; };
pub use middleware::Middleware;