From ef2a3b36aee81f7dc2b0d715cf8123e94cb8c671 Mon Sep 17 00:00:00 2001 From: Sergey Levitin Date: Sat, 24 Oct 2020 19:57:51 +0300 Subject: [PATCH] Add a bot example for SqliteStorage --- examples/sqlite_remember_bot/Cargo.toml | 20 +++++++ examples/sqlite_remember_bot/sqlite.db | Bin 0 -> 4096 bytes examples/sqlite_remember_bot/sqlite.db-shm | Bin 0 -> 32768 bytes examples/sqlite_remember_bot/sqlite.db-wal | Bin 0 -> 350232 bytes examples/sqlite_remember_bot/src/main.rs | 50 ++++++++++++++++++ examples/sqlite_remember_bot/src/states.rs | 23 ++++++++ .../sqlite_remember_bot/src/transitions.rs | 35 ++++++++++++ 7 files changed, 128 insertions(+) create mode 100644 examples/sqlite_remember_bot/Cargo.toml create mode 100644 examples/sqlite_remember_bot/sqlite.db create mode 100644 examples/sqlite_remember_bot/sqlite.db-shm create mode 100644 examples/sqlite_remember_bot/sqlite.db-wal create mode 100644 examples/sqlite_remember_bot/src/main.rs create mode 100644 examples/sqlite_remember_bot/src/states.rs create mode 100644 examples/sqlite_remember_bot/src/transitions.rs diff --git a/examples/sqlite_remember_bot/Cargo.toml b/examples/sqlite_remember_bot/Cargo.toml new file mode 100644 index 00000000..b65aa346 --- /dev/null +++ b/examples/sqlite_remember_bot/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "sqlite_remember_bot" +version = "0.1.0" +authors = ["Sergey Levitin "] +edition = "2018" + +[dependencies] +log = "0.4.8" +pretty_env_logger = "0.4.0" +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } + +# You can also choose "cbor-serializer" or built-in JSON serializer +teloxide = { path = "../../", features = ["sqlite-storage", "bincode-serializer", "redis-storage"] } +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" } + +serde = "1.0.104" +futures = "0.3.5" + +thiserror = "1.0.15" +derive_more = "0.99.9" diff --git a/examples/sqlite_remember_bot/sqlite.db b/examples/sqlite_remember_bot/sqlite.db new file mode 100644 index 0000000000000000000000000000000000000000..41ade9e5d196d38ea43f480680e2ead84f89a719 GIT binary patch literal 4096 zcmWFz^vNtqRY=P(%1ta$FlG>7U}9o$P*7lCU|@t|AVoG{WYDv}$qUjhK(-m98b?E5 nGz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0qLtr!nC=3Ar-H8V& literal 0 HcmV?d00001 diff --git a/examples/sqlite_remember_bot/sqlite.db-shm b/examples/sqlite_remember_bot/sqlite.db-shm new file mode 100644 index 0000000000000000000000000000000000000000..7f9864c7eac7ba4b85364c7dacd7572566b8f50a GIT binary patch literal 32768 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 OfB*pk*(h+NFYtei&6nH& literal 0 HcmV?d00001 diff --git a/examples/sqlite_remember_bot/src/main.rs b/examples/sqlite_remember_bot/src/main.rs new file mode 100644 index 00000000..e095150a --- /dev/null +++ b/examples/sqlite_remember_bot/src/main.rs @@ -0,0 +1,50 @@ +#[macro_use] +extern crate derive_more; + +mod states; +mod transitions; + +use states::*; + +use teloxide::{ + dispatching::dialogue::{serializer::JSON, SqliteStorage, Storage}, + prelude::*, +}; +use thiserror::Error; + +type StorageError = as Storage>::Error; + +#[derive(Debug, Error)] +enum Error { + #[error("error from Telegram: {0}")] + TelegramError(#[from] RequestError), + #[error("error from storage: {0}")] + StorageError(#[from] StorageError), +} + +type In = DialogueWithCx; + +async fn handle_message(cx: UpdateWithCx, dialogue: Dialogue) -> TransitionOut { + match cx.update.text_owned() { + None => { + cx.answer_str("Send me a text message.").await?; + next(dialogue) + } + Some(ans) => dialogue.react(cx, ans).await, + } +} + +#[tokio::main] +async fn main() { + let bot = Bot::from_env(); + Dispatcher::new(bot) + .messages_handler(DialogueDispatcher::with_storage( + |DialogueWithCx { cx, dialogue }: In| async move { + let dialogue = dialogue.expect("std::convert::Infallible"); + handle_message(cx, dialogue).await.expect("Something wrong with the bot!") + }, + SqliteStorage::open("sqlite.db", JSON).await.unwrap(), + )) + .dispatch() + .await; +} diff --git a/examples/sqlite_remember_bot/src/states.rs b/examples/sqlite_remember_bot/src/states.rs new file mode 100644 index 00000000..0bb65bd7 --- /dev/null +++ b/examples/sqlite_remember_bot/src/states.rs @@ -0,0 +1,23 @@ +use teloxide_macros::Transition; + +use serde::{Deserialize, Serialize}; + +#[derive(Transition, From, Serialize, Deserialize)] +pub enum Dialogue { + Start(StartState), + HaveNumber(HaveNumberState), +} + +impl Default for Dialogue { + fn default() -> Self { + Self::Start(StartState) + } +} + +#[derive(Serialize, Deserialize)] +pub struct StartState; + +#[derive(Serialize, Deserialize)] +pub struct HaveNumberState { + pub number: i32, +} diff --git a/examples/sqlite_remember_bot/src/transitions.rs b/examples/sqlite_remember_bot/src/transitions.rs new file mode 100644 index 00000000..dcc78db9 --- /dev/null +++ b/examples/sqlite_remember_bot/src/transitions.rs @@ -0,0 +1,35 @@ +use teloxide::prelude::*; +use teloxide_macros::teloxide; + +use super::states::*; + +#[teloxide(subtransition)] +async fn start(state: StartState, cx: TransitionIn, ans: String) -> TransitionOut { + if let Ok(number) = ans.parse() { + cx.answer_str(format!("Remembered number {}. Now use /get or /reset", number)).await?; + next(HaveNumberState { number }) + } else { + cx.answer_str("Please, send me a number").await?; + next(state) + } +} + +#[teloxide(subtransition)] +async fn have_number( + state: HaveNumberState, + cx: TransitionIn, + ans: String, +) -> TransitionOut { + let num = state.number; + + if ans.starts_with("/get") { + cx.answer_str(format!("Here is your number: {}", num)).await?; + next(state) + } else if ans.starts_with("/reset") { + cx.answer_str("Resetted number").await?; + next(StartState) + } else { + cx.answer_str("Please, send /get or /reset").await?; + next(state) + } +}