Add dialogue::{next, exit}

This commit is contained in:
Temirkhan Myrzamadi 2020-02-11 02:54:08 +06:00
parent 809aaef9b1
commit bde4d09e5d
8 changed files with 40 additions and 26 deletions

View file

@ -11,6 +11,7 @@ pretty_env_logger = "0.3.1"
log = "0.4.8" log = "0.4.8"
tokio = "0.2.9" tokio = "0.2.9"
strum = "0.17.1" strum = "0.17.1"
smart-default = "0.6.0"
strum_macros = "0.17.1" strum_macros = "0.17.1"
teloxide = { path = "../../" } teloxide = { path = "../../" }

View file

@ -1,5 +1,7 @@
#[macro_use] #[macro_use]
extern crate strum_macros; extern crate strum_macros;
#[macro_use]
extern crate smart_default;
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use teloxide::{ use teloxide::{
@ -57,19 +59,15 @@ impl Display for User {
// [States of a dialogue] // [States of a dialogue]
// ============================================================================ // ============================================================================
#[derive(SmartDefault)]
enum State { enum State {
#[default]
Start, Start,
FullName, FullName,
Age, Age,
FavouriteMusic, FavouriteMusic,
} }
impl Default for State {
fn default() -> Self {
Self::Start
}
}
// ============================================================================ // ============================================================================
// [Control a dialogue] // [Control a dialogue]
// ============================================================================ // ============================================================================
@ -90,14 +88,14 @@ async fn start(mut ctx: Ctx) -> Res {
ctx.reply("Let's start! First, what's your full name?") ctx.reply("Let's start! First, what's your full name?")
.await?; .await?;
ctx.dialogue.state = State::FullName; ctx.dialogue.state = State::FullName;
Ok(DialogueStage::Next(ctx.dialogue)) next(ctx.dialogue)
} }
async fn full_name(mut ctx: Ctx) -> Res { async fn full_name(mut ctx: Ctx) -> Res {
ctx.reply("What a wonderful name! Your age?").await?; ctx.reply("What a wonderful name! Your age?").await?;
ctx.dialogue.data.full_name = Some(ctx.update.text().unwrap().to_owned()); ctx.dialogue.data.full_name = Some(ctx.update.text().unwrap().to_owned());
ctx.dialogue.state = State::Age; ctx.dialogue.state = State::Age;
Ok(DialogueStage::Next(ctx.dialogue)) next(ctx.dialogue)
} }
async fn age(mut ctx: Ctx) -> Res { async fn age(mut ctx: Ctx) -> Res {
@ -110,7 +108,7 @@ async fn age(mut ctx: Ctx) -> Res {
Err(_) => ctx.reply("Oh, please, enter a number!").await?, Err(_) => ctx.reply("Oh, please, enter a number!").await?,
} }
Ok(DialogueStage::Next(ctx.dialogue)) next(ctx.dialogue)
} }
async fn favourite_music(mut ctx: Ctx) -> Res { async fn favourite_music(mut ctx: Ctx) -> Res {
@ -118,11 +116,11 @@ async fn favourite_music(mut ctx: Ctx) -> Res {
Ok(ok) => { Ok(ok) => {
ctx.dialogue.data.favourite_music = Some(ok); ctx.dialogue.data.favourite_music = Some(ok);
ctx.reply(format!("Fine. {}", ctx.dialogue.data)).await?; ctx.reply(format!("Fine. {}", ctx.dialogue.data)).await?;
Ok(DialogueStage::Exit) exit()
} }
Err(_) => { Err(_) => {
ctx.reply("Oh, please, enter from the keyboard!").await?; ctx.reply("Oh, please, enter from the keyboard!").await?;
Ok(DialogueStage::Next(ctx.dialogue)) next(ctx.dialogue)
} }
} }
} }
@ -147,7 +145,7 @@ async fn main() {
log::info!("Starting the simple_dialogue bot!"); log::info!("Starting the simple_dialogue bot!");
Dispatcher::new(Bot::new("YourAwesomeToken")) Dispatcher::new(Bot::new("YourAwesomeToken"))
.message_handler(DialogueDispatcher::new(|ctx| async move { .message_handler(&DialogueDispatcher::new(|ctx| async move {
handle_message(ctx) handle_message(ctx)
.await .await
.expect("Something wrong with the bot!") .expect("Something wrong with the bot!")

View file

@ -0,0 +1,20 @@
use crate::dispatching::dialogue::Dialogue;
/// Continue or terminate a dialogue.
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub enum DialogueStage<State, T> {
Next(Dialogue<State, T>),
Exit,
}
/// A shortcut for `Ok(DialogueStage::Next(dialogue))`.
pub fn next<E, State, T>(
dialogue: Dialogue<State, T>,
) -> Result<DialogueStage<State, T>, E> {
Ok(DialogueStage::Next(dialogue))
}
/// A shortcut for `Ok(DialogueStage::Exit)`.
pub fn exit<E, State, T>() -> Result<DialogueStage<State, T>, E> {
Ok(DialogueStage::Exit)
}

View file

@ -1,8 +0,0 @@
use crate::dispatching::dialogue::Dialogue;
/// Continue or terminate a dialogue.
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub enum DialogueStage<State, T> {
Next(Dialogue<State, T>),
Exit,
}

View file

@ -37,13 +37,13 @@
mod dialogue; mod dialogue;
mod dialogue_dispatcher; mod dialogue_dispatcher;
mod dialogue_handler_ctx; mod dialogue_handler_ctx;
mod dialogue_state; mod dialogue_stage;
mod get_chat_id; mod get_chat_id;
mod storage; mod storage;
pub use dialogue::Dialogue; pub use dialogue::Dialogue;
pub use dialogue_dispatcher::DialogueDispatcher; pub use dialogue_dispatcher::DialogueDispatcher;
pub use dialogue_handler_ctx::DialogueHandlerCtx; pub use dialogue_handler_ctx::DialogueHandlerCtx;
pub use dialogue_state::DialogueStage; pub use dialogue_stage::{exit, next, DialogueStage};
pub use get_chat_id::GetChatId; pub use get_chat_id::GetChatId;
pub use storage::{InMemStorage, Storage}; pub use storage::{InMemStorage, Storage};

View file

@ -8,7 +8,7 @@ use crate::{
CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll, CallbackQuery, ChosenInlineResult, InlineQuery, Message, Poll,
PollAnswer, PreCheckoutQuery, ShippingQuery, Update, UpdateKind, PollAnswer, PreCheckoutQuery, ShippingQuery, Update, UpdateKind,
}, },
Bot, Bot, RequestError,
}; };
use futures::{stream, StreamExt}; use futures::{stream, StreamExt};
use std::{fmt::Debug, future::Future, sync::Arc}; use std::{fmt::Debug, future::Future, sync::Arc};
@ -26,7 +26,9 @@ type Handlers<'a, Upd, HandlerE> = Vec<
/// ///
/// See [the module-level documentation for the design /// See [the module-level documentation for the design
/// overview](crate::dispatching). /// overview](crate::dispatching).
pub struct Dispatcher<'a, HandlerE> { // HandlerE=RequestError doesn't work now, because of very poor type inference.
// See https://github.com/rust-lang/rust/issues/27336 for more details.
pub struct Dispatcher<'a, HandlerE = RequestError> {
bot: Arc<Bot>, bot: Arc<Bot>,
handlers_error_handler: Box<dyn ErrorHandler<HandlerE> + 'a>, handlers_error_handler: Box<dyn ErrorHandler<HandlerE> + 'a>,

View file

@ -25,7 +25,7 @@
//! //!
//! // Setup logging here... //! // Setup logging here...
//! //!
//! Dispatcher::new(Bot::new("MyAwesomeToken")) //! Dispatcher::<RequestError>::new(Bot::new("MyAwesomeToken"))
//! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move { //! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
//! ctx.answer("pong").send().await?; //! ctx.answer("pong").send().await?;
//! Ok(()) //! Ok(())

View file

@ -3,7 +3,8 @@
pub use crate::{ pub use crate::{
dispatching::{ dispatching::{
dialogue::{ dialogue::{
DialogueDispatcher, DialogueHandlerCtx, DialogueStage, GetChatId, exit, next, DialogueDispatcher, DialogueHandlerCtx, DialogueStage,
GetChatId,
}, },
Dispatcher, DispatcherHandlerCtx, Dispatcher, DispatcherHandlerCtx,
}, },