1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
//! The stateful event loop and utilities for it.
//!
//! The stateful event loop makes it easier to write bots that depend on some
//! kind of state. It can be a chatting bot, a quiz bot or any other bot that
//! needs to store data. The stateful event loop also can be used to easily
//! share some data between all handlers, e.g. if you use a database that
//! stores all your data, you can implement an utility struct with methods that
//! simplify access to the database and share it across all your handlers.
//!
//! For example, let's think of a bot with a global counter, and the bot allows
//! increasing and showing it.
//!
//! If we'd have gone with a stateless event loop, we'd start with this:
//!
//! ```
//! let mut bot = tbot::from_env!("BOT_TOKEN").event_loop();
//! ```
//!
//! To go with a stateful bot, we simply call [`stateful_event_loop`] instead of
//! [`event_loop`]:
//!
//! ```
//! # let initial_state = ();
//! let mut bot = tbot::from_env!("BOT_TOKEN")
//!     .stateful_event_loop(initial_state);
//! ```
//!
//! [`stateful_event_loop`]: ../struct.Bot.html#method.stateful_event_loop
//! [`event_loop`]: ../struct.Bot.html#method.event_loop
//!
//! What should `initial_state` be? It can actually be any value (that can be
//! shared across threads). You'd think that, as we only have a counter,
//! we would simply use any integer type. However, `tbot` won't let you mutate
//! the state — instead, you should make use of interior mutability yourself.
//! This design decision was made to avoid mutability if it isn't needed and
//! for users to decide what parts of their state should be mutable — that is
//! to prevent all the state being locked when only a part of it is actually
//! needed to be locked.
//!
//! So what we need is an integer wrapped in an [`RwLock`]:
//!
//! ```
//! # use std::sync::RwLock; /*
//! use tokio::sync::RwLock;
//! # */
//!
//! let mut bot = tbot::from_env!("BOT_TOKEN")
//!     .stateful_event_loop(RwLock::new(0));
//! ```
//!
//! [`RwLock`]: https://docs.rs/tokio/0.2.*/tokio/sync/struct.RwLock.html
//!
//! Now, if we would have gone with the stateless event loop, we'd write this:
//!
//! ```
//! # let mut bot = tbot::Bot::new(String::new()).event_loop();
//! bot.command("increase", |context| async move { /* .. */ });
//! ```
//!
//! Once we opt in to the stateful event loop, we need to write this:
//!
//! ```
//! # let mut bot = tbot::Bot::new(String::new()).stateful_event_loop(());
//! bot.command("increase", |context, state| async move { /* .. */ });
//! ```
//!
//! The state is passed being wrapped in an `Arc`, that is, this handler
//! receives `Arc<RwLock<i32>>` as the second argument. This allows concurrent
//! access to the state. Now you only need to use the state:
//!
//! ```
//! # struct RwLock(std::sync::RwLock<i32>);
//! # impl RwLock {
//! #     async fn write(&self) -> std::sync::RwLockWriteGuard<'_, i32> {
//! #         self.0.write().unwrap()
//! #     }
//! # }
//! # let mut bot = tbot::Bot::new(String::new())
//! #     .stateful_event_loop(RwLock(std::sync::RwLock::new(0)));
//! use tbot::prelude::*;
//!
//! bot.command("increase", |context, state| async move {
//!     *state.write().await += 1;
//!     let call_result =
//!         context.send_message("Increased the counter").call().await;
//!
//!     if let Err(err) = call_result {
//!         dbg!(err);
//!     }
//! });
//! ```
//!
//! `tbot` also provides a few utility state stores for common patterns.
//! You can combine them with other state stores or with your state if needed.

pub mod chats;
mod event_loop;
pub mod messages;

pub use chats::Chats;
pub use event_loop::StatefulEventLoop;
pub use messages::Messages;