mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-08 19:33:53 +01:00
Refactor
This commit is contained in:
parent
d7d97ef136
commit
61d002b8d4
10 changed files with 206 additions and 171 deletions
|
@ -12,4 +12,7 @@ log = "0.4.8"
|
|||
tokio = "0.2.9"
|
||||
strum = "0.17.1"
|
||||
strum_macros = "0.17.1"
|
||||
teloxide = { path = "../../" }
|
||||
teloxide = { path = "../../" }
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
|
@ -99,13 +99,13 @@ type Res = Result<SessionState<User>, RequestError>;
|
|||
|
||||
async fn start(ctx: Ctx) -> Res {
|
||||
reply!(ctx, "Let's start! First, what's your full name?");
|
||||
Ok(SessionState::Continue(ctx.session))
|
||||
Ok(SessionState::Next(ctx.session))
|
||||
}
|
||||
|
||||
async fn full_name(mut ctx: Ctx) -> Res {
|
||||
reply!(ctx, "What a wonderful name! Your age?");
|
||||
ctx.session.full_name = Some(ctx.update.text().unwrap().to_owned());
|
||||
Ok(SessionState::Continue(ctx.session))
|
||||
Ok(SessionState::Next(ctx.session))
|
||||
}
|
||||
|
||||
async fn age(mut ctx: Ctx) -> Res {
|
||||
|
@ -117,7 +117,7 @@ async fn age(mut ctx: Ctx) -> Res {
|
|||
Err(_) => reply!(ctx, "Oh, please, enter a number!"),
|
||||
}
|
||||
|
||||
Ok(SessionState::Continue(ctx.session))
|
||||
Ok(SessionState::Next(ctx.session))
|
||||
}
|
||||
|
||||
async fn favourite_music(mut ctx: Ctx) -> Res {
|
||||
|
@ -125,11 +125,11 @@ async fn favourite_music(mut ctx: Ctx) -> Res {
|
|||
Ok(ok) => {
|
||||
ctx.session.favourite_music = Some(ok);
|
||||
reply!(ctx, format!("Fine. {}", ctx.session));
|
||||
Ok(SessionState::Terminate)
|
||||
Ok(SessionState::Exit)
|
||||
}
|
||||
Err(_) => {
|
||||
reply!(ctx, "Oh, please, enter from the keyboard!");
|
||||
Ok(SessionState::Continue(ctx.session))
|
||||
Ok(SessionState::Next(ctx.session))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ async fn handle_message(ctx: Ctx) -> Res {
|
|||
return favourite_music(ctx).await;
|
||||
}
|
||||
|
||||
Ok(SessionState::Terminate)
|
||||
Ok(SessionState::Exit)
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use crate::{
|
||||
dispatching::{
|
||||
error_handlers, update_listeners, update_listeners::UpdateListener,
|
||||
AsyncHandler,
|
||||
AsyncHandler, HandlerCtx,
|
||||
},
|
||||
requests::{Request, ResponseResult},
|
||||
types::{
|
||||
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
|
||||
PreCheckoutQuery, ShippingQuery, UpdateKind,
|
||||
|
@ -13,32 +12,6 @@ use crate::{
|
|||
use futures::StreamExt;
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
/// A dispatcher's handler's context of a bot and an update.
|
||||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](teloxide::dispatching).
|
||||
pub struct HandlerCtx<Upd> {
|
||||
pub bot: Arc<Bot>,
|
||||
pub update: Upd,
|
||||
}
|
||||
|
||||
impl HandlerCtx<Message> {
|
||||
pub fn chat_id(&self) -> i64 {
|
||||
self.update.chat_id()
|
||||
}
|
||||
|
||||
pub async fn reply<T>(self, text: T) -> ResponseResult<()>
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.bot
|
||||
.send_message(self.chat_id(), text)
|
||||
.send()
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
type H<'a, Upd, HandlerE> =
|
||||
Option<Box<dyn AsyncHandler<HandlerCtx<Upd>, Result<(), HandlerE>> + 'a>>;
|
||||
|
||||
|
|
38
src/dispatching/handler_ctx.rs
Normal file
38
src/dispatching/handler_ctx.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use crate::{
|
||||
dispatching::session::GetChatId,
|
||||
requests::{Request, ResponseResult},
|
||||
types::Message,
|
||||
Bot,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A dispatcher's handler's context of a bot and an update.
|
||||
///
|
||||
/// See [the module-level documentation for the design
|
||||
/// overview](teloxide::dispatching).
|
||||
pub struct HandlerCtx<Upd> {
|
||||
pub bot: Arc<Bot>,
|
||||
pub update: Upd,
|
||||
}
|
||||
|
||||
impl<Upd> GetChatId for HandlerCtx<Upd>
|
||||
where
|
||||
Upd: GetChatId,
|
||||
{
|
||||
fn chat_id(&self) -> i64 {
|
||||
self.update.chat_id()
|
||||
}
|
||||
}
|
||||
|
||||
impl HandlerCtx<Message> {
|
||||
pub async fn reply<T>(&self, text: T) -> ResponseResult<()>
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.bot
|
||||
.send_message(self.chat_id(), text)
|
||||
.send()
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
//! Update dispatching.
|
||||
//!
|
||||
//!
|
||||
|
||||
mod async_handler;
|
||||
mod dispatcher;
|
||||
pub mod error_handlers;
|
||||
mod handler_ctx;
|
||||
pub mod session;
|
||||
pub mod update_listeners;
|
||||
|
||||
pub use async_handler::*;
|
||||
pub use dispatcher::*;
|
||||
pub use async_handler::AsyncHandler;
|
||||
pub use dispatcher::Dispatcher;
|
||||
pub use handler_ctx::HandlerCtx;
|
||||
|
|
|
@ -30,136 +30,13 @@
|
|||
// TODO: examples
|
||||
|
||||
mod get_chat_id;
|
||||
mod session_dispatcher;
|
||||
mod session_handler_ctx;
|
||||
mod session_state;
|
||||
mod storage;
|
||||
|
||||
use crate::{
|
||||
dispatching::{AsyncHandler, HandlerCtx},
|
||||
requests::{Request, ResponseResult},
|
||||
types::Message,
|
||||
Bot,
|
||||
};
|
||||
pub use get_chat_id::*;
|
||||
use std::{future::Future, pin::Pin, sync::Arc};
|
||||
pub use storage::*;
|
||||
|
||||
/// A context of a private message handler.
|
||||
pub struct SessionHandlerCtx<Upd, Session> {
|
||||
pub bot: Arc<Bot>,
|
||||
pub update: Upd,
|
||||
pub session: Session,
|
||||
}
|
||||
|
||||
impl<Session> SessionHandlerCtx<Message, Session> {
|
||||
pub fn chat_id(&self) -> i64 {
|
||||
self.update.chat_id()
|
||||
}
|
||||
|
||||
pub async fn reply<T>(&self, text: T) -> ResponseResult<()>
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.bot
|
||||
.send_message(self.chat_id(), text)
|
||||
.send()
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
/// Continue or terminate a user session.
|
||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||
pub enum SessionState<Session> {
|
||||
Continue(Session),
|
||||
Terminate,
|
||||
}
|
||||
|
||||
/// A dispatcher of user sessions.
|
||||
///
|
||||
/// Note that `SessionDispatcher` implements `AsyncHandler`, so you can just put
|
||||
/// an instance of this dispatcher into the [`Dispatcher`]'s methods.
|
||||
///
|
||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
pub struct SessionDispatcher<'a, Session, H> {
|
||||
storage: Box<dyn Storage<Session> + 'a>,
|
||||
handler: H,
|
||||
}
|
||||
|
||||
impl<'a, Session, H> SessionDispatcher<'a, Session, H>
|
||||
where
|
||||
Session: Default + 'a,
|
||||
{
|
||||
/// Creates a dispatcher with the specified `handler` and [`InMemStorage`]
|
||||
/// (a default storage).
|
||||
///
|
||||
/// [`InMemStorage`]: crate::dispatching::session::InMemStorage
|
||||
#[must_use]
|
||||
pub fn new(handler: H) -> Self {
|
||||
Self {
|
||||
storage: Box::new(InMemStorage::default()),
|
||||
handler,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a dispatcher with the specified `handler` and `storage`.
|
||||
#[must_use]
|
||||
pub fn with_storage<Stg>(handler: H, storage: Stg) -> Self
|
||||
where
|
||||
Stg: Storage<Session> + 'a,
|
||||
{
|
||||
Self {
|
||||
storage: Box::new(storage),
|
||||
handler,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Session, H, Upd> AsyncHandler<HandlerCtx<Upd>, Result<(), ()>>
|
||||
for SessionDispatcher<'a, Session, H>
|
||||
where
|
||||
H: AsyncHandler<SessionHandlerCtx<Upd, Session>, SessionState<Session>>,
|
||||
Upd: GetChatId,
|
||||
Session: Default,
|
||||
{
|
||||
/// Dispatches a single `message` from a private chat.
|
||||
fn handle<'b>(
|
||||
&'b self,
|
||||
ctx: HandlerCtx<Upd>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<(), ()>> + 'b>>
|
||||
where
|
||||
Upd: 'b,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let chat_id = ctx.update.chat_id();
|
||||
|
||||
let session = self
|
||||
.storage
|
||||
.remove_session(chat_id)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
if let SessionState::Continue(new_session) = self
|
||||
.handler
|
||||
.handle(SessionHandlerCtx {
|
||||
bot: ctx.bot,
|
||||
update: ctx.update,
|
||||
session,
|
||||
})
|
||||
.await
|
||||
{
|
||||
if self
|
||||
.storage
|
||||
.update_session(chat_id, new_session)
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
panic!(
|
||||
"We previously storage.remove_session() so \
|
||||
storage.update_session() must return None"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
pub use get_chat_id::GetChatId;
|
||||
pub use session_dispatcher::SessionDispatcher;
|
||||
pub use session_handler_ctx::SessionHandlerCtx;
|
||||
pub use session_state::SessionState;
|
||||
pub use storage::{InMemStorage, Storage};
|
||||
|
|
98
src/dispatching/session/session_dispatcher.rs
Normal file
98
src/dispatching/session/session_dispatcher.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
use crate::dispatching::{
|
||||
session::{
|
||||
GetChatId, InMemStorage, SessionHandlerCtx, SessionState, Storage,
|
||||
},
|
||||
AsyncHandler, HandlerCtx,
|
||||
};
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
/// A dispatcher of user sessions.
|
||||
///
|
||||
/// Note that `SessionDispatcher` implements `AsyncHandler`, so you can just put
|
||||
/// an instance of this dispatcher into the [`Dispatcher`]'s methods.
|
||||
///
|
||||
/// [`Dispatcher`]: crate::dispatching::Dispatcher
|
||||
pub struct SessionDispatcher<'a, Session, H> {
|
||||
storage: Box<dyn Storage<Session> + 'a>,
|
||||
handler: H,
|
||||
}
|
||||
|
||||
impl<'a, Session, H> SessionDispatcher<'a, Session, H>
|
||||
where
|
||||
Session: Default + 'a,
|
||||
{
|
||||
/// Creates a dispatcher with the specified `handler` and [`InMemStorage`]
|
||||
/// (a default storage).
|
||||
///
|
||||
/// [`InMemStorage`]: crate::dispatching::session::InMemStorage
|
||||
#[must_use]
|
||||
pub fn new(handler: H) -> Self {
|
||||
Self {
|
||||
storage: Box::new(InMemStorage::default()),
|
||||
handler,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a dispatcher with the specified `handler` and `storage`.
|
||||
#[must_use]
|
||||
pub fn with_storage<Stg>(handler: H, storage: Stg) -> Self
|
||||
where
|
||||
Stg: Storage<Session> + 'a,
|
||||
{
|
||||
Self {
|
||||
storage: Box::new(storage),
|
||||
handler,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Session, H, Upd> AsyncHandler<HandlerCtx<Upd>, Result<(), ()>>
|
||||
for SessionDispatcher<'a, Session, H>
|
||||
where
|
||||
H: AsyncHandler<SessionHandlerCtx<Upd, Session>, SessionState<Session>>,
|
||||
Upd: GetChatId,
|
||||
Session: Default,
|
||||
{
|
||||
/// Dispatches a single `message` from a private chat.
|
||||
fn handle<'b>(
|
||||
&'b self,
|
||||
ctx: HandlerCtx<Upd>,
|
||||
) -> Pin<Box<dyn Future<Output = Result<(), ()>> + 'b>>
|
||||
where
|
||||
Upd: 'b,
|
||||
{
|
||||
Box::pin(async move {
|
||||
let chat_id = ctx.update.chat_id();
|
||||
|
||||
let session = self
|
||||
.storage
|
||||
.remove_session(chat_id)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
if let SessionState::Next(new_session) = self
|
||||
.handler
|
||||
.handle(SessionHandlerCtx {
|
||||
bot: ctx.bot,
|
||||
update: ctx.update,
|
||||
session,
|
||||
})
|
||||
.await
|
||||
{
|
||||
if self
|
||||
.storage
|
||||
.update_session(chat_id, new_session)
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
panic!(
|
||||
"We previously storage.remove_session() so \
|
||||
storage.update_session() must return None"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
38
src/dispatching/session/session_handler_ctx.rs
Normal file
38
src/dispatching/session/session_handler_ctx.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use crate::{
|
||||
dispatching::session::GetChatId,
|
||||
requests::{Request, ResponseResult},
|
||||
types::Message,
|
||||
Bot,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A context of a [`SessionDispatcher`]'s message handler.
|
||||
///
|
||||
/// [`SessionDispatcher`]: crate::dispatching::session::SessionDispatcher
|
||||
pub struct SessionHandlerCtx<Upd, Session> {
|
||||
pub bot: Arc<Bot>,
|
||||
pub update: Upd,
|
||||
pub session: Session,
|
||||
}
|
||||
|
||||
impl<Upd, Session> GetChatId for SessionHandlerCtx<Upd, Session>
|
||||
where
|
||||
Upd: GetChatId,
|
||||
{
|
||||
fn chat_id(&self) -> i64 {
|
||||
self.update.chat_id()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Session> SessionHandlerCtx<Message, Session> {
|
||||
pub async fn reply<T>(&self, text: T) -> ResponseResult<()>
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
self.bot
|
||||
.send_message(self.chat_id(), text)
|
||||
.send()
|
||||
.await
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
6
src/dispatching/session/session_state.rs
Normal file
6
src/dispatching/session/session_state.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
/// Continue or terminate a user session.
|
||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||
pub enum SessionState<Session> {
|
||||
Next(Session),
|
||||
Exit,
|
||||
}
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
pub use crate::{
|
||||
dispatching::{
|
||||
session::{SessionDispatcher, SessionHandlerCtx, SessionState},
|
||||
session::{
|
||||
GetChatId, SessionDispatcher, SessionHandlerCtx, SessionState,
|
||||
},
|
||||
Dispatcher, HandlerCtx,
|
||||
},
|
||||
requests::{Request, ResponseResult},
|
||||
|
|
Loading…
Reference in a new issue