Expand description
A storage of state per chat.
The Chats
storage can be used to store some state for each chat
separately. An example of it is a questionary bot when the bot collects
some data from the user step-by-step:
enum Questionary {
AskName,
AskIfPraisedTheBorrowChecker {
name: String,
},
Done {
name: String,
has_praised_the_borrow_checker: bool,
},
}
Chats
stores its states in a hash map where the key is the chat ID and
the value is the state for the chat. As explained in docs for state
,
if you want to mutate state, you need to manually wrap it in a lock,
and this applies to Chats
as well. Let’s wrap our state in a Mutex
:
use tbot::state::Chats;
use tokio::sync::Mutex;
let mut bot = tbot::from_env!("BOT_TOKEN")
.stateful_event_loop(Mutex::new(Chats::new()));
Let’s start our questionary once the user starts the bot:
use tbot::prelude::*;
bot.start(|context, state| async move {
state.lock().await.insert(&*context, Questionary::AskName);
let call_result =
context.send_message("Hello! What's your name?").call().await;
if let Err(err) = call_result {
dbg!(err);
}
});
You can see that the insert
method can figure out the chat ID from
the context, but there’s still insert_by_id
if you need it. In fact,
Chats
’s API is very similar to the API of std
’s HashMap
,
but instead of the key you need to provide the context or use the equivalent
method with the _by_id
postfix.
If you need to, you can combine Chats
with other state stores like this:
use tbot::state::Chats;
use tokio::sync::RwLock;
#[derive(Default)]
struct State {
chats: RwLock<Chats<String>>,
some_other_state: SomeOtherState,
}
let mut bot = tbot::from_env!("BOT_TOKEN")
.stateful_event_loop(State::default());