From f54db300ed4b5136636ba1e00350f46bca9e5499 Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Tue, 11 Oct 2022 14:54:51 +0600 Subject: [PATCH 1/6] Implement the `CommandRepl` trait Former-commit-id: 739772929bd7e13f42f12e9afa02fef450ec0222 --- CHANGELOG.md | 8 ++ MIGRATION_GUIDE.md | 16 +++ examples/admin.rs | 2 +- examples/command.rs | 2 +- src/dispatching/repls.rs | 2 + src/dispatching/repls/commands_repl.rs | 140 +++++++++++++++++++++++++ src/lib.rs | 7 +- src/prelude.rs | 3 +- 8 files changed, 174 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7687aa9b..b9b891ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## unreleased +### Added + + - `teloxide::dispatching::repls::CommandRepl`, `teloxide::prelude::CommandRepl` ([issue #740](https://github.com/teloxide/teloxide/issues/740)) + +### Deprecated + + - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}` (use `CommandRepl` instead) + ## 0.11.0 - 2022-10-07 ### Changed diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 1449cca1..937320a7 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -1,6 +1,22 @@ This document describes breaking changes of `teloxide` crate, as well as the ways to update code. Note that the list of required changes is not fully exhaustive and it may lack something in rare cases. +## 0.10 -> 0.xxx.xxx + +### teloxide + +We have introduced the new trait `CommandRepl` that replaces the old `commands_repl_(with_listener)` functions: + +```diff,rust +- teloxide::commands_repl(bot, answer, Command::ty()) ++ Command::repl(bot, answer) +``` + +```diff,rust +- teloxide::commands_repl_with_listener(bot, answer, listener, Command::ty()) ++ Command::repl_with_listener(bot, answer, listener) +``` + ## 0.10 -> 0.11 ### core diff --git a/examples/admin.rs b/examples/admin.rs index 17f7373f..113d6f07 100644 --- a/examples/admin.rs +++ b/examples/admin.rs @@ -60,7 +60,7 @@ async fn main() { let bot = teloxide::Bot::from_env(); - teloxide::commands_repl(bot, action, Command::ty()).await; + Command::repl(bot, action).await; } async fn action(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> { diff --git a/examples/command.rs b/examples/command.rs index 00f44315..26848015 100644 --- a/examples/command.rs +++ b/examples/command.rs @@ -7,7 +7,7 @@ async fn main() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, answer, Command::ty()).await; + Command::repl(bot, answer).await; } #[derive(BotCommands, Clone)] diff --git a/src/dispatching/repls.rs b/src/dispatching/repls.rs index 71d70343..e8e6c4ac 100644 --- a/src/dispatching/repls.rs +++ b/src/dispatching/repls.rs @@ -11,5 +11,7 @@ mod commands_repl; mod repl; +pub use commands_repl::CommandRepl; +#[allow(deprecated)] pub use commands_repl::{commands_repl, commands_repl_with_listener}; pub use repl::{repl, repl_with_listener}; diff --git a/src/dispatching/repls/commands_repl.rs b/src/dispatching/repls/commands_repl.rs index fe9d9fb7..0c237044 100644 --- a/src/dispatching/repls/commands_repl.rs +++ b/src/dispatching/repls/commands_repl.rs @@ -8,8 +8,145 @@ use crate::{ utils::command::BotCommands, }; use dptree::di::{DependencyMap, Injectable}; +use futures::future::BoxFuture; use std::{fmt::Debug, marker::PhantomData}; +/// A [REPL] for commands. +/// +/// REPLs are meant only for simple bots and rapid prototyping. If you need to +/// supply dependencies or describe more complex dispatch logic, please use +/// [`Dispatcher`]. See also: ["Dispatching or +/// REPLs?"](../index.html#dispatching-or-repls). +/// +/// [`Dispatcher`]: crate::dispatching::Dispatcher +/// +/// All errors from the handler and update listener will be logged. +/// +/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop +/// +/// This trait extends your [`BotCommands`] type with REPL facilities. +/// +/// ## Signatures +/// +/// Don't be scared by many trait bounds in the signatures, in essence they +/// require: +/// +/// 1. `bot` is a bot, client for the Telegram bot API. It is represented via +/// the [`Requester`] trait. +/// 2. `handler` is an `async` function that takes arguments from +/// [`DependencyMap`] (see below) and returns [`ResponseResult`]. +/// 3. `listener` is something that takes updates from a Telegram server and +/// implements [`UpdateListener`]. +/// +/// All the other requirements are about thread safety and data validity and can +/// be ignored for most of the time. +/// +/// ## Handler arguments +/// +/// `teloxide` provides the following types to the `handler`: +/// - [`Message`] +/// - `R` (type of the `bot`) +/// - `Cmd` (type of the parsed command) +/// - [`Me`] +/// +/// Each of these types can be accepted as a handler parameter. Note that they +/// aren't all required at the same time: e.g., you can take only the bot and +/// the command without [`Me`] and [`Message`]. +/// +/// [`Me`]: crate::types::Me +/// [`Message`]: crate::types::Message +/// +/// ## Stopping +// +#[doc = include_str!("stopping.md")] +/// +/// ## Caution +// +#[doc = include_str!("caution.md")] +/// +#[cfg(feature = "ctrlc_handler")] +pub trait CommandRepl { + /// A REPL for commands. + /// + /// See [`CommandRepl`] for more details. + fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()> + where + R: Requester + Clone + Send + Sync + 'static, + ::GetUpdates: Send, + ::GetWebhookInfo: Send, + ::GetMe: Send, + ::DeleteWebhook: Send, + H: Injectable, Args> + Send + Sync + 'static; + + /// A REPL for commands with a custom [`UpdateListener`]. + /// + /// See [`CommandRepl`] for more details. + fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()> + where + H: Injectable, Args> + Send + Sync + 'static, + L: UpdateListener + Send + 'a, + L::Err: Debug + Send + 'a, + R: Requester + Clone + Send + Sync + 'static, + ::GetMe: Send; +} + +#[cfg(feature = "ctrlc_handler")] +impl CommandRepl for Cmd +where + Cmd: BotCommands + Send + Sync + 'static, +{ + fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()> + where + R: Requester + Clone + Send + Sync + 'static, + ::GetUpdates: Send, + ::GetWebhookInfo: Send, + ::GetMe: Send, + ::DeleteWebhook: Send, + H: Injectable, Args> + Send + Sync + 'static, + { + let cloned_bot = bot.clone(); + + Box::pin(async move { + Self::repl_with_listener( + bot, + handler, + update_listeners::polling_default(cloned_bot).await, + ) + .await + }) + } + + fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()> + where + H: Injectable, Args> + Send + Sync + 'static, + L: UpdateListener + Send + 'a, + L::Err: Debug + Send + 'a, + R: Requester + Clone + Send + Sync + 'static, + ::GetMe: Send, + { + use crate::dispatching::Dispatcher; + + // Other update types are of no interest to use since this REPL is only for + // commands. See . + let ignore_update = |_upd| Box::pin(async {}); + + Box::pin(async move { + Dispatcher::builder( + bot, + Update::filter_message().filter_command::().endpoint(handler), + ) + .default_handler(ignore_update) + .enable_ctrlc_handler() + .build() + .dispatch_with_listener( + listener, + LoggingErrorHandler::with_custom_text("An error from the update listener"), + ) + .await + }) + } +} + /// A [REPL] for commands. // /// @@ -59,6 +196,7 @@ use std::{fmt::Debug, marker::PhantomData}; #[doc = include_str!("caution.md")] /// #[cfg(feature = "ctrlc_handler")] +#[deprecated(note = "Use `CommandsRepl::repl` instead")] pub async fn commands_repl<'a, R, Cmd, H, Args>(bot: R, handler: H, cmd: PhantomData) where R: Requester + Clone + Send + Sync + 'static, @@ -68,6 +206,7 @@ where { let cloned_bot = bot.clone(); + #[allow(deprecated)] commands_repl_with_listener( bot, handler, @@ -127,6 +266,7 @@ where #[doc = include_str!("caution.md")] /// #[cfg(feature = "ctrlc_handler")] +#[deprecated(note = "Use `CommandsRepl::repl_with_listener` instead")] pub async fn commands_repl_with_listener<'a, R, Cmd, H, L, Args>( bot: R, handler: H, diff --git a/src/lib.rs b/src/lib.rs index 80237a9d..04012a60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,9 +58,10 @@ #![allow(clippy::nonstandard_macro_braces)] #[cfg(feature = "ctrlc_handler")] -pub use dispatching::repls::{ - commands_repl, commands_repl_with_listener, repl, repl_with_listener, -}; +pub use dispatching::repls::{repl, repl_with_listener}; + +#[allow(deprecated)] +pub use dispatching::repls::{commands_repl, commands_repl_with_listener}; pub mod dispatching; pub mod error_handlers; diff --git a/src/prelude.rs b/src/prelude.rs index 6dbe94df..499eaea7 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,7 +6,8 @@ pub use crate::error_handlers::{LoggingErrorHandler, OnError}; pub use crate::respond; pub use crate::dispatching::{ - dialogue::Dialogue, Dispatcher, HandlerExt as _, MessageFilterExt as _, UpdateFilterExt as _, + dialogue::Dialogue, repls::CommandRepl as _, Dispatcher, HandlerExt as _, + MessageFilterExt as _, UpdateFilterExt as _, }; pub use teloxide_core::{ From 5ed01a91d4164133781e79debbcb4bc80e476020 Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Tue, 11 Oct 2022 14:57:40 +0600 Subject: [PATCH 2/6] Use `Command::repl` in `README.md` Former-commit-id: db30e9efbe6333ad836fc3cb78916fa69caf6d00 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d25c150f..2b6594e4 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ async fn main() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, answer, Command::ty()).await; + Command::repl(bot, answer).await; } #[derive(BotCommands, Clone)] From e39a9d007afa1ad1f008bfccc3876e3a5836404f Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Tue, 11 Oct 2022 15:00:02 +0600 Subject: [PATCH 3/6] Deprecate `BotCommands::ty` too Former-commit-id: d90a9ff2e466db4fdcdaa8a6b62ab86e6f9e76af --- CHANGELOG.md | 2 +- src/utils/command.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9b891ec..513e536d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Deprecated - - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}` (use `CommandRepl` instead) + - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}`, `teloxide::utils::command::BotCommands::ty` (use `CommandRepl` instead) ## 0.11.0 - 2022-10-07 diff --git a/src/utils/command.rs b/src/utils/command.rs index 785479d7..9c9814eb 100644 --- a/src/utils/command.rs +++ b/src/utils/command.rs @@ -235,6 +235,7 @@ pub trait BotCommands: Sized { /// /// [`commands_repl`]: (crate::repls::commands_repl) #[must_use] + #[deprecated(note = "Use `CommandRepl` instead")] fn ty() -> PhantomData { PhantomData } From 9b8e21231c9aee74170d6bb3542222effea6b8e1 Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Sat, 15 Oct 2022 23:54:16 +0600 Subject: [PATCH 4/6] Make `CommandRepl`'s methods `#[must_use]` Former-commit-id: 0fb9399201cfa24d5890311ad9cc3cdf7cb1d0ad --- src/dispatching/repls/commands_repl.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dispatching/repls/commands_repl.rs b/src/dispatching/repls/commands_repl.rs index 0c237044..5cbecd5b 100644 --- a/src/dispatching/repls/commands_repl.rs +++ b/src/dispatching/repls/commands_repl.rs @@ -69,6 +69,7 @@ pub trait CommandRepl { /// A REPL for commands. /// /// See [`CommandRepl`] for more details. + #[must_use] fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()> where R: Requester + Clone + Send + Sync + 'static, @@ -81,6 +82,7 @@ pub trait CommandRepl { /// A REPL for commands with a custom [`UpdateListener`]. /// /// See [`CommandRepl`] for more details. + #[must_use] fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()> where H: Injectable, Args> + Send + Sync + 'static, From 7963a9184ab047e3602eff14d1fb130019d28b19 Mon Sep 17 00:00:00 2001 From: Sima Kinsart Date: Sat, 22 Oct 2022 10:11:18 +0600 Subject: [PATCH 5/6] Mention graceful shutdown in the highlights Former-commit-id: d60a7d034156866dc37f478ee5bf2c110fb14a63 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2fb0010a..878c4ad8 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ [`dptree`]: https://github.com/teloxide/dptree [chain of responsibility]: https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern - - **Feature-rich.** You can use both long polling and webhooks, configure an underlying HTTPS client, set a custom URL of a Telegram API server, and much more. + - **Feature-rich.** You can use both long polling and webhooks, configure an underlying HTTPS client, set a custom URL of a Telegram API server, do graceful shutdown, and much more. - **Simple dialogues.** Our dialogues subsystem is simple and easy-to-use, and, furthermore, is agnostic of how/where dialogues are stored. For example, you can just replace a one line to achieve [persistence]. Out-of-the-box storages include [Redis] and [Sqlite]. From 5532a4cd87d56ba130d01183f2f2f65f5c92f590 Mon Sep 17 00:00:00 2001 From: Hirrolot Date: Sat, 29 Oct 2022 14:39:21 +0600 Subject: [PATCH 6/6] Rename `CommandRepl` => `CommandReplExt` Former-commit-id: e7c5317954943f6ca3e65f036796078a8c4f0525 --- CHANGELOG.md | 4 ++-- src/dispatching/repls.rs | 2 +- src/dispatching/repls/commands_repl.rs | 8 ++++---- src/prelude.rs | 2 +- src/utils/command.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 513e536d..5f6c5e26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - - `teloxide::dispatching::repls::CommandRepl`, `teloxide::prelude::CommandRepl` ([issue #740](https://github.com/teloxide/teloxide/issues/740)) + - `teloxide::dispatching::repls::CommandReplExt`, `teloxide::prelude::CommandReplExt` ([issue #740](https://github.com/teloxide/teloxide/issues/740)) ### Deprecated - - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}`, `teloxide::utils::command::BotCommands::ty` (use `CommandRepl` instead) + - `teloxide::dispatching::repls::{commands_repl, commands_repl_with_listener}`, `teloxide::utils::command::BotCommands::ty` (use `CommandReplExt` instead) ## 0.11.0 - 2022-10-07 diff --git a/src/dispatching/repls.rs b/src/dispatching/repls.rs index e8e6c4ac..aea4806e 100644 --- a/src/dispatching/repls.rs +++ b/src/dispatching/repls.rs @@ -11,7 +11,7 @@ mod commands_repl; mod repl; -pub use commands_repl::CommandRepl; +pub use commands_repl::CommandReplExt; #[allow(deprecated)] pub use commands_repl::{commands_repl, commands_repl_with_listener}; pub use repl::{repl, repl_with_listener}; diff --git a/src/dispatching/repls/commands_repl.rs b/src/dispatching/repls/commands_repl.rs index 5cbecd5b..15f2396d 100644 --- a/src/dispatching/repls/commands_repl.rs +++ b/src/dispatching/repls/commands_repl.rs @@ -65,10 +65,10 @@ use std::{fmt::Debug, marker::PhantomData}; #[doc = include_str!("caution.md")] /// #[cfg(feature = "ctrlc_handler")] -pub trait CommandRepl { +pub trait CommandReplExt { /// A REPL for commands. /// - /// See [`CommandRepl`] for more details. + /// See [`CommandReplExt`] for more details. #[must_use] fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()> where @@ -81,7 +81,7 @@ pub trait CommandRepl { /// A REPL for commands with a custom [`UpdateListener`]. /// - /// See [`CommandRepl`] for more details. + /// See [`CommandReplExt`] for more details. #[must_use] fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) -> BoxFuture<'a, ()> where @@ -93,7 +93,7 @@ pub trait CommandRepl { } #[cfg(feature = "ctrlc_handler")] -impl CommandRepl for Cmd +impl CommandReplExt for Cmd where Cmd: BotCommands + Send + Sync + 'static, { diff --git a/src/prelude.rs b/src/prelude.rs index 499eaea7..ca6afa90 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,7 +6,7 @@ pub use crate::error_handlers::{LoggingErrorHandler, OnError}; pub use crate::respond; pub use crate::dispatching::{ - dialogue::Dialogue, repls::CommandRepl as _, Dispatcher, HandlerExt as _, + dialogue::Dialogue, repls::CommandReplExt as _, Dispatcher, HandlerExt as _, MessageFilterExt as _, UpdateFilterExt as _, }; diff --git a/src/utils/command.rs b/src/utils/command.rs index 9c9814eb..8f96998e 100644 --- a/src/utils/command.rs +++ b/src/utils/command.rs @@ -235,7 +235,7 @@ pub trait BotCommands: Sized { /// /// [`commands_repl`]: (crate::repls::commands_repl) #[must_use] - #[deprecated(note = "Use `CommandRepl` instead")] + #[deprecated(note = "Use `CommandReplExt` instead")] fn ty() -> PhantomData { PhantomData }