Add a bot example for SqliteStorage

This commit is contained in:
Sergey Levitin 2020-10-24 19:57:51 +03:00
parent 5e1fe064cd
commit ef2a3b36ae
7 changed files with 128 additions and 0 deletions

View file

@ -0,0 +1,20 @@
[package]
name = "sqlite_remember_bot"
version = "0.1.0"
authors = ["Sergey Levitin <selevit@gmail.com>"]
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"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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 = <SqliteStorage<JSON> as Storage<Dialogue>>::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<Message, Dialogue, StorageError>;
async fn handle_message(cx: UpdateWithCx<Message>, dialogue: Dialogue) -> TransitionOut<Dialogue> {
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;
}

View file

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

View file

@ -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<Dialogue> {
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<Dialogue> {
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)
}
}