diff --git a/.gitignore b/.gitignore index 19037d54..218bb4a8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ Cargo.lock .vscode/ examples/target examples/ping_pong_bot/target -examples/dialogue_bot/target \ No newline at end of file +examples/dialogue_bot/target +examples/multiple_handlers_bot/target \ No newline at end of file diff --git a/examples/dialogue_bot/src/main.rs b/examples/dialogue_bot/src/main.rs index 5da1d516..c2d0e522 100644 --- a/examples/dialogue_bot/src/main.rs +++ b/examples/dialogue_bot/src/main.rs @@ -3,8 +3,6 @@ #[macro_use] extern crate smart_default; -use std::env::{set_var, var}; - use teloxide::{ prelude::*, types::{KeyboardButton, ReplyKeyboardMarkup}, @@ -175,12 +173,15 @@ async fn handle_message(ctx: Ctx) -> Res { #[tokio::main] async fn main() { - set_var("RUST_LOG", "dialogue_bot=trace"); - set_var("RUST_LOG", "teloxide=error"); - pretty_env_logger::init(); - log::info!("Starting the dialogue_bot bot!"); + run().await; +} - let bot = Bot::new(var("TELOXIDE_TOKEN").unwrap()); +async fn run() { + std::env::set_var("RUST_LOG", "info"); + pretty_env_logger::init(); + log::info!("Starting dialogue_bot!"); + + let bot = Bot::new(std::env::var("TELOXIDE_TOKEN").unwrap()); Dispatcher::new(bot) .message_handler(&DialogueDispatcher::new(|ctx| async move { diff --git a/examples/multiple_handlers_bot/Cargo.toml b/examples/multiple_handlers_bot/Cargo.toml new file mode 100644 index 00000000..5b44ccbe --- /dev/null +++ b/examples/multiple_handlers_bot/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "multiple_handlers_bot" +version = "0.1.0" +authors = ["Temirkhan Myrzamadi "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +pretty_env_logger = "0.3.1" +log = "0.4.8" +tokio = "0.2.9" +teloxide = { path = "../../" } \ No newline at end of file diff --git a/examples/multiple_handlers_bot/src/main.rs b/examples/multiple_handlers_bot/src/main.rs new file mode 100644 index 00000000..5ac6c96f --- /dev/null +++ b/examples/multiple_handlers_bot/src/main.rs @@ -0,0 +1,48 @@ +use teloxide::prelude::*; + +#[tokio::main] +async fn main() { + run().await; +} + +async fn run() { + // Configure the fancy logger. + std::env::set_var("RUST_LOG", "info"); + pretty_env_logger::init(); + log::info!("Starting multiple_handlers_bot!"); + + let bot = Bot::new(std::env::var("TELOXIDE_TOKEN").unwrap()); + + // Create a dispatcher with multiple handlers of different types. This will + // print One! and Two! on every incoming UpdateKind::Message. + Dispatcher::::new(bot) + // This is the first UpdateKind::Message handler, which will be called + // after the Update handler below. + .message_handler(&|ctx: DispatcherHandlerCtx| async move { + log::info!("Two!"); + DispatcherHandlerResult::next(ctx.update, Ok(())) + }) + // Remember: handler of Update are called first. + .update_handler(&|ctx: DispatcherHandlerCtx| async move { + log::info!("One!"); + DispatcherHandlerResult::next(ctx.update, Ok(())) + }) + // This handler will be called right after the first UpdateKind::Message + // handler, because it is registered after. + .message_handler(&|_ctx: DispatcherHandlerCtx| async move { + // The same as DispatcherHandlerResult::exit(Ok(())) + Ok(()) + }) + // This handler will never be called, because the UpdateKind::Message + // handler above terminates the pipeline. + .message_handler(&|ctx: DispatcherHandlerCtx| async move { + log::info!("This will never be printed!"); + DispatcherHandlerResult::next(ctx.update, Ok(())) + }) + .dispatch() + .await; + + // Note: if this bot receive, for example, UpdateKind::ChannelPost, it will + // only print "One!", because the UpdateKind::Message handlers will not be + // called. +} diff --git a/examples/ping_pong_bot/src/main.rs b/examples/ping_pong_bot/src/main.rs index 3ed49515..39f39b9c 100644 --- a/examples/ping_pong_bot/src/main.rs +++ b/examples/ping_pong_bot/src/main.rs @@ -1,17 +1,17 @@ use teloxide::prelude::*; -use std::env::{set_var, var}; - #[tokio::main] async fn main() { - // Configure a fancy logger. Let this bot print everything, but restrict - // teloxide to only log errors. - set_var("RUST_LOG", "ping_pong_bot=trace"); - set_var("RUST_LOG", "teloxide=error"); - pretty_env_logger::init(); - log::info!("Starting the ping-pong bot!"); + run().await; +} - let bot = Bot::new(var("TELOXIDE_TOKEN").unwrap()); +async fn run() { + // Configure the fancy logger. + std::env::set_var("RUST_LOG", "info"); + pretty_env_logger::init(); + log::info!("Starting ping_pong_bot!"); + + let bot = Bot::new(std::env::var("TELOXIDE_TOKEN").unwrap()); // Create a dispatcher with a single message handler that answers "pong" to // each incoming message. diff --git a/src/dispatching/dispatcher.rs b/src/dispatching/dispatcher.rs index 7cb55363..82f16b2d 100644 --- a/src/dispatching/dispatcher.rs +++ b/src/dispatching/dispatcher.rs @@ -84,6 +84,16 @@ where self } + #[must_use] + pub fn update_handler(mut self, h: &'a H) -> Self + where + H: CtxHandler, I> + 'a, + I: Into> + 'a, + { + self.update_handlers = register_handler(self.update_handlers, h); + self + } + #[must_use] pub fn message_handler(mut self, h: &'a H) -> Self where diff --git a/src/dispatching/dispatcher_handler_result.rs b/src/dispatching/dispatcher_handler_result.rs index 69b0ea4f..d7cacf22 100644 --- a/src/dispatching/dispatcher_handler_result.rs +++ b/src/dispatching/dispatcher_handler_result.rs @@ -10,14 +10,22 @@ pub struct DispatcherHandlerResult { } impl DispatcherHandlerResult { - /// Creates new `DispatcherHandlerResult`. - pub fn new(next: Option, result: Result<(), E>) -> Self { - Self { next, result } + /// Creates new `DispatcherHandlerResult` that continues the pipeline. + pub fn next(update: Upd, result: Result<(), E>) -> Self { + Self { + next: Some(update), + result, + } + } + + /// Creates new `DispatcherHandlerResult` that terminates the pipeline. + pub fn exit(result: Result<(), E>) -> Self { + Self { next: None, result } } } impl From> for DispatcherHandlerResult { fn from(result: Result<(), E>) -> Self { - Self::new(None, result) + Self::exit(result) } } diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index e3ad2dff..d6d35317 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -22,8 +22,8 @@ //! explicitly, because of automatic conversions. Just return `Result<(), E>` if //! you want to terminate the pipeline (see the example below). //! -//! ## Examples -//! The ping-pong bot ([full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/)): +//! # Examples +//! ### The ping-pong bot //! //! ``` //! # #[tokio::main] @@ -32,6 +32,8 @@ //! //! // Setup logging here... //! +//! // Create a dispatcher with a single message handler that answers "pong" +//! // to each incoming message. //! Dispatcher::::new(Bot::new("MyAwesomeToken")) //! .message_handler(&|ctx: DispatcherHandlerCtx| async move { //! ctx.answer("pong").send().await?; @@ -42,6 +44,52 @@ //! # } //! ``` //! +//! [Full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/) +//! +//! ### Multiple handlers +//! +//! ``` +//! # #[tokio::main] +//! # async fn main_() { +//! use teloxide::prelude::*; +//! +//! // Create a dispatcher with multiple handlers of different types. This will +//! // print One! and Two! on every incoming UpdateKind::Message. +//! Dispatcher::::new(Bot::new("MyAwesomeToken")) +//! // This is the first UpdateKind::Message handler, which will be called +//! // after the Update handler below. +//! .message_handler(&|ctx: DispatcherHandlerCtx| async move { +//! log::info!("Two!"); +//! DispatcherHandlerResult::next(ctx.update, Ok(())) +//! }) +//! // Remember: handler of Update are called first. +//! .update_handler(&|ctx: DispatcherHandlerCtx| async move { +//! log::info!("One!"); +//! DispatcherHandlerResult::next(ctx.update, Ok(())) +//! }) +//! // This handler will be called right after the first UpdateKind::Message +//! // handler, because it is registered after. +//! .message_handler(&|_ctx: DispatcherHandlerCtx| async move { +//! // The same as DispatcherHandlerResult::exit(Ok(())) +//! Ok(()) +//! }) +//! // This handler will never be called, because the UpdateKind::Message +//! // handler above terminates the pipeline. +//! .message_handler(&|ctx: DispatcherHandlerCtx| async move { +//! log::info!("This will never be printed!"); +//! DispatcherHandlerResult::next(ctx.update, Ok(())) +//! }) +//! .dispatch() +//! .await; +//! +//! // Note: if this bot receive, for example, UpdateKind::ChannelPost, it will +//! // only print "One!", because the UpdateKind::Message handlers will not be +//! // called. +//! # } +//! ``` +//! +//! [Full](https://github.com/teloxide/teloxide/blob/dev/examples/miltiple_handlers_bot/) +//! //! For a bit more complicated example, please see [examples/dialogue_bot]. //! //! [`Dispatcher`]: crate::dispatching::Dispatcher diff --git a/src/prelude.rs b/src/prelude.rs index c70efa5b..97b01f16 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,9 +6,9 @@ pub use crate::{ exit, next, DialogueDispatcher, DialogueHandlerCtx, DialogueStage, GetChatId, }, - Dispatcher, DispatcherHandlerCtx, + Dispatcher, DispatcherHandlerCtx, DispatcherHandlerResult, }, requests::{Request, ResponseResult}, - types::Message, + types::{Message, Update}, Bot, RequestError, };