Merge pull request #712 from teloxide/repl_docs_upd

Update docs of REPLs
This commit is contained in:
Waffle Maybe 2022-10-07 14:25:16 +04:00 committed by GitHub
commit f52d11d246
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 198 additions and 83 deletions

View file

@ -1,4 +1,12 @@
//! REPLs for dispatching updates. //! [REPL]s for dispatching updates.
//!
//! This module provides utilities for easy update handling. They accept a
//! single "handler" function that processes all updates of a certain kind. Note
//! that REPLs are meant to be used for simple scenarios, such as prototyping,
//! inasmuch they lack configuration and some [advanced features].
//!
//! [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
//! [advanced features]: crate::dispatching#dispatching-or-repls
mod commands_repl; mod commands_repl;
mod repl; mod repl;

View file

@ -0,0 +1,2 @@
**DO NOT** use this function together with [`Dispatcher`] and other REPLs,
because Telegram disallow multiple requests at the same time from the same bot.

View file

@ -3,44 +3,68 @@ use crate::{
update_listeners, update_listeners::UpdateListener, HandlerExt, UpdateFilterExt, update_listeners, update_listeners::UpdateListener, HandlerExt, UpdateFilterExt,
}, },
error_handlers::LoggingErrorHandler, error_handlers::LoggingErrorHandler,
requests::{Requester, ResponseResult},
types::Update, types::Update,
utils::command::BotCommands, utils::command::BotCommands,
RequestError,
}; };
use dptree::di::{DependencyMap, Injectable}; use dptree::di::{DependencyMap, Injectable};
use std::{fmt::Debug, marker::PhantomData}; use std::{fmt::Debug, marker::PhantomData};
use teloxide_core::requests::Requester;
/// A [REPL] for commands. /// A [REPL] for commands.
//
/// ///
/// All errors from an update listener and handler will be logged. //
/// #[doc = include_str!("preamble.md")]
/// 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?"](dispatching/index.html#dispatching-or-repls)
///
/// ## Caution
///
/// **DO NOT** use this function together with [`Dispatcher`] and other REPLs,
/// because Telegram disallow multiple requests at the same time from the same
/// bot.
///
/// ## Dependency requirements
///
/// - Those of [`HandlerExt::filter_command`]
/// ///
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
/// [`Dispatcher`]: crate::dispatching::Dispatcher ///
/// ## Signature
///
/// Don't be scared by many trait bounds in the signature, 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. `cmd` is a type hint for your command enumeration
/// `MyCommand`: just write `MyCommand::ty()`. Note that `MyCommand` must
/// implement the [`BotCommands`] trait, typically via
/// `#[derive(BotCommands)]`.
///
/// 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")] #[cfg(feature = "ctrlc_handler")]
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
Cmd: BotCommands + Send + Sync + 'static,
H: Injectable<DependencyMap, Result<(), RequestError>, Args> + Send + Sync + 'static,
R: Requester + Clone + Send + Sync + 'static, R: Requester + Clone + Send + Sync + 'static,
<R as Requester>::GetUpdates: Send, <R as Requester>::GetUpdates: Send,
H: Injectable<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static,
Cmd: BotCommands + Send + Sync + 'static,
{ {
let cloned_bot = bot.clone(); let cloned_bot = bot.clone();
@ -53,45 +77,72 @@ where
.await; .await;
} }
/// Like [`commands_repl`], but with a custom [`UpdateListener`]. /// A [REPL] for commands, with a custom [`UpdateListener`].
//
/// ///
/// All errors from an update listener and handler will be logged. //
#[doc = include_str!("preamble.md")]
/// ///
/// REPLs are meant only for simple bots and rapid prototyping. If you need to /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
/// supply dependencies or describe more complex dispatch logic, please use
/// [`Dispatcher`].
/// ///
/// See also: ["Dispatching or /// ## Signature
/// REPLs?"](dispatching/index.html#dispatching-or-repls) ///
/// Don't be scared by many trait bounds in the signature, 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`].
/// 4. `cmd` is a type hint for your command enumeration `MyCommand`: just
/// write `MyCommand::ty()`. Note that `MyCommand` must implement the
/// [`BotCommands`] trait, typically via `#[derive(BotCommands)]`.
///
/// 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 /// ## Caution
//
#[doc = include_str!("caution.md")]
/// ///
/// **DO NOT** use this function together with [`Dispatcher`] and other REPLs,
/// because Telegram disallow multiple requests at the same time from the same
/// bot.
///
/// ## Dependency requirements
///
/// - Those of [`HandlerExt::filter_command`]
///
/// [`Dispatcher`]: crate::dispatching::Dispatcher
/// [`commands_repl`]: crate::dispatching::repls::commands_repl()
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
#[cfg(feature = "ctrlc_handler")] #[cfg(feature = "ctrlc_handler")]
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,
listener: L, listener: L,
_cmd: PhantomData<Cmd>, cmd: PhantomData<Cmd>,
) where ) where
Cmd: BotCommands + Send + Sync + 'static, Cmd: BotCommands + Send + Sync + 'static,
H: Injectable<DependencyMap, Result<(), RequestError>, Args> + Send + Sync + 'static, H: Injectable<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static,
L: UpdateListener + Send + 'a, L: UpdateListener + Send + 'a,
L::Err: Debug + Send + 'a, L::Err: Debug + Send + 'a,
R: Requester + Clone + Send + Sync + 'static, R: Requester + Clone + Send + Sync + 'static,
{ {
use crate::dispatching::Dispatcher; use crate::dispatching::Dispatcher;
let _ = cmd;
// Other update types are of no interest to use since this REPL is only for // Other update types are of no interest to use since this REPL is only for
// commands. See <https://github.com/teloxide/teloxide/issues/557>. // commands. See <https://github.com/teloxide/teloxide/issues/557>.
let ignore_update = |_upd| Box::pin(async {}); let ignore_update = |_upd| Box::pin(async {});

View file

@ -0,0 +1,7 @@
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?"](dispatching/index.html#dispatching-or-repls).
[`Dispatcher`]: crate::dispatching::Dispatcher
All errors from the handler and update listener will be logged.

View file

@ -1,70 +1,113 @@
use crate::{ use crate::{
dispatching::{update_listeners, update_listeners::UpdateListener, UpdateFilterExt}, dispatching::{update_listeners, update_listeners::UpdateListener, UpdateFilterExt},
error_handlers::LoggingErrorHandler, error_handlers::LoggingErrorHandler,
requests::{Requester, ResponseResult},
types::Update, types::Update,
RequestError,
}; };
use dptree::di::{DependencyMap, Injectable}; use dptree::di::{DependencyMap, Injectable};
use std::fmt::Debug; use std::fmt::Debug;
use teloxide_core::requests::Requester;
/// A [REPL] for messages. /// A [REPL] for messages.
//
/// ///
/// All errors from an update listener and a handler will be logged. //
/// #[doc = include_str!("preamble.md")]
/// 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?"](dispatching/index.html#dispatching-or-repls)
///
/// ## Caution
///
/// **DO NOT** use this function together with [`Dispatcher`] and other REPLs,
/// because Telegram disallow multiple requests at the same time from the same
/// bot.
/// ///
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
/// [`Dispatcher`]: crate::dispatching::Dispatcher ///
/// ## Signature
///
/// Don't be scared by many trait bounds in the signature, 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`].
///
/// ## Handler arguments
///
/// Teloxide provides the following types to the `handler`:
/// - [`Message`]
/// - `R` (type of the `bot`)
/// - [`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 message without [`Me`].
///
/// [`Me`]: crate::types::Me
/// [`Message`]: crate::types::Message
///
/// ## Stopping
//
#[doc = include_str!("stopping.md")]
///
/// ## Caution
//
#[doc = include_str!("caution.md")]
///
#[cfg(feature = "ctrlc_handler")] #[cfg(feature = "ctrlc_handler")]
pub async fn repl<R, H, Args>(bot: R, handler: H) pub async fn repl<R, H, Args>(bot: R, handler: H)
where where
H: Injectable<DependencyMap, Result<(), RequestError>, Args> + Send + Sync + 'static,
R: Requester + Send + Sync + Clone + 'static, R: Requester + Send + Sync + Clone + 'static,
<R as Requester>::GetUpdates: Send, <R as Requester>::GetUpdates: Send,
H: Injectable<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static,
{ {
let cloned_bot = bot.clone(); let cloned_bot = bot.clone();
repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot).await).await; repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot).await).await;
} }
/// Like [`repl`], but with a custom [`UpdateListener`]. /// A [REPL] for messages, with a custom [`UpdateListener`].
//
/// ///
/// All errors from an update listener and handler will be logged. //
#[doc = include_str!("preamble.md")]
/// ///
/// REPLs are meant only for simple bots and rapid prototyping. If you need to /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
/// supply dependencies or describe more complex dispatch logic, please use
/// [`Dispatcher`].
///
/// See also: ["Dispatching or
/// REPLs?"](dispatching/index.html#dispatching-or-repls)
///
/// # Caution
///
/// **DO NOT** use this function together with [`Dispatcher`] and other REPLs,
/// because Telegram disallow multiple requests at the same time from the same
/// bot.
///
/// [`Dispatcher`]: crate::dispatching::Dispatcher
/// [`repl`]: crate::dispatching::repls::repl()
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
///
/// ## Signature
///
/// Don't be scared by many trait bounds in the signature, 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`].
///
/// ## Handler arguments
///
/// Teloxide provides the following types to the `handler`:
/// - [`Message`]
/// - `R` (type of the `bot`)
/// - [`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 message without [`Me`].
///
/// [`Me`]: crate::types::Me
/// [`Message`]: crate::types::Message
///
/// ## Stopping
//
#[doc = include_str!("stopping.md")]
///
/// ## Caution
//
#[doc = include_str!("caution.md")]
///
#[cfg(feature = "ctrlc_handler")] #[cfg(feature = "ctrlc_handler")]
pub async fn repl_with_listener<'a, R, H, L, Args>(bot: R, handler: H, listener: L) pub async fn repl_with_listener<R, H, L, Args>(bot: R, handler: H, listener: L)
where where
H: Injectable<DependencyMap, Result<(), RequestError>, Args> + Send + Sync + 'static,
L: UpdateListener + Send + 'a,
L::Err: Debug,
R: Requester + Clone + Send + Sync + 'static, R: Requester + Clone + Send + Sync + 'static,
H: Injectable<DependencyMap, ResponseResult<()>, Args> + Send + Sync + 'static,
L: UpdateListener + Send,
L::Err: Debug,
{ {
use crate::dispatching::Dispatcher; use crate::dispatching::Dispatcher;

View file

@ -0,0 +1,4 @@
To stop a REPL, simply press `Ctrl`+`C` in the terminal where you run the program.
Note that graceful shutdown may take some time (we plan to improve this, see [#711]).
[#711]: https://github.com/teloxide/teloxide/issues/711