diff --git a/examples/dialogue_bot/src/main.rs b/examples/dialogue_bot/src/main.rs index e0447004..f9b9683d 100644 --- a/examples/dialogue_bot/src/main.rs +++ b/examples/dialogue_bot/src/main.rs @@ -45,9 +45,9 @@ async fn run() { Dispatcher::new(bot) .messages_handler(DialogueDispatcher::new( - |cx: DialogueWithCx| async move { + |input: TransitionIn| async move { // Unwrap without panic because of std::convert::Infallible. - dispatch(cx.cx, cx.dialogue.unwrap()) + dispatch(input.cx, input.dialogue.unwrap()) .await .expect("Something wrong with the bot!") }, diff --git a/examples/redis_remember_bot/Cargo.toml b/examples/redis_remember_bot/Cargo.toml index a8f6bd3c..6a91b292 100644 --- a/examples/redis_remember_bot/Cargo.toml +++ b/examples/redis_remember_bot/Cargo.toml @@ -6,8 +6,11 @@ edition = "2018" [dependencies] tokio = "0.2.9" -smart-default = "0.6.0" + # You can also choose "cbor-serializer" or built-in JSON serializer teloxide = { path = "../../", features = ["redis-storage", "bincode-serializer"] } serde = "1.0.104" + thiserror = "1.0.15" +smart-default = "0.6.0" +derive_more = "0.99.9" \ No newline at end of file diff --git a/examples/redis_remember_bot/src/main.rs b/examples/redis_remember_bot/src/main.rs index 0de999e8..2eb8aa03 100644 --- a/examples/redis_remember_bot/src/main.rs +++ b/examples/redis_remember_bot/src/main.rs @@ -1,5 +1,14 @@ -use serde::{Deserialize, Serialize}; -use smart_default::SmartDefault; +#[macro_use] +extern crate smart_default; +#[macro_use] +extern crate derive_more; + +mod states; +mod transitions; + +use states::*; +use transitions::*; + use std::sync::Arc; use teloxide::{ dispatching::dialogue::{serializer::Bincode, RedisStorage, Storage}, @@ -7,13 +16,6 @@ use teloxide::{ }; use thiserror::Error; -#[derive(SmartDefault, Serialize, Deserialize)] -enum Dialogue { - #[default] - Start, - HaveNumber(i32), -} - type StorageError = as Storage>::Error; #[derive(Debug, Error)] @@ -24,70 +26,20 @@ enum Error { StorageError(#[from] StorageError), } -type Cx = DialogueDispatcherHandlerCx; +type In = TransitionIn; -type Res = Result, Error>; +async fn handle_message(input: In) -> Out { + let (cx, dialogue) = input.unpack(); -async fn handle_message(cx: Cx) -> Res { - let DialogueDispatcherHandlerCx { bot, update, dialogue } = cx; - let text = match update.text() { + let text = match cx.update.text_owned() { Some(text) => text, None => { - bot.send_message( - update.chat_id(), - "Please, send me a text message", - ) - .send() - .await?; - return next(Dialogue::Start); + cx.answer_str("Please, send me a text message").await?; + return next(StartState); } }; - match dialogue? { - Dialogue::Start => { - if let Ok(number) = text.parse() { - bot.send_message( - update.chat_id(), - format!( - "Remembered number {}. Now use /get or /reset", - number - ), - ) - .send() - .await?; - next(Dialogue::HaveNumber(number)) - } else { - bot.send_message(update.chat_id(), "Please, send me a number") - .send() - .await?; - next(Dialogue::Start) - } - } - Dialogue::HaveNumber(num) => { - if text.starts_with("/get") { - bot.send_message( - update.chat_id(), - format!("Here is your number: {}", num), - ) - .send() - .await?; - next(Dialogue::HaveNumber(num)) - } else if text.starts_with("/reset") { - bot.send_message(update.chat_id(), format!("Resetted number")) - .send() - .await?; - next(Dialogue::Start) - } else { - bot.send_message( - update.chat_id(), - "Please, send /get or /reset", - ) - .send() - .await?; - next(Dialogue::HaveNumber(num)) - } - } - } + dispatch(cx, dialogue, &text).await } #[tokio::main] diff --git a/examples/redis_remember_bot/src/states.rs b/examples/redis_remember_bot/src/states.rs index e69de29b..142e823a 100644 --- a/examples/redis_remember_bot/src/states.rs +++ b/examples/redis_remember_bot/src/states.rs @@ -0,0 +1,23 @@ +use teloxide::prelude::*; + +use serde::{Deserialize, Serialize}; + +#[derive(Default, Serialize, Deserialize)] +pub struct StartState; + +#[derive(Serialize, Deserialize)] +pub struct HaveNumberState { + rest: StartState, + pub number: i32, +} + +up!( + StartState + [number: i32] -> HaveNumberState, +); + +#[derive(SmartDefault, From, Serialize, Deserialize)] +pub enum Dialogue { + #[default] + Start(StartState), + HaveNumber(HaveNumberState), +} diff --git a/examples/redis_remember_bot/src/transitions.rs b/examples/redis_remember_bot/src/transitions.rs index e69de29b..a30c906a 100644 --- a/examples/redis_remember_bot/src/transitions.rs +++ b/examples/redis_remember_bot/src/transitions.rs @@ -0,0 +1,42 @@ +use teloxide::prelude::*; + +use super::states::*; + +pub type Cx = UpdateWithCx; +pub type Out = TransitionOut; + +async fn start(cx: Cx, state: StartState, text: &str) -> Out { + if let Ok(number) = text.parse() { + cx.answer_str(format!( + "Remembered number {}. Now use /get or /reset", + number + )) + .await?; + next(state.up(number)) + } else { + cx.answer_str("Please, send me a number").await?; + next(state) + } +} + +async fn have_number(cx: Cx, state: HaveNumberState, text: &str) -> Out { + let num = state.number; + + if text.starts_with("/get") { + cx.answer_str(format!("Here is your number: {}", num)).await?; + next(state) + } else if text.starts_with("/reset") { + cx.answer_str(format!("Resetted number")).await?; + next(StartState) + } else { + cx.answer_str("Please, send /get or /reset").await?; + next(state) + } +} + +pub async fn dispatch(cx: Cx, dialogue: Dialogue, text: &str) -> Out { + match dialogue { + Dialogue::Start(state) => start(cx, state, text).await, + Dialogue::HaveNumber(state) => have_number(cx, state, text).await, + } +}