mirror of
https://github.com/teloxide/teloxide.git
synced 2025-01-03 09:49:07 +01:00
Update explanation of dialogues (README.md)
This commit is contained in:
parent
53625c9441
commit
ab69b334a1
1 changed files with 50 additions and 49 deletions
99
README.md
99
README.md
|
@ -187,20 +187,18 @@ async fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
<div align="center">
|
||||
<kbd>
|
||||
<img src=https://github.com/teloxide/teloxide/raw/master/media/SIMPLE_COMMANDS_BOT.png width="500"/>
|
||||
</kbd>
|
||||
<br/><br/>
|
||||
</div>
|
||||
|
||||
### Dialogues
|
||||
Wanna see more? This is how dialogues management is made in teloxide.
|
||||
A dialogue is described by an enumeration, where each variant is one of possible dialogue's states. There are also _transition functions_, which turn a dialogue from one state to another, thereby forming an [FSM].
|
||||
|
||||
[FSM]: https://en.wikipedia.org/wiki/Finite-state_machine
|
||||
|
||||
States and transition functions are placed into separated modules. For example:
|
||||
|
||||
([dialogue_bot/src/states.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/states.rs))
|
||||
```rust
|
||||
// Imports are omitted...
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct StartState;
|
||||
|
||||
pub struct ReceiveFullNameState {
|
||||
|
@ -234,77 +232,83 @@ up!(
|
|||
ReceiveFavouriteMusicState + [favourite_music: FavouriteMusic] -> ExitState,
|
||||
);
|
||||
|
||||
pub type Dialogue = Coprod!(
|
||||
StartState,
|
||||
ReceiveFullNameState,
|
||||
ReceiveAgeState,
|
||||
ReceiveFavouriteMusicState,
|
||||
);
|
||||
#[derive(SmartDefault, From)]
|
||||
pub enum Dialogue {
|
||||
#[default]
|
||||
Start(StartState),
|
||||
ReceiveFullName(ReceiveFullNameState),
|
||||
ReceiveAge(ReceiveAgeState),
|
||||
ReceiveFavouriteMusic(ReceiveFavouriteMusicState),
|
||||
}
|
||||
```
|
||||
|
||||
The [`wrap_dialogue!`](https://docs.rs/teloxide/latest/teloxide/macro.wrap_dialogue.html) macro generates a new-type of `Dialogue` with a default implementation.
|
||||
The handy `up!` macro automatically generates functions that complete one state to another by appending a field.
|
||||
|
||||
([dialogue_bot/src/transitions.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/transitions.rs))
|
||||
```rust
|
||||
// Imports are omitted...
|
||||
|
||||
pub type In<State> = TransitionIn<State, std::convert::Infallible>;
|
||||
pub type Out = TransitionOut<Wrapper>;
|
||||
|
||||
pub async fn start(cx: In<StartState>) -> Out {
|
||||
let (cx, dialogue) = cx.unpack();
|
||||
pub type Cx = UpdateWithCx<Message>;
|
||||
pub type Out = TransitionOut<Dialogue>;
|
||||
|
||||
async fn start(cx: Cx, state: StartState) -> Out {
|
||||
cx.answer_str("Let's start! First, what's your full name?").await?;
|
||||
next(dialogue.up())
|
||||
next(state.up())
|
||||
}
|
||||
|
||||
pub async fn receive_full_name(cx: In<ReceiveFullNameState>) -> Out {
|
||||
let (cx, dialogue) = cx.unpack();
|
||||
|
||||
async fn receive_full_name(cx: Cx, state: ReceiveFullNameState) -> Out {
|
||||
match cx.update.text_owned() {
|
||||
Some(full_name) => {
|
||||
cx.answer_str("What a wonderful name! Your age?").await?;
|
||||
next(dialogue.up(full_name))
|
||||
next(state.up(full_name))
|
||||
}
|
||||
_ => {
|
||||
cx.answer_str("Please, enter a text message!").await?;
|
||||
next(dialogue)
|
||||
next(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn receive_age(cx: In<ReceiveAgeState>) -> Out {
|
||||
let (cx, dialogue) = cx.unpack();
|
||||
|
||||
async fn receive_age(cx: Cx, state: ReceiveAgeState) -> Out {
|
||||
match cx.update.text().map(str::parse) {
|
||||
Some(Ok(age)) => {
|
||||
cx.answer("Good. Now choose your favourite music:")
|
||||
.reply_markup(FavouriteMusic::markup())
|
||||
.send()
|
||||
.await?;
|
||||
next(dialogue.up(age))
|
||||
next(state.up(age))
|
||||
}
|
||||
_ => {
|
||||
cx.answer_str("Please, enter a number!").await?;
|
||||
next(dialogue)
|
||||
next(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn receive_favourite_music(
|
||||
cx: In<ReceiveFavouriteMusicState>,
|
||||
async fn receive_favourite_music(
|
||||
cx: Cx,
|
||||
state: ReceiveFavouriteMusicState,
|
||||
) -> Out {
|
||||
let (cx, dialogue) = cx.unpack();
|
||||
|
||||
match cx.update.text().map(str::parse) {
|
||||
Some(Ok(favourite_music)) => {
|
||||
cx.answer_str(format!("Fine. {}", dialogue.up(favourite_music)))
|
||||
cx.answer_str(format!("Fine. {}", state.up(favourite_music)))
|
||||
.await?;
|
||||
exit()
|
||||
}
|
||||
_ => {
|
||||
cx.answer_str("Please, enter from the keyboard!").await?;
|
||||
next(dialogue)
|
||||
next(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn dispatch(cx: Cx, dialogue: Dialogue) -> Out {
|
||||
match dialogue {
|
||||
Dialogue::Start(state) => start(cx, state).await,
|
||||
Dialogue::ReceiveFullName(state) => receive_full_name(cx, state).await,
|
||||
Dialogue::ReceiveAge(state) => receive_age(cx, state).await,
|
||||
Dialogue::ReceiveFavouriteMusic(state) => {
|
||||
receive_favourite_music(cx, state).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -335,6 +339,7 @@ impl FavouriteMusic {
|
|||
```
|
||||
|
||||
|
||||
|
||||
([dialogue_bot/src/main.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/main.rs))
|
||||
```rust
|
||||
// Imports are omitted...
|
||||
|
@ -347,18 +352,14 @@ async fn main() {
|
|||
let bot = Bot::from_env();
|
||||
|
||||
Dispatcher::new(bot)
|
||||
.messages_handler(DialogueDispatcher::new(|cx| async move {
|
||||
let DialogueWithCx { cx, dialogue } = cx;
|
||||
|
||||
// Unwrap without panic because of std::convert::Infallible.
|
||||
let Wrapper(dialogue) = dialogue.unwrap();
|
||||
|
||||
dispatch!(
|
||||
[cx, dialogue] ->
|
||||
[start, receive_full_name, receive_age, receive_favourite_music]
|
||||
)
|
||||
.expect("Something wrong with the bot!")
|
||||
}, || Dialogue::inject(StartState)))
|
||||
.messages_handler(DialogueDispatcher::new(
|
||||
|input: TransitionIn<Dialogue, Infallible>| async move {
|
||||
// Unwrap without panic because of std::convert::Infallible.
|
||||
dispatch(input.cx, input.dialogue.unwrap())
|
||||
.await
|
||||
.expect("Something wrong with the bot!")
|
||||
},
|
||||
))
|
||||
.dispatch()
|
||||
.await;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue