mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 14:35:36 +01:00
Simplify composite_state
example
This commit is contained in:
parent
294f3f5447
commit
de34970e70
1 changed files with 48 additions and 72 deletions
|
@ -40,7 +40,7 @@
|
||||||
use teloxide::{
|
use teloxide::{
|
||||||
dispatching::{dialogue::InMemStorage, MessageFilterExt},
|
dispatching::{dialogue::InMemStorage, MessageFilterExt},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
types::{ChatId, Message},
|
types::Message,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Bot = teloxide::Bot;
|
type Bot = teloxide::Bot;
|
||||||
|
@ -68,17 +68,11 @@ enum GlobalState {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum UserSetup {
|
enum UserSetup {
|
||||||
ReceiveFullName,
|
ReceiveFullName,
|
||||||
ReceiveAge { full_name: String },
|
ReceiveAge { full_name: FullName },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper struct to store only required information to answer messages and
|
#[derive(Clone, derive_more::Display)]
|
||||||
/// reduce the size of the stack frames for handler functions
|
struct FullName(pub String);
|
||||||
#[derive(Clone)]
|
|
||||||
struct IdsBundle {
|
|
||||||
chat_id: ChatId,
|
|
||||||
// Can be used to reply to messages or edit messages
|
|
||||||
// message_id: MessageId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
|
@ -95,50 +89,38 @@ async fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schema() -> UpdateHandler {
|
fn schema() -> UpdateHandler {
|
||||||
Update::filter_message()
|
Update::filter_message().branch(
|
||||||
/*
|
Message::filter_text()
|
||||||
Currently the size of the `Message` struct (for TBA 6.9) is 1936 bytes, it's insane to copy it entirely in every handler's stack.
|
.enter_dialogue::<Message, Storage, GlobalState>()
|
||||||
So, here I introduce the `IdsBundle` which is 8 bytes in size, because all we need is a `chat_id`.
|
.branch(
|
||||||
The similar thing can be applied to the `CallbackQuery` struct which is
|
teloxide::filter_command::<Command, _>()
|
||||||
even bigger..
|
.branch(dptree::case![Command::Start].endpoint(ask_full_name)),
|
||||||
Take a look at this issue: https://github.com/teloxide/teloxide/issues/1118, maybe there will be
|
)
|
||||||
more appropriate approach: `Arc<Message>` or similar.
|
.branch(dptree::case![GlobalState::Idle].endpoint(handle_configured_user_message))
|
||||||
*/
|
.branch(
|
||||||
.map(|msg: Message| IdsBundle { chat_id: msg.chat.id })
|
// Its essential not to use
|
||||||
.branch(
|
// `dptree::case![GlobalState::UserSetup(UserSetup::ReceiveFullName)]` directly,
|
||||||
Message::filter_text()
|
// this won't work. Each nested enum requires it's own `branch`
|
||||||
.enter_dialogue::<Message, Storage, GlobalState>()
|
// scope. Actually, each `dptree::case![..]` introduces the inner
|
||||||
.branch(
|
// enum value to the `DependencyMap`, so there is an option
|
||||||
teloxide::filter_command::<Command, _>()
|
// to branch on the inner values freely.
|
||||||
.branch(dptree::case![Command::Start].endpoint(ask_full_name)),
|
dptree::case![GlobalState::UserSetup(_state)]
|
||||||
)
|
.branch(
|
||||||
.branch(dptree::case![GlobalState::Idle].endpoint(handle_configured_user_message))
|
dptree::case![UserSetup::ReceiveFullName]
|
||||||
.branch(
|
.map(|text: String| FullName(text))
|
||||||
/*
|
.endpoint(ask_age),
|
||||||
Its essential not to use `dptree::case![GlobalState::UserSetup(UserSetup::ReceiveFullName)]` directly, this won't work.
|
)
|
||||||
|
.branch(
|
||||||
Each nested enum requires it's own `branch` scope.
|
dptree::case![UserSetup::ReceiveAge { full_name }]
|
||||||
Actually, each `dptree::case![..]` introduces the inner enum value to the `DependencyMap`, so there is an option
|
.endpoint(finish_user_setup),
|
||||||
to branch on the inner values freely.
|
),
|
||||||
*/
|
)
|
||||||
dptree::case![GlobalState::UserSetup(_state)]
|
.branch(dptree::endpoint(handle_unconfigured_user_message)),
|
||||||
.branch(dptree::case![UserSetup::ReceiveFullName].endpoint(ask_age))
|
)
|
||||||
.branch(
|
|
||||||
dptree::case![UserSetup::ReceiveAge { full_name }]
|
|
||||||
.endpoint(finish_user_setup),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.branch(dptree::endpoint(handle_unconfigured_user_message)),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn ask_full_name(
|
async fn ask_full_name(bot: Bot, dialogue: Dialogue, message: Message) -> HandlerResult {
|
||||||
bot: Bot,
|
bot.send_message(message.chat.id, "Let's start! What's your full name?").await?;
|
||||||
dialogue: Dialogue,
|
|
||||||
// For the sake of interest, take a look at the size of the `Message` struct
|
|
||||||
IdsBundle { chat_id }: IdsBundle,
|
|
||||||
) -> HandlerResult {
|
|
||||||
bot.send_message(chat_id, "Let's start! What's your full name?").await?;
|
|
||||||
dialogue.update(GlobalState::UserSetup(UserSetup::ReceiveFullName)).await?;
|
dialogue.update(GlobalState::UserSetup(UserSetup::ReceiveFullName)).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -146,21 +128,21 @@ async fn ask_full_name(
|
||||||
async fn ask_age(
|
async fn ask_age(
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
dialogue: Dialogue,
|
dialogue: Dialogue,
|
||||||
IdsBundle { chat_id }: IdsBundle,
|
message: Message,
|
||||||
full_name: String,
|
full_name: FullName,
|
||||||
) -> HandlerResult {
|
) -> HandlerResult {
|
||||||
bot.send_message(chat_id, format!("Hi, {full_name}! How old are you?")).await?;
|
bot.send_message(message.chat.id, format!("Hi, {full_name}! How old are you?")).await?;
|
||||||
dialogue.update(GlobalState::UserSetup(UserSetup::ReceiveAge { full_name })).await?;
|
dialogue.update(GlobalState::UserSetup(UserSetup::ReceiveAge { full_name })).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn finish_user_setup(bot: Bot, dialogue: Dialogue, message: Message) -> HandlerResult {
|
async fn finish_user_setup(
|
||||||
/*
|
bot: Bot,
|
||||||
We did `Message::filter_text`, so it's safe to assume that this message contains text.
|
dialogue: Dialogue,
|
||||||
Unfortunately, we can't get incoming text as the handler parameter, because it's
|
message: Message,
|
||||||
shadowed by the `full_name` value from the `UserSetup::ReceiveAge {full_name}` state
|
age: String,
|
||||||
*/
|
) -> HandlerResult {
|
||||||
let _age = match message.text().unwrap().parse::<u8>() {
|
let _age = match age.parse::<u8>() {
|
||||||
Ok(age) => age,
|
Ok(age) => age,
|
||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
bot.send_message(message.chat.id, "Please, enter your age").await?;
|
bot.send_message(message.chat.id, "Please, enter your age").await?;
|
||||||
|
@ -173,18 +155,12 @@ async fn finish_user_setup(bot: Bot, dialogue: Dialogue, message: Message) -> Ha
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_configured_user_message(
|
async fn handle_configured_user_message(bot: Bot, message: Message) -> HandlerResult {
|
||||||
bot: Bot,
|
bot.send_message(message.chat.id, "Hi, configured user!").await?;
|
||||||
IdsBundle { chat_id }: IdsBundle,
|
|
||||||
) -> HandlerResult {
|
|
||||||
bot.send_message(chat_id, "Hi, configured user!").await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_unconfigured_user_message(
|
async fn handle_unconfigured_user_message(bot: Bot, message: Message) -> HandlerResult {
|
||||||
bot: Bot,
|
bot.send_message(message.chat.id, "Use /start to setup your account").await?;
|
||||||
IdsBundle { chat_id }: IdsBundle,
|
|
||||||
) -> HandlerResult {
|
|
||||||
bot.send_message(chat_id, "Use /start to setup your account").await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue