From 7a7254b8a17c6a06640b86b797f32e5ba187ee3e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 13 Feb 2020 20:12:24 +0600 Subject: [PATCH] Add BotBuilder --- Cargo.toml | 1 + examples/dialogue_bot/src/main.rs | 5 +- examples/multiple_handlers_bot/src/main.rs | 6 +- examples/ping_pong_bot/src/main.rs | 6 +- src/bot/mod.rs | 115 ++++++++++++++------- src/lib.rs | 10 +- src/prelude.rs | 1 + 7 files changed, 90 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 23823539..f57fcbf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ tokio-util = { version = "0.2.0", features = ["full"] } reqwest = { version = "0.10", features = ["json", "stream", "native-tls-vendored"] } log = "0.4.8" +pretty_env_logger = "0.4.0" bytes = "0.5.3" mime = "0.3.16" diff --git a/examples/dialogue_bot/src/main.rs b/examples/dialogue_bot/src/main.rs index e3363935..0a7003cb 100644 --- a/examples/dialogue_bot/src/main.rs +++ b/examples/dialogue_bot/src/main.rs @@ -177,12 +177,9 @@ async fn main() { } async fn run() { - std::env::set_var("RUST_LOG", "info"); - pretty_env_logger::init(); + let bot = Bot::from_env().enable_logging(crate_name!()).build(); log::info!("Starting dialogue_bot!"); - let bot = Bot::from_env(); - Dispatcher::new(bot) .message_handler(&DialogueDispatcher::new(|ctx| async move { handle_message(ctx) diff --git a/examples/multiple_handlers_bot/src/main.rs b/examples/multiple_handlers_bot/src/main.rs index a3422798..ff814ca4 100644 --- a/examples/multiple_handlers_bot/src/main.rs +++ b/examples/multiple_handlers_bot/src/main.rs @@ -6,13 +6,9 @@ async fn main() { } async fn run() { - // Configure the fancy logger. - std::env::set_var("RUST_LOG", "info"); - pretty_env_logger::init(); + let bot = Bot::from_env().enable_logging(crate_name!()).build(); log::info!("Starting multiple_handlers_bot!"); - let bot = Bot::from_env(); - // Create a dispatcher with multiple handlers of different types. This will // print One! and Two! on every incoming UpdateKind::Message. Dispatcher::::new(bot) diff --git a/examples/ping_pong_bot/src/main.rs b/examples/ping_pong_bot/src/main.rs index 7485bd95..617fb1c0 100644 --- a/examples/ping_pong_bot/src/main.rs +++ b/examples/ping_pong_bot/src/main.rs @@ -6,13 +6,9 @@ async fn main() { } async fn run() { - // Configure the fancy logger. - std::env::set_var("RUST_LOG", "info"); - pretty_env_logger::init(); + let bot = Bot::from_env().enable_logging(crate_name!()).build(); log::info!("Starting ping_pong_bot!"); - let bot = Bot::from_env(); - // Create a dispatcher with a single message handler that answers "pong" to // each incoming message. Dispatcher::::new(bot) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index a69f9caf..ad251844 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -1,3 +1,5 @@ +use log::LevelFilter; +use pretty_env_logger::env_logger::WriteStyle; use reqwest::Client; use std::sync::Arc; @@ -12,57 +14,92 @@ pub struct Bot { } impl Bot { - /// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a - /// bot's token) and the default [`reqwest::Client`]. + /// Returns [`BotBuilder`] from the `TELOXIDE_TOKEN` environmental variable + /// (a bot's token). /// /// # Panics /// If cannot get the `TELOXIDE_TOKEN` environmental variable. /// - /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html - pub fn from_env() -> Arc { - Self::new( - std::env::var("TELOXIDE_TOKEN") + /// [`BotBuilder`]: crate::BotBuilder + pub fn from_env() -> BotBuilder { + BotBuilder { + token: std::env::var("TELOXIDE_TOKEN") .expect("Cannot get the TELOXIDE_TOKEN env variable"), - ) + client: None, + } } - /// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a - /// bot's token) and your [`reqwest::Client`]. + /// Returns [`BotBuilder`] with the specified token. /// - /// # Panics - /// If cannot get the `TELOXIDE_TOKEN` environmental variable. - /// - /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html - pub fn from_env_with_client(client: Client) -> Arc { - Self::with_client( - std::env::var("TELOXIDE_TOKEN") - .expect("Cannot get the TELOXIDE_TOKEN env variable"), - client, - ) - } - - /// Creates a new `Bot` with the specified token and the default - /// [`reqwest::Client`]. - /// - /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html - pub fn new(token: S) -> Arc + /// [`BotBuilder`]: crate::BotBuilder + pub fn new(token: S) -> BotBuilder where S: Into, { - Self::with_client(token, Client::new()) - } - - /// Creates a new `Bot` with the specified token and your - /// [`reqwest::Client`]. - /// - /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html - pub fn with_client(token: S, client: Client) -> Arc - where - S: Into, - { - Arc::new(Bot { + BotBuilder { token: token.into(), - client, + client: None, + } + } +} + +/// Used to build [`Bot`]. +/// +/// [`Bot`]: crate::Bot +pub struct BotBuilder { + token: String, + client: Option, +} + +impl BotBuilder { + /// Sets your custom [`reqwest::Client`] (teloxide will make all requests + /// using it). + /// + /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html + pub fn client(mut self, client: Client) -> Self { + self.client = Some(client); + self + } + + /// Enables logging through [pretty-env-logger]. + /// + /// A logger will **only** print errors from teloxide and **all** logs from + /// your program. + /// + /// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger + pub fn enable_logging(self, crate_name: &'static str) -> Self { + Self::enable_logging_with_filter(self, crate_name, LevelFilter::Trace) + } + + /// Enables logging through [pretty-env-logger]. + /// + /// A logger will **only** print errors from teloxide and restrict logs from + /// your program by the specified filter. + /// + /// [pretty-env-logger]: https://crates.io/crates/pretty_env_logger + pub fn enable_logging_with_filter( + self, + crate_name: &'static str, + filter: LevelFilter, + ) -> Self { + pretty_env_logger::formatted_builder() + .write_style(WriteStyle::Auto) + .filter(Some(crate_name), filter) + .filter(Some("teloxide"), LevelFilter::Error) + .init(); + self + } + + /// Builds [`Bot`]. + /// + /// Sets the default [`request::Client`] if you haven't specified yours. + /// + /// [`request::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html + /// [`Bot`]: crate::Bot + pub fn build(self) -> Arc { + Arc::new(Bot { + token: self.token, + client: self.client.unwrap_or(Client::new()), }) } } diff --git a/src/lib.rs b/src/lib.rs index 8061b39f..2b2a3254 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ )] #![allow(clippy::match_bool)] -pub use bot::Bot; +pub use bot::{Bot, BotBuilder}; pub use errors::{ApiErrorKind, DownloadError, RequestError}; mod errors; @@ -18,3 +18,11 @@ pub mod types; pub mod utils; extern crate teloxide_macros; + +/// Expands to a name of your crate. +#[macro_export] +macro_rules! crate_name { + () => { + env!("CARGO_PKG_NAME") + }; +} diff --git a/src/prelude.rs b/src/prelude.rs index 97b01f16..7162d9b0 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,6 +1,7 @@ //! Commonly used items. pub use crate::{ + crate_name, dispatching::{ dialogue::{ exit, next, DialogueDispatcher, DialogueHandlerCtx, DialogueStage,