Merge branch 'dev' into rocksdb-storage

Former-commit-id: 24f8476da7
This commit is contained in:
Sima Kinsart 2022-10-30 11:57:10 +06:00 committed by GitHub
commit 2fd41bda94
10 changed files with 177 additions and 9 deletions

View file

@ -8,7 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- The `rocksdb-storage` feature -- enables the RocksDB support ([PR #753](https://github.com/teloxide/teloxide/pull/753)). - The `rocksdb-storage` feature -- enables the RocksDB support ([PR #753](https://github.com/teloxide/teloxide/pull/753))
- `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 `CommandReplExt` instead)
## 0.11.0 - 2022-10-07 ## 0.11.0 - 2022-10-07

View file

@ -1,6 +1,22 @@
This document describes breaking changes of `teloxide` crate, as well as the ways to update code. 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. 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 ## 0.10 -> 0.11
### core ### core

View file

@ -29,7 +29,7 @@
[`dptree`]: https://github.com/teloxide/dptree [`dptree`]: https://github.com/teloxide/dptree
[chain of responsibility]: https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern [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], [RocksDB] and [Sqlite]. - **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], [RocksDB] and [Sqlite].
@ -132,7 +132,7 @@ async fn main() {
let bot = Bot::from_env(); let bot = Bot::from_env();
teloxide::commands_repl(bot, answer, Command::ty()).await; Command::repl(bot, answer).await;
} }
#[derive(BotCommands, Clone)] #[derive(BotCommands, Clone)]

View file

@ -60,7 +60,7 @@ async fn main() {
let bot = teloxide::Bot::from_env(); 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<()> { async fn action(bot: Bot, msg: Message, cmd: Command) -> ResponseResult<()> {

View file

@ -7,7 +7,7 @@ async fn main() {
let bot = Bot::from_env(); let bot = Bot::from_env();
teloxide::commands_repl(bot, answer, Command::ty()).await; Command::repl(bot, answer).await;
} }
#[derive(BotCommands, Clone)] #[derive(BotCommands, Clone)]

View file

@ -11,5 +11,7 @@
mod commands_repl; mod commands_repl;
mod repl; mod repl;
pub use commands_repl::CommandReplExt;
#[allow(deprecated)]
pub use commands_repl::{commands_repl, commands_repl_with_listener}; pub use commands_repl::{commands_repl, commands_repl_with_listener};
pub use repl::{repl, repl_with_listener}; pub use repl::{repl, repl_with_listener};

View file

@ -8,8 +8,147 @@ use crate::{
utils::command::BotCommands, utils::command::BotCommands,
}; };
use dptree::di::{DependencyMap, Injectable}; use dptree::di::{DependencyMap, Injectable};
use futures::future::BoxFuture;
use std::{fmt::Debug, marker::PhantomData}; 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 CommandReplExt {
/// A REPL for commands.
///
/// See [`CommandReplExt`] for more details.
#[must_use]
fn repl<'a, R, H, Args>(bot: R, handler: H) -> BoxFuture<'a, ()>
where
R: Requester + Clone + Send + Sync + 'static,
<R as Requester>::GetUpdates: Send,
<R as Requester>::GetWebhookInfo: Send,
<R as Requester>::GetMe: Send,
<R as Requester>::DeleteWebhook: Send,
H: Injectable<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static;
/// A REPL for commands with a custom [`UpdateListener`].
///
/// 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
H: Injectable<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static,
L: UpdateListener + Send + 'a,
L::Err: Debug + Send + 'a,
R: Requester + Clone + Send + Sync + 'static,
<R as Requester>::GetMe: Send;
}
#[cfg(feature = "ctrlc_handler")]
impl<Cmd> CommandReplExt 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,
<R as Requester>::GetUpdates: Send,
<R as Requester>::GetWebhookInfo: Send,
<R as Requester>::GetMe: Send,
<R as Requester>::DeleteWebhook: Send,
H: Injectable<DependencyMap, ResponseResult<()>, 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<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static,
L: UpdateListener + Send + 'a,
L::Err: Debug + Send + 'a,
R: Requester + Clone + Send + Sync + 'static,
<R as Requester>::GetMe: Send,
{
use crate::dispatching::Dispatcher;
// Other update types are of no interest to use since this REPL is only for
// commands. See <https://github.com/teloxide/teloxide/issues/557>.
let ignore_update = |_upd| Box::pin(async {});
Box::pin(async move {
Dispatcher::builder(
bot,
Update::filter_message().filter_command::<Cmd>().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. /// A [REPL] for commands.
// //
/// ///
@ -59,6 +198,7 @@ use std::{fmt::Debug, marker::PhantomData};
#[doc = include_str!("caution.md")] #[doc = include_str!("caution.md")]
/// ///
#[cfg(feature = "ctrlc_handler")] #[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<Cmd>) pub async fn commands_repl<'a, R, Cmd, H, Args>(bot: R, handler: H, cmd: PhantomData<Cmd>)
where where
R: Requester + Clone + Send + Sync + 'static, R: Requester + Clone + Send + Sync + 'static,
@ -68,6 +208,7 @@ where
{ {
let cloned_bot = bot.clone(); let cloned_bot = bot.clone();
#[allow(deprecated)]
commands_repl_with_listener( commands_repl_with_listener(
bot, bot,
handler, handler,
@ -127,6 +268,7 @@ where
#[doc = include_str!("caution.md")] #[doc = include_str!("caution.md")]
/// ///
#[cfg(feature = "ctrlc_handler")] #[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>( pub async fn commands_repl_with_listener<'a, R, Cmd, H, L, Args>(
bot: R, bot: R,
handler: H, handler: H,

View file

@ -58,9 +58,10 @@
#![allow(clippy::nonstandard_macro_braces)] #![allow(clippy::nonstandard_macro_braces)]
#[cfg(feature = "ctrlc_handler")] #[cfg(feature = "ctrlc_handler")]
pub use dispatching::repls::{ pub use dispatching::repls::{repl, repl_with_listener};
commands_repl, commands_repl_with_listener, repl, repl_with_listener,
}; #[allow(deprecated)]
pub use dispatching::repls::{commands_repl, commands_repl_with_listener};
pub mod dispatching; pub mod dispatching;
pub mod error_handlers; pub mod error_handlers;

View file

@ -6,7 +6,8 @@ pub use crate::error_handlers::{LoggingErrorHandler, OnError};
pub use crate::respond; pub use crate::respond;
pub use crate::dispatching::{ pub use crate::dispatching::{
dialogue::Dialogue, Dispatcher, HandlerExt as _, MessageFilterExt as _, UpdateFilterExt as _, dialogue::Dialogue, repls::CommandReplExt as _, Dispatcher, HandlerExt as _,
MessageFilterExt as _, UpdateFilterExt as _,
}; };
pub use teloxide_core::{ pub use teloxide_core::{

View file

@ -235,6 +235,7 @@ pub trait BotCommands: Sized {
/// ///
/// [`commands_repl`]: (crate::repls::commands_repl) /// [`commands_repl`]: (crate::repls::commands_repl)
#[must_use] #[must_use]
#[deprecated(note = "Use `CommandReplExt` instead")]
fn ty() -> PhantomData<Self> { fn ty() -> PhantomData<Self> {
PhantomData PhantomData
} }