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::{ use crate::{
dispatching::{ dispatching::{
update_listeners, update_listeners::UpdateListener, AsyncHandler, error_handlers::ErrorHandler, update_listeners,
HandlerCtx, LoggingHandler, update_listeners::UpdateListener, CtxHandler, DispatcherHandlerCtx,
LoggingErrorHandler, Middleware,
}, },
types::{ types::{
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll, CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
PreCheckoutQuery, ShippingQuery, UpdateKind, PreCheckoutQuery, ShippingQuery, Update, UpdateKind,
}, },
Bot, Bot,
}; };
use futures::StreamExt; use futures::{stream, StreamExt};
use std::{fmt::Debug, sync::Arc}; use std::{fmt::Debug, sync::Arc};
type H<'a, Upd, HandlerE> = type H<'a, Upd, HandlerE> = Option<
Option<Box<dyn AsyncHandler<HandlerCtx<Upd>, Result<(), HandlerE>> + 'a>>; Box<dyn CtxHandler<DispatcherHandlerCtx<Upd>, Result<(), HandlerE>> + 'a>,
>;
/// One dispatcher to rule them all. /// One dispatcher to rule them all.
/// ///
@ -22,7 +24,9 @@ type H<'a, Upd, HandlerE> =
pub struct Dispatcher<'a, HandlerE> { pub struct Dispatcher<'a, HandlerE> {
bot: Arc<Bot>, 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>, message_handler: H<'a, Message, HandlerE>,
edited_message_handler: H<'a, Message, HandlerE>, edited_message_handler: H<'a, Message, HandlerE>,
@ -45,7 +49,8 @@ where
pub fn new(bot: Bot) -> Self { pub fn new(bot: Bot) -> Self {
Self { Self {
bot: Arc::new(bot), 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", "An error from a Dispatcher's handler",
)), )),
message_handler: None, 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. /// 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
where where
T: AsyncHandler<HandlerE, ()> + 'a, T: ErrorHandler<HandlerE> + 'a,
{ {
self.handlers_error_handler = Box::new(val); self.handlers_error_handler = Box::new(val);
self self
@ -74,7 +89,7 @@ where
#[must_use] #[must_use]
pub fn message_handler<H>(mut self, h: H) -> Self pub fn message_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{ {
self.message_handler = Some(Box::new(h)); self.message_handler = Some(Box::new(h));
self self
@ -83,7 +98,7 @@ where
#[must_use] #[must_use]
pub fn edited_message_handler<H>(mut self, h: H) -> Self pub fn edited_message_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{ {
self.edited_message_handler = Some(Box::new(h)); self.edited_message_handler = Some(Box::new(h));
self self
@ -92,7 +107,7 @@ where
#[must_use] #[must_use]
pub fn channel_post_handler<H>(mut self, h: H) -> Self pub fn channel_post_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<Message>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Message>, Result<(), HandlerE>> + 'a,
{ {
self.channel_post_handler = Some(Box::new(h)); self.channel_post_handler = Some(Box::new(h));
self self
@ -101,7 +116,7 @@ where
#[must_use] #[must_use]
pub fn edited_channel_post_handler<H>(mut self, h: H) -> Self pub fn edited_channel_post_handler<H>(mut self, h: H) -> Self
where 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.edited_channel_post_handler = Some(Box::new(h));
self self
@ -110,7 +125,8 @@ where
#[must_use] #[must_use]
pub fn inline_query_handler<H>(mut self, h: H) -> Self pub fn inline_query_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<InlineQuery>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<InlineQuery>, Result<(), HandlerE>>
+ 'a,
{ {
self.inline_query_handler = Some(Box::new(h)); self.inline_query_handler = Some(Box::new(h));
self self
@ -119,8 +135,10 @@ where
#[must_use] #[must_use]
pub fn chosen_inline_result_handler<H>(mut self, h: H) -> Self pub fn chosen_inline_result_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<ChosenInlineResult>, Result<(), HandlerE>> H: CtxHandler<
+ 'a, DispatcherHandlerCtx<ChosenInlineResult>,
Result<(), HandlerE>,
> + 'a,
{ {
self.chosen_inline_result_handler = Some(Box::new(h)); self.chosen_inline_result_handler = Some(Box::new(h));
self self
@ -129,7 +147,10 @@ where
#[must_use] #[must_use]
pub fn callback_query_handler<H>(mut self, h: H) -> Self pub fn callback_query_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<CallbackQuery>, Result<(), HandlerE>> + 'a, H: CtxHandler<
DispatcherHandlerCtx<CallbackQuery>,
Result<(), HandlerE>,
> + 'a,
{ {
self.callback_query_handler = Some(Box::new(h)); self.callback_query_handler = Some(Box::new(h));
self self
@ -138,7 +159,10 @@ where
#[must_use] #[must_use]
pub fn shipping_query_handler<H>(mut self, h: H) -> Self pub fn shipping_query_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<ShippingQuery>, Result<(), HandlerE>> + 'a, H: CtxHandler<
DispatcherHandlerCtx<ShippingQuery>,
Result<(), HandlerE>,
> + 'a,
{ {
self.shipping_query_handler = Some(Box::new(h)); self.shipping_query_handler = Some(Box::new(h));
self self
@ -147,8 +171,10 @@ where
#[must_use] #[must_use]
pub fn pre_checkout_query_handler<H>(mut self, h: H) -> Self pub fn pre_checkout_query_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<PreCheckoutQuery>, Result<(), HandlerE>> H: CtxHandler<
+ 'a, DispatcherHandlerCtx<PreCheckoutQuery>,
Result<(), HandlerE>,
> + 'a,
{ {
self.pre_checkout_query_handler = Some(Box::new(h)); self.pre_checkout_query_handler = Some(Box::new(h));
self self
@ -157,7 +183,7 @@ where
#[must_use] #[must_use]
pub fn poll_handler<H>(mut self, h: H) -> Self pub fn poll_handler<H>(mut self, h: H) -> Self
where where
H: AsyncHandler<HandlerCtx<Poll>, Result<(), HandlerE>> + 'a, H: CtxHandler<DispatcherHandlerCtx<Poll>, Result<(), HandlerE>> + 'a,
{ {
self.poll_handler = Some(Box::new(h)); self.poll_handler = Some(Box::new(h));
self self
@ -170,7 +196,7 @@ where
pub async fn dispatch(&'a self) { pub async fn dispatch(&'a self) {
self.dispatch_with_listener( self.dispatch_with_listener(
update_listeners::polling_default(Arc::clone(&self.bot)), 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; .await;
} }
@ -183,7 +209,7 @@ where
update_listener_error_handler: &'a Eh, update_listener_error_handler: &'a Eh,
) where ) where
UListener: UpdateListener<ListenerE> + 'a, UListener: UpdateListener<ListenerE> + 'a,
Eh: AsyncHandler<ListenerE, ()> + 'a, Eh: ErrorHandler<ListenerE> + 'a,
ListenerE: Debug, ListenerE: Debug,
{ {
let update_listener = Box::pin(update_listener); let update_listener = Box::pin(update_listener);
@ -193,11 +219,17 @@ where
let update = match update { let update = match update {
Ok(update) => update, Ok(update) => update,
Err(error) => { Err(error) => {
update_listener_error_handler.handle(error).await; update_listener_error_handler.handle_error(error).await;
return; return;
} }
}; };
let update = stream::iter(&self.middlewares)
.fold(update, |acc, middleware| async move {
middleware.handle(acc).await
})
.await;
match update.kind { match update.kind {
UpdateKind::Message(message) => { UpdateKind::Message(message) => {
self.handle(&self.message_handler, message).await self.handle(&self.message_handler, message).await
@ -241,13 +273,13 @@ where
async fn handle<Upd>(&self, handler: &H<'a, Upd, HandlerE>, update: Upd) { async fn handle<Upd>(&self, handler: &H<'a, Upd, HandlerE>, update: Upd) {
if let Some(handler) = &handler { if let Some(handler) = &handler {
if let Err(error) = handler if let Err(error) = handler
.handle(HandlerCtx { .handle_ctx(DispatcherHandlerCtx {
bot: Arc::clone(&self.bot), bot: Arc::clone(&self.bot),
update, update,
}) })
.await .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). /// overview](crate::dispatching).
/// ///
/// [`Dispatcher`]: crate::dispatching::Dispatcher /// [`Dispatcher`]: crate::dispatching::Dispatcher
pub struct HandlerCtx<Upd> { pub struct DispatcherHandlerCtx<Upd> {
pub bot: Arc<Bot>, pub bot: Arc<Bot>,
pub update: Upd, pub update: Upd,
} }
impl<Upd> GetChatId for HandlerCtx<Upd> impl<Upd> GetChatId for DispatcherHandlerCtx<Upd>
where where
Upd: GetChatId, Upd: GetChatId,
{ {
@ -26,7 +26,7 @@ where
} }
} }
impl HandlerCtx<Message> { impl DispatcherHandlerCtx<Message> {
pub async fn reply<T>(&self, text: T) -> ResponseResult<()> pub async fn reply<T>(&self, text: T) -> ResponseResult<()>
where where
T: Into<String>, 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. //! Updates dispatching.
//! //!
//! The key type here is [`Dispatcher`]. It encapsulates [`UpdateListener`], a //! The key type here is [`Dispatcher`]. It encapsulates middlewares, handlers
//! handler of errors, and handlers for [10 update kinds]. When [`Update`] is //! for [10 update kinds], and [`ErrorHandler`] for them. When [`Update`] is
//! received from Telegram, it is supplied to an appropriate handler, and if a //! received from Telegram, the following steps are executed:
//! handler has returned an error, the error is supplied into an error handler. //!
//! 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! //! That's simple!
//! //!
//! All the handlers are of type [`AsyncHandler`]. It's like a [first-class //! Note that handlers implement [`CtxHandler`], which means that you are able
//! construction] in this module, because: //! to supply [`SessionDispatcher`] as a handler, since it implements
//! 1. It is implemented for [`SessionDispatcher`], which itself accepts //! [`CtxHandler`] too!
//! [`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...
//! //!
//! ## Examples //! ## Examples
//! The ping-pong bot ([full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/)): //! The ping-pong bot ([full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/)):
@ -27,7 +26,7 @@
//! // Setup logging here... //! // Setup logging here...
//! //!
//! Dispatcher::new(Bot::new("MyAwesomeToken")) //! Dispatcher::new(Bot::new("MyAwesomeToken"))
//! .message_handler(|ctx: HandlerCtx<Message>| async move { //! .message_handler(|ctx: DispatcherHandlerCtx<Message>| async move {
//! ctx.reply("pong").await //! ctx.reply("pong").await
//! }) //! })
//! .dispatch() //! .dispatch()
@ -35,26 +34,26 @@
//! # } //! # }
//! ``` //! ```
//! //!
//! [first-class construction]: https://stackoverflow.com/questions/646794/what-is-a-first-class-programming-construct
//! [`Dispatcher`]: crate::dispatching::Dispatcher //! [`Dispatcher`]: crate::dispatching::Dispatcher
//! [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
//! [10 update kinds]: crate::types::UpdateKind //! [10 update kinds]: crate::types::UpdateKind
//! [`Update`]: crate::types::Update //! [`Update`]: crate::types::Update
//! [`AsyncHandler`]: crate::dispatching::AsyncHandler //! [`ErrorHandler`]: crate::dispatching::ErrorHandler
//! [`LoggingHandler`]: crate::dispatching::LoggingHandler //! [`CtxHandler`]: crate::dispatching::CtxHandler
//! [`IgnoringHandler`]: crate::dispatching::IgnoringHandler //! [`SessionDispatcher`]: crate::dispatching::SessionDispatcher
//! [`IgnoringHandlerSafe`]: crate::dispatching::IgnoringHandlerSafe
//! [for asynchronous functions]: crate::dispatching::AsyncHandler
//! [`SessionDispatcher`]: crate::dispatching::session::SessionDispatcher
mod async_handlers; mod ctx_handlers;
mod dispatcher; mod dispatcher;
mod handler_ctx; mod dispatcher_handler_ctx;
mod error_handlers;
mod middleware;
pub mod session; pub mod session;
pub mod update_listeners; pub mod update_listeners;
pub use async_handlers::{ pub use ctx_handlers::CtxHandler;
AsyncHandler, IgnoringHandler, IgnoringHandlerSafe, LoggingHandler,
};
pub use dispatcher::Dispatcher; 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 //! 3. Your handler, which receives an update and turns your session into the
//! next state. //! next state.
//! 4. [`SessionDispatcher`], which encapsulates your handler, [`Storage`], and //! 4. [`SessionDispatcher`], which encapsulates your handler, [`Storage`], and
//! implements [`AsyncHandler`]. //! implements [`CtxHandler`].
//! //!
//! You supply [`SessionDispatcher`] into [`Dispatcher`]. Every time //! You supply [`SessionDispatcher`] into [`Dispatcher`]. Every time
//! [`Dispatcher`] calls `SessionDispatcher::handle(...)`, the following steps //! [`Dispatcher`] calls `SessionDispatcher::handle_ctx(...)`, the following
//! are executed: //! steps are executed:
//! //!
//! 1. If a storage doesn't contain a session from this chat, supply //! 1. If a storage doesn't contain a session from this chat, supply
//! `Session::default()` into you handler, otherwise, supply the saved session //! `Session::default()` into you handler, otherwise, supply the saved session
@ -26,7 +26,7 @@
//! [`SessionState::Exit`]: //! [`SessionState::Exit`]:
//! crate::dispatching::session::SessionState::Exit //! crate::dispatching::session::SessionState::Exit
//! [`SessionState::Next`]: crate::dispatching::session::SessionState::Next //! [`SessionState::Next`]: crate::dispatching::session::SessionState::Next
//! [`AsyncHandler`]: crate::dispatching::AsyncHandler //! [`CtxHandler`]: crate::dispatching::CtxHandler
//! [`Dispatcher`]: crate::dispatching::Dispatcher //! [`Dispatcher`]: crate::dispatching::Dispatcher
// TODO: examples // TODO: examples

View file

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

View file

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