Add multiple_handlers_bot

This commit is contained in:
Temirkhan Myrzamadi 2020-02-13 14:55:46 +06:00
parent 56ae0e1e6c
commit 7cf6aaff90
9 changed files with 154 additions and 25 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ Cargo.lock
examples/target examples/target
examples/ping_pong_bot/target examples/ping_pong_bot/target
examples/dialogue_bot/target examples/dialogue_bot/target
examples/multiple_handlers_bot/target

View file

@ -3,8 +3,6 @@
#[macro_use] #[macro_use]
extern crate smart_default; extern crate smart_default;
use std::env::{set_var, var};
use teloxide::{ use teloxide::{
prelude::*, prelude::*,
types::{KeyboardButton, ReplyKeyboardMarkup}, types::{KeyboardButton, ReplyKeyboardMarkup},
@ -175,12 +173,15 @@ async fn handle_message(ctx: Ctx<Dialogue>) -> Res {
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
set_var("RUST_LOG", "dialogue_bot=trace"); run().await;
set_var("RUST_LOG", "teloxide=error"); }
pretty_env_logger::init();
log::info!("Starting the dialogue_bot bot!");
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) Dispatcher::new(bot)
.message_handler(&DialogueDispatcher::new(|ctx| async move { .message_handler(&DialogueDispatcher::new(|ctx| async move {

View file

@ -0,0 +1,13 @@
[package]
name = "multiple_handlers_bot"
version = "0.1.0"
authors = ["Temirkhan Myrzamadi <hirrolot@gmail.com>"]
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 = "../../" }

View file

@ -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::<RequestError>::new(bot)
// This is the first UpdateKind::Message handler, which will be called
// after the Update handler below.
.message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
log::info!("Two!");
DispatcherHandlerResult::next(ctx.update, Ok(()))
})
// Remember: handler of Update are called first.
.update_handler(&|ctx: DispatcherHandlerCtx<Update>| 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<Message>| 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<Message>| 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.
}

View file

@ -1,17 +1,17 @@
use teloxide::prelude::*; use teloxide::prelude::*;
use std::env::{set_var, var};
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
// Configure a fancy logger. Let this bot print everything, but restrict run().await;
// 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!");
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 // Create a dispatcher with a single message handler that answers "pong" to
// each incoming message. // each incoming message.

View file

@ -84,6 +84,16 @@ where
self self
} }
#[must_use]
pub fn update_handler<H, I>(mut self, h: &'a H) -> Self
where
H: CtxHandler<DispatcherHandlerCtx<Update>, I> + 'a,
I: Into<DispatcherHandlerResult<Update, HandlerE>> + 'a,
{
self.update_handlers = register_handler(self.update_handlers, h);
self
}
#[must_use] #[must_use]
pub fn message_handler<H, I>(mut self, h: &'a H) -> Self pub fn message_handler<H, I>(mut self, h: &'a H) -> Self
where where

View file

@ -10,14 +10,22 @@ pub struct DispatcherHandlerResult<Upd, E> {
} }
impl<Upd, E> DispatcherHandlerResult<Upd, E> { impl<Upd, E> DispatcherHandlerResult<Upd, E> {
/// Creates new `DispatcherHandlerResult`. /// Creates new `DispatcherHandlerResult` that continues the pipeline.
pub fn new(next: Option<Upd>, result: Result<(), E>) -> Self { pub fn next(update: Upd, result: Result<(), E>) -> Self {
Self { next, result } Self {
next: Some(update),
result,
}
}
/// Creates new `DispatcherHandlerResult` that terminates the pipeline.
pub fn exit(result: Result<(), E>) -> Self {
Self { next: None, result }
} }
} }
impl<Upd, E> From<Result<(), E>> for DispatcherHandlerResult<Upd, E> { impl<Upd, E> From<Result<(), E>> for DispatcherHandlerResult<Upd, E> {
fn from(result: Result<(), E>) -> Self { fn from(result: Result<(), E>) -> Self {
Self::new(None, result) Self::exit(result)
} }
} }

View file

@ -22,8 +22,8 @@
//! explicitly, because of automatic conversions. Just return `Result<(), E>` if //! explicitly, because of automatic conversions. Just return `Result<(), E>` if
//! you want to terminate the pipeline (see the example below). //! you want to terminate the pipeline (see the example below).
//! //!
//! ## Examples //! # Examples
//! The ping-pong bot ([full](https://github.com/teloxide/teloxide/blob/dev/examples/ping_pong_bot/)): //! ### The ping-pong bot
//! //!
//! ``` //! ```
//! # #[tokio::main] //! # #[tokio::main]
@ -32,6 +32,8 @@
//! //!
//! // Setup logging here... //! // Setup logging here...
//! //!
//! // Create a dispatcher with a single message handler that answers "pong"
//! // to each incoming message.
//! Dispatcher::<RequestError>::new(Bot::new("MyAwesomeToken")) //! Dispatcher::<RequestError>::new(Bot::new("MyAwesomeToken"))
//! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move { //! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
//! ctx.answer("pong").send().await?; //! 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::<RequestError>::new(Bot::new("MyAwesomeToken"))
//! // This is the first UpdateKind::Message handler, which will be called
//! // after the Update handler below.
//! .message_handler(&|ctx: DispatcherHandlerCtx<Message>| async move {
//! log::info!("Two!");
//! DispatcherHandlerResult::next(ctx.update, Ok(()))
//! })
//! // Remember: handler of Update are called first.
//! .update_handler(&|ctx: DispatcherHandlerCtx<Update>| 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<Message>| 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<Message>| 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]. //! For a bit more complicated example, please see [examples/dialogue_bot].
//! //!
//! [`Dispatcher`]: crate::dispatching::Dispatcher //! [`Dispatcher`]: crate::dispatching::Dispatcher

View file

@ -6,9 +6,9 @@ pub use crate::{
exit, next, DialogueDispatcher, DialogueHandlerCtx, DialogueStage, exit, next, DialogueDispatcher, DialogueHandlerCtx, DialogueStage,
GetChatId, GetChatId,
}, },
Dispatcher, DispatcherHandlerCtx, Dispatcher, DispatcherHandlerCtx, DispatcherHandlerResult,
}, },
requests::{Request, ResponseResult}, requests::{Request, ResponseResult},
types::Message, types::{Message, Update},
Bot, RequestError, Bot, RequestError,
}; };