mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-31 16:40:37 +01:00
Rework handlers (failing now)
This commit is contained in:
parent
ab8dae9213
commit
e6bf25b3bf
4 changed files with 203 additions and 184 deletions
|
@ -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)
|
||||
}
|
||||
|
|
23
src/dispatching/dispatcher_handler_result.rs
Normal file
23
src/dispatching/dispatcher_handler_result.rs
Normal 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)
|
||||
}
|
||||
}
|
|
@ -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 })
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue