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 00000000..41ade9e5 Binary files /dev/null and b/examples/sqlite_remember_bot/sqlite.db differ diff --git a/examples/sqlite_remember_bot/sqlite.db-shm b/examples/sqlite_remember_bot/sqlite.db-shm new file mode 100644 index 00000000..7f9864c7 Binary files /dev/null and b/examples/sqlite_remember_bot/sqlite.db-shm differ diff --git a/examples/sqlite_remember_bot/sqlite.db-wal b/examples/sqlite_remember_bot/sqlite.db-wal new file mode 100644 index 00000000..c3cc68bf Binary files /dev/null and b/examples/sqlite_remember_bot/sqlite.db-wal differ 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) + } +}