Divide AsyncHandler into different traits

This commit is contained in:
Temirkhan Myrzamadi 2020-02-03 16:25:05 +06:00
parent ee3a95b31e
commit 7e34007a4d
10 changed files with 306 additions and 213 deletions

View file

@ -1,145 +0,0 @@
use std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};
/// An asynchronous polymorphic handler of a context.
///
/// See [the module-level documentation for the design
/// overview](crate::dispatching).
pub trait AsyncHandler<Ctx, Output> {
#[must_use]
fn handle<'a>(
&'a self,
ctx: Ctx,
) -> Pin<Box<dyn Future<Output = Output> + 'a>>
where
Ctx: 'a;
}
impl<Ctx, Output, F, Fut> AsyncHandler<Ctx, Output> for F
where
F: Fn(Ctx) -> Fut,
Fut: Future<Output = Output>,
{
fn handle<'a>(
&'a self,
ctx: Ctx,
) -> Pin<Box<dyn Future<Output = Fut::Output> + 'a>>
where
Ctx: 'a,
{
Box::pin(async move { self(ctx).await })
}
}
/// A handler that silently ignores all values.
///
/// ## Example
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use teloxide::dispatching::{AsyncHandler, IgnoringHandler};
///
/// IgnoringHandler.handle(()).await;
/// IgnoringHandler.handle(404).await;
/// IgnoringHandler.handle("error").await;
/// # }
/// ```
pub struct IgnoringHandler;
impl<Ctx> AsyncHandler<Ctx, ()> for IgnoringHandler {
fn handle<'a>(&'a self, _: Ctx) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
Ctx: 'a,
{
Box::pin(async {})
}
}
/// A handler that silently ignores all values that can never happen (e.g.:
/// [`!`] or [`Infallible`]).
///
/// ## Examples
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use std::convert::{Infallible, TryInto};
///
/// use teloxide::dispatching::{AsyncHandler, IgnoringHandlerSafe};
///
/// let result: Result<String, Infallible> = "str".try_into();
/// match result {
/// Ok(string) => println!("{}", string),
/// Err(inf) => IgnoringHandlerSafe.handle(inf).await,
/// }
///
/// IgnoringHandlerSafe.handle(return).await; // return type of `return` is `!` (aka never)
/// # }
/// ```
///
/// ```compile_fail
/// use teloxide::dispatching::{AsyncHandler, IgnoringHandlerSafe};
///
/// IgnoringHandlerSafe.handle(0);
/// ```
///
/// [`!`]: https://doc.rust-lang.org/std/primitive.never.html
/// [`Infallible`]: std::convert::Infallible
pub struct IgnoringHandlerSafe;
#[allow(unreachable_code)]
impl AsyncHandler<Infallible, ()> for IgnoringHandlerSafe {
fn handle<'a>(
&'a self,
_: Infallible,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
Infallible: 'a,
{
Box::pin(async {})
}
}
/// A handler that log all values passed into it.
///
/// ## Example
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use teloxide::dispatching::{AsyncHandler, LoggingHandler};
///
/// LoggingHandler::default().handle(()).await;
/// LoggingHandler::new("error").handle(404).await;
/// LoggingHandler::new("error")
/// .handle("Invalid data type!")
/// .await;
/// # }
/// ```
#[derive(Default)]
pub struct LoggingHandler {
text: String,
}
impl LoggingHandler {
/// Creates `LoggingHandler` with a meta text before a log.
///
/// The logs will be printed in this format: `{text}: {:?}`.
#[must_use]
pub fn new<T>(text: T) -> Self
where
T: Into<String>,
{
Self { text: text.into() }
}
}
impl<Ctx> AsyncHandler<Ctx, ()> for LoggingHandler
where
Ctx: Debug,
{
fn handle<'a>(&'a self, ctx: Ctx) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
Ctx: 'a,
{
log::debug!("{text}: {:?}", ctx, text = self.text);
Box::pin(async {})
}
}

View file

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

View file

