From 6c0f1b9fc450477005428c7097676adcb892fd56 Mon Sep 17 00:00:00 2001 From: p0lunin Date: Tue, 28 Dec 2021 18:24:56 +0200 Subject: [PATCH] Added handler_factory.rs --- examples/dialogue_bot/src/main.rs | 76 +++++++++++++++++++---------- src/dispatching2/handler_ext.rs | 22 +++++---- src/dispatching2/handler_factory.rs | 8 +++ src/dispatching2/mod.rs | 3 ++ src/prelude.rs | 1 + 5 files changed, 74 insertions(+), 36 deletions(-) create mode 100644 src/dispatching2/handler_factory.rs diff --git a/examples/dialogue_bot/src/main.rs b/examples/dialogue_bot/src/main.rs index fa717307..f312a9d5 100644 --- a/examples/dialogue_bot/src/main.rs +++ b/examples/dialogue_bot/src/main.rs @@ -17,6 +17,7 @@ use teloxide::{ dispatching2::dialogue::{serializer::Json, SqliteStorage}, prelude::*, }; +use teloxide::dispatching2::HandlerFactory; // FIXME: naming type MyBot = AutoSend; @@ -27,8 +28,49 @@ type BotDialogue = Dialogue; pub enum State { Start, ReceiveFullName, - ReceiveAge { full_name: String }, - ReceiveLocation { full_name: String, age: u8 }, + ReceiveAge(String), + ReceiveLocation(ReceiveLocation), +} + +#[derive(Clone, serde::Serialize, serde::Deserialize)] +pub struct ReceiveLocation { full_name: String, age: u8 } + +impl HandlerFactory for State { + type Out = anyhow::Result<()>; + + fn handler() -> dptree::Handler<'static, DependencyMap, anyhow::Result<()>> { + dptree::entry() + .branch( + dptree::filter(|dialogue: Dialogue| async move { + let state = match dialogue.current_state_or_default().await { + Ok(state) => state, + Err(_) => return false, + }; + match state { State::Start => true, _ => false } + }).endpoint(handle_start) + ) + .branch( + dptree::filter(|dialogue: Dialogue| async move { + let state = match dialogue.current_state_or_default().await { + Ok(state) => state, + Err(_) => return false, + }; + match state { State::ReceiveFullName => true, _ => false } + }).endpoint(handle_receive_full_name) + ) + .branch( + dptree::filter_map(|dialogue: Dialogue| async move { + let state = dialogue.current_state_or_default().await.ok()?; + match state { State::ReceiveAge(arg) => Some(arg), _ => None } + }).endpoint(handle_receive_age) + ) + .branch( + dptree::filter_map(|dialogue: Dialogue| async move { + let state = dialogue.current_state_or_default().await.ok()?; + match state { State::ReceiveLocation(arg) => Some(arg), _ => None } + }).endpoint(handle_receive_location) + ) + } } impl Default for State { @@ -48,31 +90,12 @@ async fn main() { Dispatcher::new(bot) .dependencies(dptree::deps![storage]) .messages_handler(|h| { - h.add_dialogue::().branch(dptree::endpoint(handle_message)) + h.add_dialogue::().dispatch_by::() }) .dispatch() .await; } -async fn handle_message(bot: MyBot, mes: Message, dialogue: BotDialogue) -> anyhow::Result<()> { - match mes.text().map(ToOwned::to_owned) { - None => { - bot.send_message(mes.chat_id(), "Send me a text message.").await?; - Ok(()) - } - Some(_) => match dialogue.current_state_or_default().await? { - State::Start => handle_start(bot, mes, dialogue).await, - State::ReceiveFullName => handle_receive_full_name(bot, mes, dialogue).await, - State::ReceiveAge { full_name } => { - handle_receive_age(bot, mes, dialogue, full_name).await - } - State::ReceiveLocation { full_name, age } => { - handle_receive_location(bot, mes, dialogue, full_name, age).await - } - }, - } -} - async fn handle_start(bot: MyBot, mes: Message, dialogue: BotDialogue) -> anyhow::Result<()> { bot.send_message(mes.chat_id(), "Let's start! What's your full name?").await?; dialogue.next(State::ReceiveFullName).await?; @@ -85,7 +108,7 @@ async fn handle_receive_full_name( dialogue: BotDialogue, ) -> anyhow::Result<()> { bot.send_message(mes.chat_id(), "How old are you?").await?; - dialogue.next(State::ReceiveAge { full_name: mes.text().unwrap().into() }).await?; + dialogue.next(State::ReceiveAge(mes.text().unwrap().into())).await?; Ok(()) } @@ -98,7 +121,7 @@ async fn handle_receive_age( match mes.text().unwrap().parse::() { Ok(age) => { bot.send_message(mes.chat_id(), "What's your location?").await?; - dialogue.next(State::ReceiveLocation { full_name, age }).await?; + dialogue.next(State::ReceiveLocation(ReceiveLocation { full_name, age })).await?; } _ => { bot.send_message(mes.chat_id(), "Send me a number.").await?; @@ -111,11 +134,10 @@ async fn handle_receive_location( bot: MyBot, mes: Message, dialogue: BotDialogue, - full_name: String, - age: u8, + state: ReceiveLocation ) -> anyhow::Result<()> { let location = mes.text().unwrap(); - let message = format!("Full name: {}\nAge: {}\nLocation: {}", full_name, age, location); + let message = format!("Full name: {}\nAge: {}\nLocation: {}", state.full_name, state.age, location); bot.send_message(mes.chat_id(), message).await?; dialogue.exit().await?; Ok(()) diff --git a/src/dispatching2/handler_ext.rs b/src/dispatching2/handler_ext.rs index 4c1f6a20..3edf0963 100644 --- a/src/dispatching2/handler_ext.rs +++ b/src/dispatching2/handler_ext.rs @@ -1,30 +1,34 @@ use crate::{types::Message, utils::command::BotCommand}; use dptree::{ - di::{DependencySupplier, Insert}, Handler, }; +use crate::dispatching2::HandlerFactory; +use dptree::di::DependencyMap; -pub trait HandlerExt { +pub trait HandlerExt { fn add_command(self, bot_name: String) -> Self where - C: BotCommand + Send, - IR: Insert; + C: BotCommand + Send + Sync + 'static; + + fn dispatch_by(self) -> Self + where F: HandlerFactory; } -impl HandlerExt for Handler<'_, Input, Output, IR> +impl HandlerExt for Handler<'static, DependencyMap, Output> where - Input: Send + Sync + 'static, Output: Send + Sync + 'static, - IR: Send + Sync + 'static + Clone + DependencySupplier, { fn add_command(self, bot_name: String) -> Self where - C: BotCommand + Send, - IR: Insert, + C: BotCommand + Send + Sync + 'static, { self.chain(dptree::filter_map(move |message: Message| { let bot_name = bot_name.clone(); async move { message.text().and_then(|text| C::parse(text, bot_name).ok()) } })) } + + fn dispatch_by(self) -> Self where F: HandlerFactory { + self.chain(F::handler()) + } } diff --git a/src/dispatching2/handler_factory.rs b/src/dispatching2/handler_factory.rs new file mode 100644 index 00000000..fe1d5399 --- /dev/null +++ b/src/dispatching2/handler_factory.rs @@ -0,0 +1,8 @@ +use dptree::di::DependencyMap; +use dptree::Handler; + +pub trait HandlerFactory { + type Out; + + fn handler() -> Handler<'static, DependencyMap, Self::Out>; +} \ No newline at end of file diff --git a/src/dispatching2/mod.rs b/src/dispatching2/mod.rs index 412eb300..847d44ea 100644 --- a/src/dispatching2/mod.rs +++ b/src/dispatching2/mod.rs @@ -3,5 +3,8 @@ pub(crate) mod repls; pub mod dialogue; mod dispatcher; mod handler_ext; +mod handler_factory; pub use dispatcher::Dispatcher; +pub use handler_factory::HandlerFactory; +pub use handler_ext::HandlerExt; diff --git a/src/prelude.rs b/src/prelude.rs index a7010fa7..a91827c3 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -17,6 +17,7 @@ pub use crate::dispatching::{ #[cfg(feature = "new-dispatching")] pub use crate::dispatching2::{ dialogue::{Dialogue, DialogueHandlerExt as _}, + HandlerExt as _, Dispatcher, };