Update redis_remember_bot

This commit is contained in:
Temirkhan Myrzamadi 2020-07-01 19:25:10 +06:00
parent fb6156a3b9
commit 03ab247262
5 changed files with 89 additions and 69 deletions

View file

@ -45,9 +45,9 @@ async fn run() {
Dispatcher::new(bot)
.messages_handler(DialogueDispatcher::new(
|cx: DialogueWithCx<Message, Dialogue, Infallible>| async move {
|input: TransitionIn<Dialogue, Infallible>| 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!")
},

View file

@ -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"

View file

@ -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 = <RedisStorage<Bincode> as Storage<Dialogue>>::Error;
#[derive(Debug, Error)]
@ -24,70 +26,20 @@ enum Error {
StorageError(#[from] StorageError),
}
type Cx<State> = DialogueDispatcherHandlerCx<Message, State, StorageError>;
type In = TransitionIn<Dialogue, StorageError>;
type Res = Result<DialogueStage<Dialogue>, Error>;
async fn handle_message(input: In) -> Out {
let (cx, dialogue) = input.unpack();
async fn handle_message(cx: Cx<Dialogue>) -> 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]

View file

@ -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),
}

View file

@ -0,0 +1,42 @@
use teloxide::prelude::*;
use super::states::*;
pub type Cx = UpdateWithCx<Message>;
pub type Out = TransitionOut<Dialogue>;
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,
}
}