@ -1,19 +1,21 @@
use crate::{
dispatching::{
update_listeners, update_listeners::UpdateListener, AsyncHandler,
HandlerCtx, LoggingHandler,
error_handlers::ErrorHandler, update_listeners,
update_listeners::UpdateListener, CtxHandler, DispatcherHandlerCtx,
LoggingErrorHandler, Middleware,
},
types::{
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
PreCheckoutQuery, ShippingQuery, UpdateKind,
PreCheckoutQuery, ShippingQuery, Update, UpdateKind,
},
Bot,
};
use futures::StreamExt;
use futures::{stream, StreamExt};
use std::{fmt::Debug, sync::Arc};
type H<'a, Upd, HandlerE> =
Option<Box<dyn AsyncHandler<HandlerCtx<Upd>, Result<(), HandlerE>> + 'a>>;
type H<'a, Upd, HandlerE> = Option<
Box<dyn CtxHandler<DispatcherHandlerCtx<Upd>, Result<(), HandlerE>> + 'a>,
>;
/// One dispatcher to rule them all.
///
@ -22,7 +24,9 @@ type H<'a, Upd, HandlerE> =
pub struct Dispatcher<'a, HandlerE> {
bot: Arc<Bot>,
handlers_error_handler: Box<dyn AsyncHandler<HandlerE, ()> + 'a>,
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>,
@ -45,7 +49,8 @@ where
pub fn new(bot: Bot) -> Self {
Self {
bot: Arc::new(bot),
handlers_error_handler: Box::new(LoggingHandler::new(
middlewares: Vec::new(),
handlers_error_handler: Box::new(LoggingErrorHandler::new(
"An error from a Dispatcher's handler",
)),
message_handler: None,
@ -61,11 +66,21 @@ where
}
}
/// Appends a middleware.
#[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
where
T: AsyncHandler<HandlerE, ()> + 'a,
T: ErrorHandler<HandlerE> + 'a,
{
self.handlers_error_handler = Box::new(val);
self
@ -74,7 +89,7 @@ where
#[must_use]
pub fn message_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.message_handler = Some(Box::new(h));
self
@ -83,7 +98,7 @@ where
#[must_use]
pub fn edited_message_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.edited_message_handler = Some(Box::new(h));
self
@ -92,7 +107,7 @@ where
#[must_use]
pub fn channel_post_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.channel_post_handler = Some(Box::new(h));
self
@ -101,7 +116,7 @@ where
#[must_use]
pub fn edited_channel_post_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a,
H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{
self.edited_channel_post_handler = Some(Box::new(h));
self
@ -110,7 +125,8 @@ where
#[must_use]
pub fn inline_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<InlineQuery>, Result<(), HandlerE>> + 'a,
H: CtxHandler<DispatcherHandlerCtx<InlineQuery>, Result<(), HandlerE>>
+ 'a,
{
self.inline_query_handler = Some(Box::new(h));
self
@ -119,8 +135,10 @@ where
#[must_use]
pub fn chosen_inline_result_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<ChosenInlineResult>, Result<(), HandlerE>>
+ 'a,
H: CtxHandler<
DispatcherHandlerCtx<ChosenInlineResult>,
Result<(), HandlerE>,
> + 'a,
{
self.chosen_inline_result_handler = Some(Box::new(h));
self
@ -129,7 +147,10 @@ where
#[must_use]
pub fn callback_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<CallbackQuery>, Result<(), HandlerE>> + 'a,
H: CtxHandler<
DispatcherHandlerCtx<CallbackQuery>,
Result<(), HandlerE>,
> + 'a,
{
self.callback_query_handler = Some(Box::new(h));
self
@ -138,7 +159,10 @@ where
#[must_use]
pub fn shipping_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<ShippingQuery>, Result<(), HandlerE>> + 'a,
H: CtxHandler<
DispatcherHandlerCtx<ShippingQuery>,
Result<(), HandlerE>,
> + 'a,
{
self.shipping_query_handler = Some(Box::new(h));
self
@ -147,8 +171,10 @@ where
#[must_use]
pub fn pre_checkout_query_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<PreCheckoutQuery>, Result<(), HandlerE>>
+ 'a,
H: CtxHandler<
DispatcherHandlerCtx<PreCheckoutQuery>,
Result<(), HandlerE>,
> + 'a,
{
self.pre_checkout_query_handler = Some(Box::new(h));
self
@ -157,7 +183,7 @@ where
#[must_use]
pub fn poll_handler<H>(mut self, h: H) -> Self
where
H: AsyncHandler<HandlerCtx<Poll>, Result<(), HandlerE>> + 'a,
H: CtxHandler<DispatcherHandlerCtx<Poll>, Result<(), HandlerE>> + 'a,
{
self.poll_handler = Some(Box::new(h));
self
@ -170,7 +196,7 @@ where
pub async fn dispatch(&'a self) {
self.dispatch_with_listener(
update_listeners::polling_default(Arc::clone(&self.bot)),
&LoggingHandler::new("An error from the update listener"),
&LoggingErrorHandler::new("An error from the update listener"),
)
.await;
}
@ -183,7 +209,7 @@ where
update_listener_error_handler: &'a Eh,
) where
UListener: UpdateListener<ListenerE> + 'a,
Eh: AsyncHandler<ListenerE, ()> + 'a,
Eh: ErrorHandler<ListenerE> + 'a,
ListenerE: Debug,
{
let update_listener = Box::pin(update_listener);
@ -193,11 +219,17 @@ where
let update = match update {
Ok(update) => update,
Err(error) => {
update_listener_error_handler.handle(error).await;
update_listener_error_handler.handle_error(error).await;
return;
}
};
let update = stream::iter(&self.middlewares)
.fold(update, |acc, middleware| async move {
middleware.handle(acc).await
})
.await;
match update.kind {
UpdateKind::Message(message) => {
self.handle(&self.message_handler, message).await
@ -241,13 +273,13 @@ where
async fn handle<Upd>(&self, handler: &H<'a, Upd, HandlerE>, update: Upd) {
if let Some(handler) = &handler {
if let Err(error) = handler
.handle(HandlerCtx {
.handle_ctx(DispatcherHandlerCtx {
bot: Arc::clone(&self.bot),
update,
})
.await
{
self.handlers_error_handler.handle(error).await;
self.handlers_error_handler.handle_error(error).await;
}
}
}

View file

@ -12,12 +12,12 @@ use std::sync::Arc;
/// overview](crate::dispatching).
///
/// [`Dispatcher`]: crate::dispatching::Dispatcher
pub struct HandlerCtx<Upd> {
pub struct DispatcherHandlerCtx<Upd> {
pub bot: Arc<Bot>,
pub update: Upd,
}
impl<Upd> GetChatId for HandlerCtx<Upd>
impl<Upd> GetChatId for DispatcherHandlerCtx<Upd>
where
Upd: GetChatId,
{
@ -26,7 +26,7 @@ where
}
}
impl HandlerCtx<Message> {
impl DispatcherHandlerCtx<Message> {
pub async fn reply<T>(&self, text: T) -> ResponseResult<()>
where
T: Into<String>,

View file

@ -0,0 +1,151 @@
use std::{convert::Infallible, fmt::Debug, future::Future, pin::Pin};
/// An asynchronous handler of an error.
///
/// See [the module-level documentation for the design
/// 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;
}
impl<E, F, Fut> ErrorHandler<E> for F
where
F: Fn(E) -> Fut,
Fut: Future<Output = ()>,
{
fn handle_error<'a>(
&'a self,
error: E,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
E: 'a,
{
Box::pin(async move { self(error).await })
}
}
/// A handler that silently ignores all errors.
///
/// ## Example
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use teloxide::dispatching::{ErrorHandler, IgnoringErrorHandler};
///
/// IgnoringErrorHandler.handle_error(()).await;
/// IgnoringErrorHandler.handle_error(404).await;
/// IgnoringErrorHandler.handle_error("error").await;
/// # }
/// ```
pub struct IgnoringErrorHandler;
impl<E> ErrorHandler<E> for IgnoringErrorHandler {
fn handle_error<'a>(
&'a self,
_: E,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
E: 'a,
{
Box::pin(async {})
}
}
/// A handler that silently ignores all errors that can never happen (e.g.:
/// [`!`] or [`Infallible`]).
///
/// ## Examples
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use std::convert::{Infallible, TryInto};
///
/// use teloxide::dispatching::{ErrorHandler, IgnoringErrorHandlerSafe};
///
/// let result: Result<String, Infallible> = "str".try_into();
/// match result {
/// Ok(string) => println!("{}", string),
/// Err(inf) => IgnoringErrorHandlerSafe.handle_error(inf).await,
/// }
///
/// IgnoringErrorHandlerSafe.handle_error(return).await; // return type of `return` is `!` (aka never)
/// # }
/// ```
///
/// ```compile_fail
/// use teloxide::dispatching::{ErrorHandler, IgnoringErrorHandlerSafe};
///
/// IgnoringErrorHandlerSafe.handle_error(0);
/// ```
///
/// [`!`]: https://doc.rust-lang.org/std/primitive.never.html
/// [`Infallible`]: std::convert::Infallible
pub struct IgnoringErrorHandlerSafe;
#[allow(unreachable_code)]
impl ErrorHandler<Infallible> for IgnoringErrorHandlerSafe {
fn handle_error<'a>(
&'a self,
_: Infallible,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>
where
Infallible: 'a,
{
Box::pin(async {})
}
}
/// A handler that log all errors passed into it.
///
/// ## Example
/// ```
/// # #[tokio::main]
/// # async fn main_() {
/// use teloxide::dispatching::{ErrorHandler, LoggingErrorHandler};
///
/// LoggingErrorHandler::default().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,
}
impl LoggingErrorHandler {
/// Creates `LoggingErrorHandler` with a meta text before a log.
///
/// The logs will be printed in this format: `{text}: {:?}`.
#[must_use]
pub fn new<T>(text: T) -> Self
where
T: Into<String>,
{
Self { text: text.into() }
}
}
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,
{
log::debug!("{text}: {:?}", error, text = self.text);
Box::pin(async {})
}
}

View file

@ -0,0 +1,25 @@
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 = T> + 'a>>
where
T: 'a;
}
impl<T, F, Fut> Middleware<T> for F
where
F: Fn(T) -> Fut,
Fut: Future<Output = T>,
{
fn handle<'a>(&'a self, val: T) -> Pin<Box<dyn Future<Output = T> + 'a>>
where
T: 'a,
{
Box::pin(async move { self(val).await })
}
}

View file

@ -1,20 +1,19 @@
//! Updates dispatching.
//!
//! The key type here is [`Dispatcher`]. It encapsulates [`UpdateListener`], a
//! handler of errors, and handlers for [10 update kinds]. When [`Update`] is
//! received from Telegram, it is supplied to an appropriate handler, and if a
//! handler has returned an error, the error is supplied into an error handler.
//! The key type here is [`Dispatcher`]. It encapsulates middlewares, handlers
//! for [10 update kinds], and [`ErrorHandler`] for them. When [`Update`] is
//! received from Telegram, the following steps are executed:
//!
//! 1. It is supplied into all registered middlewares.
//! 2. It is supplied to an appropriate handler.
//! 3. If a handler has returned an error, the error is supplied into an error
//! handler.
//!
//! That's simple!
//!
//! All the handlers are of type [`AsyncHandler`]. It's like a [first-class
//! construction] in this module, because:
//! 1. It is implemented for [`SessionDispatcher`], which itself accepts
//! [`AsyncHandler`].
//! 2. It is implemented for [`LoggingHandler`], [`IgnoringHandler`], and
//! [`IgnoringHandlerSafe`].
//! 3. It is implemented even [for asynchronous functions].
//! 4. You can use [`AsyncHandler`]s as error handlers.
//! 5. More...
//! Note that handlers implement [`CtxHandler`], which means that you are able
//! to supply [`SessionDispatcher`] as a handler, since it implements
//! [`CtxHandler`] too!
//!
//! ## Examples
//! The ping-pong bot ([full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/)):
@ -27,7 +26,7 @@
//! // Setup logging here...
//!
//! Dispatcher::new(Bot::new("MyAwesomeToken"))
//! .message_handler(|ctx: HandlerCtx<Message>| async move {
//! .message_handler(|ctx: DispatcherHandlerCtx<Message>| async move {
//! ctx.reply("pong").await
//! })
//! .dispatch()
@ -35,26 +34,26 @@
//! # }
//! ```
//!
//! [first-class construction]: https://stackoverflow.com/questions/646794/what-is-a-first-class-programming-construct
//! [`Dispatcher`]: crate::dispatching::Dispatcher
//! [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
//! [10 update kinds]: crate::types::UpdateKind
//! [`Update`]: crate::types::Update
//! [`AsyncHandler`]: crate::dispatching::AsyncHandler
//! [`LoggingHandler`]: crate::dispatching::LoggingHandler
//! [`IgnoringHandler`]: crate::dispatching::IgnoringHandler
//! [`IgnoringHandlerSafe`]: crate::dispatching::IgnoringHandlerSafe
//! [for asynchronous functions]: crate::dispatching::AsyncHandler
//! [`SessionDispatcher`]: crate::dispatching::session::SessionDispatcher
//! [`ErrorHandler`]: crate::dispatching::ErrorHandler
//! [`CtxHandler`]: crate::dispatching::CtxHandler
//! [`SessionDispatcher`]: crate::dispatching::SessionDispatcher
mod async_handlers;
mod ctx_handlers;
mod dispatcher;
mod handler_ctx;
mod dispatcher_handler_ctx;
mod error_handlers;
mod middleware;
pub mod session;
pub mod update_listeners;
pub use async_handlers::{
AsyncHandler, IgnoringHandler, IgnoringHandlerSafe, LoggingHandler,
};
pub use ctx_handlers::CtxHandler;
pub use dispatcher::Dispatcher;
pub use handler_ctx::HandlerCtx;
pub use dispatcher_handler_ctx::DispatcherHandlerCtx;
pub use error_handlers::{
ErrorHandler, IgnoringErrorHandler, IgnoringErrorHandlerSafe,
LoggingErrorHandler,
};
pub use middleware::Middleware;

View file

@ -8,11 +8,11 @@
//! 3. Your handler, which receives an update and turns your session into the
//! next state.
//! 4. [`SessionDispatcher`], which encapsulates your handler, [`Storage`], and
//! implements [`AsyncHandler`].
//! implements [`CtxHandler`].
//!
//! You supply [`SessionDispatcher`] into [`Dispatcher`]. Every time
//! [`Dispatcher`] calls `SessionDispatcher::handle(...)`, the following steps
//! are executed:
//! [`Dispatcher`] calls `SessionDispatcher::handle_ctx(...)`, the following
//! steps are executed:
//!
//! 1. If a storage doesn't contain a session from this chat, supply
//! `Session::default()` into you handler, otherwise, supply the saved session
@ -26,7 +26,7 @@
//! [`SessionState::Exit`]:
//! crate::dispatching::session::SessionState::Exit
//! [`SessionState::Next`]: crate::dispatching::session::SessionState::Next
//! [`AsyncHandler`]: crate::dispatching::AsyncHandler
//! [`CtxHandler`]: crate::dispatching::CtxHandler
//! [`Dispatcher`]: crate::dispatching::Dispatcher
// TODO: examples

View file

@ -2,7 +2,7 @@ use crate::dispatching::{
session::{
GetChatId, InMemStorage, SessionHandlerCtx, SessionState, Storage,
},
AsyncHandler, HandlerCtx,
CtxHandler, DispatcherHandlerCtx,
};
use std::{future::Future, pin::Pin};
@ -46,17 +46,17 @@ where
}
}
impl<'a, Session, H, Upd> AsyncHandler<HandlerCtx<Upd>, Result<(), ()>>
impl<'a, Session, H, Upd> CtxHandler<DispatcherHandlerCtx<Upd>, Result<(), ()>>
for SessionDispatcher<'a, Session, H>
where
H: AsyncHandler<SessionHandlerCtx<Upd, Session>, SessionState<Session>>,
H: CtxHandler<SessionHandlerCtx<Upd, Session>, SessionState<Session>>,
Upd: GetChatId,
Session: Default,
{
/// Dispatches a single `message` from a private chat.
fn handle<'b>(
fn handle_ctx<'b>(
&'b self,
ctx: HandlerCtx<Upd>,
ctx: DispatcherHandlerCtx<Upd>,
) -> Pin<Box<dyn Future<Output = Result<(), ()>> + 'b>>
where
Upd: 'b,
@ -72,7 +72,7 @@ where
if let SessionState::Next(new_session) = self
.handler
.handle(SessionHandlerCtx {
.handle_ctx(SessionHandlerCtx {
bot: ctx.bot,
update: ctx.update,
session,

View file

@ -5,7 +5,7 @@ pub use crate::{
session::{
GetChatId, SessionDispatcher, SessionHandlerCtx, SessionState,
},
Dispatcher, HandlerCtx,
Dispatcher, DispatcherHandlerCtx,
},
requests::{Request, ResponseResult},
types::Message,