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::{
error_handlers::ErrorHandler, update_listeners,
update_listeners::UpdateListener, CtxHandler, DispatcherHandlerCtx,
LoggingErrorHandler, Middleware,
DispatcherHandlerResult, LoggingErrorHandler,
},
types::{
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
PreCheckoutQuery, ShippingQuery, Update, UpdateKind,
PollAnswer, PreCheckoutQuery, ShippingQuery, Update, UpdateKind,
},
Bot,
};
use futures::{stream, StreamExt};
use std::{fmt::Debug, sync::Arc};
use std::{fmt::Debug, future::Future, sync::Arc};
type H<'a, Upd, HandlerE> = Option<
Box<dyn CtxHandler<DispatcherHandlerCtx<Upd>, Result<(), HandlerE>> + 'a>,
type Handlers<'a, Upd, HandlerE> = Vec<
Box<
dyn CtxHandler<
DispatcherHandlerCtx<Upd>,
DispatcherHandlerResult<Upd, HandlerE>,
> + 'a,
>,
>;
/// One dispatcher to rule them all.
@ -24,20 +29,20 @@ type H<'a, Upd, HandlerE> = Option<
pub struct Dispatcher<'a, HandlerE> {
bot: Arc<Bot>,
middlewares: Vec<Box<dyn Middleware<Update> + 'a>>,
handlers_error_handler: Box<dyn ErrorHandler<HandlerE> + 'a>,
message_handler: H<'a, Message, HandlerE>,
edited_message_handler: H<'a, Message, HandlerE>,
channel_post_handler: H<'a, Message, HandlerE>,
edited_channel_post_handler: H<'a, Message, HandlerE>,
inline_query_handler: H<'a, InlineQuery, HandlerE>,
chosen_inline_result_handler: H<'a, ChosenInlineResult, HandlerE>,
callback_query_handler: H<'a, CallbackQuery, HandlerE>,
shipping_query_handler: H<'a, ShippingQuery, HandlerE>,
pre_checkout_query_handler: H<'a, PreCheckoutQuery, HandlerE>,
poll_handler: H<'a, Poll, HandlerE>,
update_handlers: Handlers<'a, Update, HandlerE>,
message_handlers: Handlers<'a, Message, HandlerE>,
edited_message_handlers: Handlers<'a, Message, HandlerE>,
channel_post_handlers: Handlers<'a, Message, HandlerE>,
edited_channel_post_handlers: Handlers<'a, Message, HandlerE>,
inline_query_handlers: Handlers<'a, InlineQuery, HandlerE>,
chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, HandlerE>,
callback_query_handlers: Handlers<'a, CallbackQuery, HandlerE>,
shipping_query_handlers: Handlers<'a, ShippingQuery, 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>
@ -49,37 +54,24 @@ where
pub fn new(bot: Bot) -> Self {
Self {
bot: Arc::new(bot),
middlewares: Vec::new(),
handlers_error_handler: Box::new(LoggingErrorHandler::new(
"An error from a Dispatcher's handler",
)),
message_handler: None,
edited_message_handler: None,
channel_post_handler: None,
edited_channel_post_handler: None,
inline_query_handler: None,
chosen_inline_result_handler: None,
callback_query_handler: None,
shipping_query_handler: None,
pre_checkout_query_handler: None,
poll_handler: None,
update_handlers: Vec::new(),
message_handlers: Vec::new(),
edited_message_handlers: Vec::new(),
channel_post_handlers: Vec::new(),
edited_channel_post_handlers: Vec::new(),
inline_query_handlers: Vec::new(),
chosen_inline_result_handlers: Vec::new(),
callback_query_handlers: Vec::new(),
shipping_query_handlers: Vec::new(),
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.
#[must_use]
pub fn handlers_error_handler<T>(mut self, val: T) -> Self
@ -90,106 +82,125 @@ where
self
}
#[must_use]
pub fn message_handler<H>(mut self, h: H) -> Self
where
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
/// Registers a single handler.
fn register_handler<Upd, H, I>(
handlers: &mut Handlers<'a, Upd, HandlerE>,
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
}
#[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
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
}
#[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
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
}
#[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
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
}
#[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
H: CtxHandler<DispatcherHandlerCtx<InlineQuery>, Result<(), HandlerE>>
+ 'a,
H: CtxHandler<DispatcherHandlerCtx<InlineQuery>, I> + 'a,
I: Into<DispatcherHandlerResult<InlineQuery, HandlerE>>,
{
self.inline_query_handler = Some(Box::new(h));
Self::register_handler(&mut self.inline_query_handlers, h);
self
}
#[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
H: CtxHandler<
DispatcherHandlerCtx<ChosenInlineResult>,
Result<(), HandlerE>,
> + 'a,
H: CtxHandler<DispatcherHandlerCtx<ChosenInlineResult>, I> + 'a,
I: Into<DispatcherHandlerResult<ChosenInlineResult, HandlerE>>,
{
self.chosen_inline_result_handler = Some(Box::new(h));
Self::register_handler(&mut self.chosen_inline_result_handlers, h);
self
}
#[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
H: CtxHandler<
DispatcherHandlerCtx<CallbackQuery>,
Result<(), HandlerE>,
> + 'a,
H: CtxHandler<DispatcherHandlerCtx<CallbackQuery>, I> + 'a,
I: Into<DispatcherHandlerResult<CallbackQuery, HandlerE>>,
{
self.callback_query_handler = Some(Box::new(h));
Self::register_handler(&mut self.callback_query_handlers, h);
self
}
#[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
H: CtxHandler<
DispatcherHandlerCtx<ShippingQuery>,
Result<(), HandlerE>,
> + 'a,
H: CtxHandler<DispatcherHandlerCtx<ShippingQuery>, I> + 'a,
I: Into<DispatcherHandlerResult<ShippingQuery, HandlerE>>,
{
self.shipping_query_handler = Some(Box::new(h));
Self::register_handler(&mut self.shipping_query_handlers, h);
self
}
#[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
H: CtxHandler<
DispatcherHandlerCtx<PreCheckoutQuery>,
Result<(), HandlerE>,
> + 'a,
H: CtxHandler<DispatcherHandlerCtx<PreCheckoutQuery>, I> + 'a,
I: Into<DispatcherHandlerResult<PreCheckoutQuery, HandlerE>>,
{
self.pre_checkout_query_handler = Some(Box::new(h));
Self::register_handler(&mut self.pre_checkout_query_handlers, h);
self
}
#[must_use]
pub fn poll_handler<H>(mut self, h: H) -> Self
pub fn poll_handler<H, I>(mut self, h: H) -> Self
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
}
@ -228,59 +239,52 @@ where
}
};
let update = stream::iter(&self.middlewares)
.fold(Some(update), |acc, middleware| async move {
// Option::and_then is not working here, because
// Middleware::handle is asynchronous.
match acc {
Some(update) => middleware.handle(update).await,
None => None,
}
})
.await;
let update =
match self.handle(&self.update_handlers, update).await {
Some(update) => update,
None => return,
};
if let Some(update) = update {
match update.kind {
UpdateKind::Message(message) => {
self.handle(&self.message_handler, message).await
}
UpdateKind::EditedMessage(message) => {
self.handle(&self.edited_message_handler, message)
.await
}
UpdateKind::ChannelPost(post) => {
self.handle(&self.channel_post_handler, post).await
}
UpdateKind::EditedChannelPost(post) => {
self.handle(&self.edited_channel_post_handler, post)
.await
}
UpdateKind::InlineQuery(query) => {
self.handle(&self.inline_query_handler, query).await
}
UpdateKind::ChosenInlineResult(result) => {
self.handle(
&self.chosen_inline_result_handler,
result,
)
.await
}
UpdateKind::CallbackQuery(query) => {
self.handle(&self.callback_query_handler, query)
.await
}
UpdateKind::ShippingQuery(query) => {
self.handle(&self.shipping_query_handler, query)
.await
}
UpdateKind::PreCheckoutQuery(query) => {
self.handle(&self.pre_checkout_query_handler, query)
.await
}
UpdateKind::Poll(poll) => {
self.handle(&self.poll_handler, poll).await
}
_ => unreachable!(),
match update.kind {
UpdateKind::Message(message) => {
self.handle(&self.message_handlers, message).await;
}
UpdateKind::EditedMessage(message) => {
self.handle(&self.edited_message_handlers, message)
.await;
}
UpdateKind::ChannelPost(post) => {
self.handle(&self.channel_post_handlers, post).await;
}
UpdateKind::EditedChannelPost(post) => {
self.handle(&self.edited_channel_post_handlers, post)
.await;
}
UpdateKind::InlineQuery(query) => {
self.handle(&self.inline_query_handlers, query).await;
}
UpdateKind::ChosenInlineResult(result) => {
self.handle(
&self.chosen_inline_result_handlers,
result,
)
.await;
}
UpdateKind::CallbackQuery(query) => {
self.handle(&self.callback_query_handlers, query).await;
}
UpdateKind::ShippingQuery(query) => {
self.handle(&self.shipping_query_handlers, query).await;
}
UpdateKind::PreCheckoutQuery(query) => {
self.handle(&self.pre_checkout_query_handlers, query)
.await;
}
UpdateKind::Poll(poll) => {
self.handle(&self.poll_handlers, poll).await;
}
UpdateKind::PollAnswer(answer) => {
self.handle(&self.poll_answer_handlers, answer).await;
}
}
})
@ -288,17 +292,40 @@ where
}
// Handles a single update.
async fn handle<Upd>(&self, handler: &H<'a, Upd, HandlerE>, update: Upd) {
if let Some(handler) = &handler {
if let Err(error) = handler
.handle_ctx(DispatcherHandlerCtx {
bot: Arc::clone(&self.bot),
update,
})
.await
{
self.handlers_error_handler.handle_error(error).await;
}
}
#[allow(clippy::ptr_arg)]
async fn handle<Upd>(
&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 {
bot: Arc::clone(&self.bot),
update,
})
.await;
if let Err(error) = result {
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;
mod dispatcher;
mod dispatcher_handler_ctx;
mod dispatcher_handler_result;
mod error_handlers;
mod middleware;
pub mod update_listeners;
pub use ctx_handlers::CtxHandler;
pub use dispatcher::Dispatcher;
pub use dispatcher_handler_ctx::DispatcherHandlerCtx;
pub use dispatcher_handler_result::DispatcherHandlerResult;
pub use error_handlers::{
ErrorHandler, IgnoringErrorHandler, IgnoringErrorHandlerSafe,
LoggingErrorHandler,
};
pub use middleware::Middleware;