From f4a7941cd80e3ef917a185c24ab109c1e9b50969 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 18:18:45 +0600 Subject: [PATCH 01/99] Update CHANGELOG.md --- CHANGELOG.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c856863d..9a1b2693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,17 +6,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.0] - ??? ### Added + - Support for typed bot commands ([issue 152](https://github.com/teloxide/teloxide/issues/152)). - `BotBuilder`, which allows setting a default `ParseMode`. - The `Transition`, `Subtransition`, `SubtransitionOutputType` traits. - A nicer approach to manage dialogues via `#[derive(Transition)]` + `#[teloxide(subtransition)]` (see [`examples/dialogue_bot`](https://github.com/teloxide/teloxide/tree/af2aa218e7bfc442ab4475023a1c661834f576fc/examples/dialogue_bot)). + - The `redis-storage` feature -- enables the Redis support. + - The `cbor-serializer` feature -- enables the `CBOR` serializer for dialogues. + - The `bincode-serializer` feature -- enables the `Bincode` serializer for dialogues. + - The `frunk` feature -- enables `teloxide::utils::UpState`, which allows mapping from a structure of `field1, ..., fieldN` to a structure of `field1, ..., fieldN, fieldN+1`. + - Upgrade to v4.9 Telegram bots API. + - `teloxide::utils::client_from_env` -- constructs a client from the `TELOXIDE_TOKEN` environmental variable. + - Import `Transition`, `TransitionIn`, `TransitionOut`, `UpState` to `teloxide::prelude`. + - Let users inspect an unknown API error using `ApiErrorKind::Unknown(String)`. All the known API errors are placed into `KnownApiErrorKind`. + - Setters to all the API types. + - `teloxide::dispatching::dialogue::serializer` -- various serializers for memory storages. The `Serializer` trait, `Bincode`, `CBOR`, `JSON`. + ### Deprecated - - `Bot::{from_env_with_client, new, with_client}`. + - `Bot::{from_env_with_client, new, with_client}` ### Changed - - Now methods which can send file to Telegram returns tokio::io::Result. Early its could panic. ([issue 216](https://github.com/teloxide/teloxide/issues/216)) - - Now provided description of unknown telegram error, by splitting ApiErrorKind at `ApiErrorKind` and `ApiErrorKindKnown` enums. ([issue 199](https://github.com/teloxide/teloxide/issues/199)) + - `DialogueDispatcherHandlerCx` -> `DialogueWithCx`. + - `DispatcherHandlerCx` -> `UpdateWithCx`. + - Now provided description of unknown telegram error, by splitting ApiErrorKind at `ApiErrorKind` and `ApiErrorKindKnown` enums ([issue 199](https://github.com/teloxide/teloxide/issues/199)). - Extract `Bot` from `Arc` ([issue 216](https://github.com/teloxide/teloxide/issues/230)). + - Mark all the API types as `#[non_exhaustive]`. + +### Fixed + - Now methods which can send file to Telegram returns tokio::io::Result. Early its could panic. ([issue 216](https://github.com/teloxide/teloxide/issues/216)) + - If a bot wasn't triggered for several days, it stops responding. ([issue 223](https://github.com/teloxide/teloxide/issues/223)) ## [0.2.0] - 2020-02-25 ### Added From 9d6e5a38fbd61f87d8ae66beb29c64fbfaca0033 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 18:19:08 +0600 Subject: [PATCH 02/99] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a1b2693..b0d4721d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Mark all the API types as `#[non_exhaustive]`. ### Fixed - - Now methods which can send file to Telegram returns tokio::io::Result. Early its could panic. ([issue 216](https://github.com/teloxide/teloxide/issues/216)) + - Now methods which can send file to Telegram returns `tokio::io::Result`. Early its could panic. ([issue 216](https://github.com/teloxide/teloxide/issues/216)) - If a bot wasn't triggered for several days, it stops responding. ([issue 223](https://github.com/teloxide/teloxide/issues/223)) ## [0.2.0] - 2020-02-25 From 299427645ffc9d715c046d47449f5dc9508c11b6 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 18:19:45 +0600 Subject: [PATCH 03/99] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0d4721d..0b6be63f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,8 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Mark all the API types as `#[non_exhaustive]`. ### Fixed - - Now methods which can send file to Telegram returns `tokio::io::Result`. Early its could panic. ([issue 216](https://github.com/teloxide/teloxide/issues/216)) - - If a bot wasn't triggered for several days, it stops responding. ([issue 223](https://github.com/teloxide/teloxide/issues/223)) + - Now methods which can send file to Telegram returns `tokio::io::Result`. Early its could panic ([issue 216](https://github.com/teloxide/teloxide/issues/216)). + - If a bot wasn't triggered for several days, it stops responding ([issue 223](https://github.com/teloxide/teloxide/issues/223)). ## [0.2.0] - 2020-02-25 ### Added From 5b47cbc7d690c889c29999e2002bb68187b465ef Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 18:23:02 +0600 Subject: [PATCH 04/99] Test examples/redis_remember_bot in the CI --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 151ca38c..c7b3cda1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,6 +56,7 @@ jobs: dices_bot, shared_state_bot, simple_commands_bot, + redis_remember_bot, ] steps: - uses: actions/checkout@v2 From 461e1150e59bca46eed7b9168ecd6273f60edd69 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 18:54:48 +0600 Subject: [PATCH 05/99] Add dispatching::repl --- CHANGELOG.md | 4 ++-- src/dispatching/mod.rs | 2 ++ src/dispatching/repl.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/prelude.rs | 2 +- 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 src/dispatching/repl.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b6be63f..fc4ed1d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `frunk` feature -- enables `teloxide::utils::UpState`, which allows mapping from a structure of `field1, ..., fieldN` to a structure of `field1, ..., fieldN, fieldN+1`. - Upgrade to v4.9 Telegram bots API. - `teloxide::utils::client_from_env` -- constructs a client from the `TELOXIDE_TOKEN` environmental variable. - - Import `Transition`, `TransitionIn`, `TransitionOut`, `UpState` to `teloxide::prelude`. + - Import `Transition`, `TransitionIn`, `TransitionOut`, `UpState`, `repl` to `teloxide::prelude`. - Let users inspect an unknown API error using `ApiErrorKind::Unknown(String)`. All the known API errors are placed into `KnownApiErrorKind`. - Setters to all the API types. - `teloxide::dispatching::dialogue::serializer` -- various serializers for memory storages. The `Serializer` trait, `Bincode`, `CBOR`, `JSON`. - + - `teloxide::dispatching::repl` ### Deprecated - `Bot::{from_env_with_client, new, with_client}` diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index 320ae5dc..a99c954e 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -78,12 +78,14 @@ pub mod dialogue; mod dispatcher; mod dispatcher_handler; mod dispatcher_handler_rx_ext; +mod repl; pub mod update_listeners; mod update_with_cx; pub use dispatcher::Dispatcher; pub use dispatcher_handler::DispatcherHandler; pub use dispatcher_handler_rx_ext::DispatcherHandlerRxExt; +pub use repl::repl; use tokio::sync::mpsc::UnboundedReceiver; pub use update_with_cx::UpdateWithCx; diff --git a/src/dispatching/repl.rs b/src/dispatching/repl.rs new file mode 100644 index 00000000..d138f402 --- /dev/null +++ b/src/dispatching/repl.rs @@ -0,0 +1,40 @@ +use crate::{ + dispatching::{Dispatcher, DispatcherHandlerRx, UpdateWithCx}, + error_handlers::OnError, + requests::ResponseResult, + types::Message, + Bot, +}; +use futures::StreamExt; +use std::{future::Future, sync::Arc}; + +/// A [REPL] for messages. +/// +/// Used mostly for testing and demonstrative purposes. +/// +/// # Caution +/// **DO NOT** use this function together with [`Dispatcher`], because Telegram +/// disallow multiple requests at the same time from the same bot. +/// +/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop +/// [`Dispatcher`]: crate::dispatching::Dispatcher +pub async fn repl(bot: Bot, handler: H) +where + H: Fn(UpdateWithCx) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + 'static, +{ + let handler = Arc::new(handler); + + Dispatcher::new(bot) + .messages_handler(|rx: DispatcherHandlerRx| { + rx.for_each_concurrent(None, move |message| { + let handler = Arc::clone(&handler); + + async move { + handler(message).await.log_on_error().await; + } + }) + }) + .dispatch() + .await; +} diff --git a/src/prelude.rs b/src/prelude.rs index 3b2032d9..ee244451 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,7 +6,7 @@ pub use crate::{ exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx, GetChatId, Transition, TransitionIn, TransitionOut, }, - Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx, + repl, Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx, }, error_handlers::{LoggingErrorHandler, OnError}, requests::{Request, ResponseResult}, From 67af702a81654341bc069c48110b1d20e8c6a859 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 19:07:58 +0600 Subject: [PATCH 06/99] Use repl in examples/dices_bot --- README.md | 15 ++++++--------- examples/dices_bot/src/main.rs | 13 +++++-------- src/dispatching/mod.rs | 33 +-------------------------------- src/lib.rs | 25 +++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 938beffc..093eaa5f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - + A full-featured framework that empowers you to easily build [Telegram bots](https://telegram.org/blog/bot-revolution) using the [`async`/`.await`](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) syntax in [Rust](https://www.rust-lang.org/). It handles all the difficult stuff so you can focus only on your business logic. @@ -102,14 +102,11 @@ async fn main() { let bot = Bot::from_env(); - Dispatcher::new(bot) - .messages_handler(|rx: DispatcherHandlerRx| { - rx.for_each(|message| async move { - message.send_dice().send().await.log_on_error().await; - }) - }) - .dispatch() - .await; + repl(bot, |message| async move { + message.send_dice().send().await?; + Ok(()) + }) + .await; } ``` diff --git a/examples/dices_bot/src/main.rs b/examples/dices_bot/src/main.rs index be2386eb..64a52f78 100644 --- a/examples/dices_bot/src/main.rs +++ b/examples/dices_bot/src/main.rs @@ -13,12 +13,9 @@ async fn run() { let bot = Bot::from_env(); - Dispatcher::new(bot) - .messages_handler(|rx: DispatcherHandlerRx| { - rx.for_each(|message| async move { - message.send_dice().send().await.log_on_error().await; - }) - }) - .dispatch() - .await; + repl(bot, |message| async move { + message.send_dice().send().await?; + Ok(()) + }) + .await; } diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index a99c954e..02306349 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -30,38 +30,7 @@ //! //! Since they implement [`DispatcherHandler`] too. //! -//! # The dices bot -//! This bot throws a dice on each incoming message: -//! -//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/dices_bot/src/main.rs)) -//! ```no_run -//! use teloxide::prelude::*; -//! -//! # #[tokio::main] -//! # async fn main_() { -//! teloxide::enable_logging!(); -//! log::info!("Starting dices_bot..."); -//! -//! let bot = Bot::from_env(); -//! -//! Dispatcher::new(bot) -//! .messages_handler(|rx: DispatcherHandlerRx| { -//! rx.for_each(|message| async move { -//! message.send_dice().send().await.log_on_error().await; -//! }) -//! }) -//! .dispatch() -//! .await; -//! # } -//! ``` -//! -//!
-//! -//! -//! -//!
-//! -//! [See more examples](https://github.com/teloxide/teloxide/tree/master/examples). +//! [See the examples](https://github.com/teloxide/teloxide/tree/master/examples). //! //! [`Dispatcher`]: crate::dispatching::Dispatcher //! [all the update kinds]: crate::types::UpdateKind diff --git a/src/lib.rs b/src/lib.rs index f4e60912..9079e39b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,31 @@ //! //! For a high-level overview, see [our GitHub repository](https://github.com/teloxide/teloxide). //! +//! ([Full](https://github.com/teloxide/teloxide/blob/master/examples/dices_bot/src/main.rs)) +//! ```no_run +//! use teloxide::prelude::*; +//! +//! # #[tokio::main] +//! # async fn main_() { +//! teloxide::enable_logging!(); +//! log::info!("Starting dices_bot..."); +//! +//! let bot = Bot::from_env(); +//! +//! repl(bot, |message| async move { +//! message.send_dice().send().await?; +//! Ok(()) +//! }) +//! .await; +//! # } +//! ``` +//! +//!
+//! +//! +//! +//!
+//! //! [Telegram bots]: https://telegram.org/blog/bot-revolution //! [`async`/`.await`]: https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html //! [Rust]: https://www.rust-lang.org/ From c81ec1602afc0d5580352c976a7087fa0bb17149 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 19:25:56 +0600 Subject: [PATCH 07/99] Remove repl from prelude --- CHANGELOG.md | 3 ++- README.md | 2 +- examples/dices_bot/src/main.rs | 2 +- src/lib.rs | 3 ++- src/prelude.rs | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc4ed1d1..4f0eff69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The `frunk` feature -- enables `teloxide::utils::UpState`, which allows mapping from a structure of `field1, ..., fieldN` to a structure of `field1, ..., fieldN, fieldN+1`. - Upgrade to v4.9 Telegram bots API. - `teloxide::utils::client_from_env` -- constructs a client from the `TELOXIDE_TOKEN` environmental variable. - - Import `Transition`, `TransitionIn`, `TransitionOut`, `UpState`, `repl` to `teloxide::prelude`. + - Import `Transition`, `TransitionIn`, `TransitionOut`, `UpState` to `teloxide::prelude`. + - Import `repl` to `teloxide`. - Let users inspect an unknown API error using `ApiErrorKind::Unknown(String)`. All the known API errors are placed into `KnownApiErrorKind`. - Setters to all the API types. - `teloxide::dispatching::dialogue::serializer` -- various serializers for memory storages. The `Serializer` trait, `Bincode`, `CBOR`, `JSON`. diff --git a/README.md b/README.md index 093eaa5f..5c470204 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ async fn main() { let bot = Bot::from_env(); - repl(bot, |message| async move { + teloxide::repl(bot, |message| async move { message.send_dice().send().await?; Ok(()) }) diff --git a/examples/dices_bot/src/main.rs b/examples/dices_bot/src/main.rs index 64a52f78..9768398e 100644 --- a/examples/dices_bot/src/main.rs +++ b/examples/dices_bot/src/main.rs @@ -13,7 +13,7 @@ async fn run() { let bot = Bot::from_env(); - repl(bot, |message| async move { + teloxide::repl(bot, |message| async move { message.send_dice().send().await?; Ok(()) }) diff --git a/src/lib.rs b/src/lib.rs index 9079e39b..a72798ad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ //! //! let bot = Bot::from_env(); //! -//! repl(bot, |message| async move { +//! teloxide::repl(bot, |message| async move { //! message.send_dice().send().await?; //! Ok(()) //! }) @@ -42,6 +42,7 @@ #![forbid(unsafe_code)] pub use bot::{Bot, BotBuilder}; +pub use dispatching::repl; pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError}; mod errors; diff --git a/src/prelude.rs b/src/prelude.rs index ee244451..3b2032d9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -6,7 +6,7 @@ pub use crate::{ exit, next, DialogueDispatcher, DialogueStage, DialogueWithCx, GetChatId, Transition, TransitionIn, TransitionOut, }, - repl, Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx, + Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx, }, error_handlers::{LoggingErrorHandler, OnError}, requests::{Request, ResponseResult}, From 1989dcbe04e25d5aac5251c216b9ee1ff067ea5e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 19:29:39 +0600 Subject: [PATCH 08/99] UpdateWithCx::send_dice -> answer_dice --- README.md | 2 +- examples/dices_bot/src/main.rs | 2 +- src/dispatching/update_with_cx.rs | 2 +- src/lib.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5c470204..13d56758 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ async fn main() { let bot = Bot::from_env(); teloxide::repl(bot, |message| async move { - message.send_dice().send().await?; + message.answer_dice().send().await?; Ok(()) }) .await; diff --git a/examples/dices_bot/src/main.rs b/examples/dices_bot/src/main.rs index 9768398e..e73b4197 100644 --- a/examples/dices_bot/src/main.rs +++ b/examples/dices_bot/src/main.rs @@ -14,7 +14,7 @@ async fn run() { let bot = Bot::from_env(); teloxide::repl(bot, |message| async move { - message.send_dice().send().await?; + message.answer_dice().send().await?; Ok(()) }) .await; diff --git a/src/dispatching/update_with_cx.rs b/src/dispatching/update_with_cx.rs index b16f19a4..66c0beec 100644 --- a/src/dispatching/update_with_cx.rs +++ b/src/dispatching/update_with_cx.rs @@ -154,7 +154,7 @@ impl UpdateWithCx { self.bot.pin_chat_message(self.update.chat.id, self.update.id) } - pub fn send_dice(&self) -> SendDice { + pub fn answer_dice(&self) -> SendDice { self.bot.send_dice(self.update.chat.id) } } diff --git a/src/lib.rs b/src/lib.rs index a72798ad..bb0c071f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ //! let bot = Bot::from_env(); //! //! teloxide::repl(bot, |message| async move { -//! message.send_dice().send().await?; +//! message.answer_dice().send().await?; //! Ok(()) //! }) //! .await; From c39586ef10647dc4e5b5b685cd27aae4857b228e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 20:07:46 +0600 Subject: [PATCH 09/99] Add commands_repl --- README.md | 16 +++----- examples/admin_bot/src/main.rs | 14 +------ examples/simple_commands_bot/src/main.rs | 10 +---- src/dispatching/commands_repl.rs | 47 ++++++++++++++++++++++++ src/dispatching/mod.rs | 2 + src/dispatching/repl.rs | 6 ++- src/lib.rs | 2 +- 7 files changed, 62 insertions(+), 35 deletions(-) create mode 100644 src/dispatching/commands_repl.rs diff --git a/README.md b/README.md index 13d56758..eb1abe58 100644 --- a/README.md +++ b/README.md @@ -156,19 +156,15 @@ async fn answer(cx: UpdateWithCx, command: Command) -> ResponseResult<( Ok(()) } -async fn handle_commands(rx: DispatcherHandlerRx) { - rx.commands::(panic!("Insert here your bot's name")) - .for_each_concurrent(None, |(cx, command)| async move { - answer(cx, command).await.log_on_error().await; - }) - .await; -} - #[tokio::main] async fn main() { - // Setup is omitted... -} + teloxide::enable_logging!(); + log::info!("Starting simple_commands_bot..."); + let bot = Bot::from_env(); + + teloxide::commands_repl(bot, panic!("Insert here your bot's name"), answer).await; +} ```
diff --git a/examples/admin_bot/src/main.rs b/examples/admin_bot/src/main.rs index 78c51cb4..76eed1c7 100644 --- a/examples/admin_bot/src/main.rs +++ b/examples/admin_bot/src/main.rs @@ -2,8 +2,6 @@ use std::str::FromStr; use teloxide::{prelude::*, types::ChatPermissions, utils::command::BotCommand}; -use futures::future; - // Derive BotCommand to parse text with a command into this enumeration. // // 1. rename = "lowercase" turns all the commands into lowercase letters. @@ -130,16 +128,6 @@ async fn action(cx: UpdateWithCx, command: Command) -> ResponseResult<( Ok(()) } -async fn handle_commands(rx: DispatcherHandlerRx) { - rx.filter(|cx| future::ready(cx.update.chat.is_group())) - .commands::(panic!("Insert here your bot's name")) - // Execute all incoming commands concurrently: - .for_each_concurrent(None, |(cx, command)| async move { - action(cx, command).await.log_on_error().await; - }) - .await; -} - #[tokio::main] async fn main() { run().await; @@ -151,5 +139,5 @@ async fn run() { let bot = Bot::from_env(); - Dispatcher::new(bot).messages_handler(handle_commands).dispatch().await + teloxide::commands_repl(bot, panic!("Insert here your bot's name"), action).await; } diff --git a/examples/simple_commands_bot/src/main.rs b/examples/simple_commands_bot/src/main.rs index 1bdf7d5e..241ad2c0 100644 --- a/examples/simple_commands_bot/src/main.rs +++ b/examples/simple_commands_bot/src/main.rs @@ -25,14 +25,6 @@ async fn answer(cx: UpdateWithCx, command: Command) -> ResponseResult<( Ok(()) } -async fn handle_commands(rx: DispatcherHandlerRx) { - rx.commands::(panic!("Insert here your bot's name")) - .for_each_concurrent(None, |(cx, command)| async move { - answer(cx, command).await.log_on_error().await; - }) - .await; -} - #[tokio::main] async fn main() { run().await; @@ -44,5 +36,5 @@ async fn run() { let bot = Bot::from_env(); - Dispatcher::new(bot).messages_handler(handle_commands).dispatch().await; + teloxide::commands_repl(bot, panic!("Insert here your bot's name"), answer).await; } diff --git a/src/dispatching/commands_repl.rs b/src/dispatching/commands_repl.rs new file mode 100644 index 00000000..e9587008 --- /dev/null +++ b/src/dispatching/commands_repl.rs @@ -0,0 +1,47 @@ +use crate::{ + dispatching::{Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx}, + error_handlers::OnError, + requests::ResponseResult, + types::Message, + utils::command::BotCommand, + Bot, +}; +use futures::StreamExt; +use std::{future::Future, sync::Arc}; + +/// A [REPL] for commands. +/// +/// Used mostly for testing and demonstrative purposes. +/// +/// # Caution +/// **DO NOT** use this function together with [`Dispatcher`] and [`repl`], +/// because Telegram disallow multiple requests at the same time from the same +/// bot. +/// +/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop +/// [`Dispatcher`]: crate::dispatching::Dispatcher +/// [`repl`]: crate::dispatching::repl +pub async fn commands_repl(bot: Bot, bot_name: &'static str, handler: H) +where + Cmd: BotCommand + Send + 'static, + H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + 'static, +{ + let handler = Arc::new(handler); + + Dispatcher::new(bot) + .messages_handler(move |rx: DispatcherHandlerRx| { + rx.commands::(bot_name).for_each_concurrent( + None, + move |(cx, cmd)| { + let handler = Arc::clone(&handler); + + async move { + handler(cx, cmd).await.log_on_error().await; + } + }, + ) + }) + .dispatch() + .await; +} diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index 02306349..d137d84c 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -43,6 +43,7 @@ //! [`tokio::sync::mpsc::UnboundedReceiver`]: https://docs.rs/tokio/0.2.11/tokio/sync/mpsc/struct.UnboundedReceiver.html //! [examples/dialogue_bot]: https://github.com/teloxide/teloxide/tree/master/examples/dialogue_bot +mod commands_repl; pub mod dialogue; mod dispatcher; mod dispatcher_handler; @@ -51,6 +52,7 @@ mod repl; pub mod update_listeners; mod update_with_cx; +pub use commands_repl::commands_repl; pub use dispatcher::Dispatcher; pub use dispatcher_handler::DispatcherHandler; pub use dispatcher_handler_rx_ext::DispatcherHandlerRxExt; diff --git a/src/dispatching/repl.rs b/src/dispatching/repl.rs index d138f402..3b3b9b2f 100644 --- a/src/dispatching/repl.rs +++ b/src/dispatching/repl.rs @@ -13,11 +13,13 @@ use std::{future::Future, sync::Arc}; /// Used mostly for testing and demonstrative purposes. /// /// # Caution -/// **DO NOT** use this function together with [`Dispatcher`], because Telegram -/// disallow multiple requests at the same time from the same bot. +/// **DO NOT** use this function together with [`Dispatcher`] and +/// [`commands_repl`], because Telegram disallow multiple requests at the same +/// time from the same bot. /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher +/// [`commands_repl`]: crate::dispatching::commands_repl pub async fn repl(bot: Bot, handler: H) where H: Fn(UpdateWithCx) -> Fut + Send + Sync + 'static, diff --git a/src/lib.rs b/src/lib.rs index bb0c071f..07f54b1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ #![forbid(unsafe_code)] pub use bot::{Bot, BotBuilder}; -pub use dispatching::repl; +pub use dispatching::{commands_repl, repl}; pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError}; mod errors; From 3cef2f9ca80f04e9fab01a653817f3de9bdd15fd Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 20:22:31 +0600 Subject: [PATCH 10/99] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f0eff69..082f78a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,11 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgrade to v4.9 Telegram bots API. - `teloxide::utils::client_from_env` -- constructs a client from the `TELOXIDE_TOKEN` environmental variable. - Import `Transition`, `TransitionIn`, `TransitionOut`, `UpState` to `teloxide::prelude`. - - Import `repl` to `teloxide`. + - Import `repl`, `commands_repl` to `teloxide`. - Let users inspect an unknown API error using `ApiErrorKind::Unknown(String)`. All the known API errors are placed into `KnownApiErrorKind`. - Setters to all the API types. - `teloxide::dispatching::dialogue::serializer` -- various serializers for memory storages. The `Serializer` trait, `Bincode`, `CBOR`, `JSON`. - - `teloxide::dispatching::repl` + - `teloxide::dispatching::{repl, commands_repl` ### Deprecated - `Bot::{from_env_with_client, new, with_client}` From ce32f75beda15c34d2d7ae54ecfd6be7b1275966 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 20:23:31 +0600 Subject: [PATCH 11/99] repl & commands_repl are not only for demonstrative purposes --- src/dispatching/commands_repl.rs | 2 -- src/dispatching/repl.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/dispatching/commands_repl.rs b/src/dispatching/commands_repl.rs index e9587008..e31db3d7 100644 --- a/src/dispatching/commands_repl.rs +++ b/src/dispatching/commands_repl.rs @@ -11,8 +11,6 @@ use std::{future::Future, sync::Arc}; /// A [REPL] for commands. /// -/// Used mostly for testing and demonstrative purposes. -/// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and [`repl`], /// because Telegram disallow multiple requests at the same time from the same diff --git a/src/dispatching/repl.rs b/src/dispatching/repl.rs index 3b3b9b2f..31577939 100644 --- a/src/dispatching/repl.rs +++ b/src/dispatching/repl.rs @@ -10,8 +10,6 @@ use std::{future::Future, sync::Arc}; /// A [REPL] for messages. /// -/// Used mostly for testing and demonstrative purposes. -/// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and /// [`commands_repl`], because Telegram disallow multiple requests at the same From cfb78097b22cbca8fc58610b63d3b8e0f27dad6f Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 20:24:44 +0600 Subject: [PATCH 12/99] Don't import 'futures' by default (README.md) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index eb1abe58..790828be 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,6 @@ log = "0.4.8" pretty_env_logger = "0.4.0" tokio = "0.2.11" -futures = "0.3.5" ``` ## API overview From 1ab789fd7173dcfb3cdaa95a912ffaf4b1562a9f Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 23:30:28 +0600 Subject: [PATCH 13/99] Add commands_repl_with_listener --- src/dispatching/commands_repl.rs | 79 ++++++++++++++++++++++++-------- src/dispatching/mod.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/dispatching/commands_repl.rs b/src/dispatching/commands_repl.rs index e31db3d7..c4f0f89d 100644 --- a/src/dispatching/commands_repl.rs +++ b/src/dispatching/commands_repl.rs @@ -1,45 +1,84 @@ use crate::{ - dispatching::{Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx}, - error_handlers::OnError, + dispatching::{ + update_listeners, update_listeners::UpdateListener, Dispatcher, DispatcherHandlerRx, + DispatcherHandlerRxExt, UpdateWithCx, + }, + error_handlers::{LoggingErrorHandler, OnError}, requests::ResponseResult, types::Message, utils::command::BotCommand, Bot, }; -use futures::StreamExt; -use std::{future::Future, sync::Arc}; +use futures::{future::BoxFuture, FutureExt, StreamExt}; +use std::{fmt::Debug, future::Future, sync::Arc}; /// A [REPL] for commands. /// /// # Caution -/// **DO NOT** use this function together with [`Dispatcher`] and [`repl`], +/// **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 /// [`Dispatcher`]: crate::dispatching::Dispatcher -/// [`repl`]: crate::dispatching::repl -pub async fn commands_repl(bot: Bot, bot_name: &'static str, handler: H) +pub fn commands_repl( + bot: Bot, + bot_name: &'static str, + handler: H, +) -> BoxFuture<'static, ()> where Cmd: BotCommand + Send + 'static, H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, Fut: Future> + Send + 'static, +{ + let cloned_bot = bot.clone(); + + commands_repl_with_listener( + bot, + bot_name, + handler, + update_listeners::polling_default(cloned_bot), + ) +} + +/// Like [`commands_repl`], but with a custom [`UpdateListener`]. +/// +/// [`commands_repl`]: crate::dispatching::commands_repl +/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener +pub fn commands_repl_with_listener<'a, Cmd, H, Fut, UL, ListenerE>( + bot: Bot, + bot_name: &'static str, + handler: H, + update_listener: UL, +) -> BoxFuture<'a, ()> +where + Cmd: BotCommand + Send + 'static, + H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + 'static, + UL: UpdateListener + Send + 'a, + ListenerE: Debug + Send + 'a, { let handler = Arc::new(handler); - Dispatcher::new(bot) - .messages_handler(move |rx: DispatcherHandlerRx| { - rx.commands::(bot_name).for_each_concurrent( - None, - move |(cx, cmd)| { - let handler = Arc::clone(&handler); + async move { + Dispatcher::new(bot) + .messages_handler(move |rx: DispatcherHandlerRx| { + rx.commands::(bot_name).for_each_concurrent( + None, + move |(cx, cmd)| { + let handler = Arc::clone(&handler); - async move { - handler(cx, cmd).await.log_on_error().await; - } - }, + async move { + handler(cx, cmd).await.log_on_error().await; + } + }, + ) + }) + .dispatch_with_listener( + update_listener, + LoggingErrorHandler::with_custom_text("An error from the update listener"), ) - }) - .dispatch() - .await; + .await + } + .boxed() } diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index d137d84c..eae08f1f 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -52,7 +52,7 @@ mod repl; pub mod update_listeners; mod update_with_cx; -pub use commands_repl::commands_repl; +pub use commands_repl::{commands_repl, commands_repl_with_listener}; pub use dispatcher::Dispatcher; pub use dispatcher_handler::DispatcherHandler; pub use dispatcher_handler_rx_ext::DispatcherHandlerRxExt; diff --git a/src/lib.rs b/src/lib.rs index 07f54b1c..6e379d13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ #![forbid(unsafe_code)] pub use bot::{Bot, BotBuilder}; -pub use dispatching::{commands_repl, repl}; +pub use dispatching::{commands_repl, commands_repl_with_listener, repl}; pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError}; mod errors; From 2849c1cbdef3810944ea74c6cf80f99c5fd089dd Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 30 Jul 2020 23:52:10 +0600 Subject: [PATCH 14/99] Fix the docs of REPLs --- src/dispatching/commands_repl.rs | 8 +++++++- src/dispatching/repl.rs | 7 +++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/dispatching/commands_repl.rs b/src/dispatching/commands_repl.rs index c4f0f89d..dd6964b7 100644 --- a/src/dispatching/commands_repl.rs +++ b/src/dispatching/commands_repl.rs @@ -43,7 +43,13 @@ where /// Like [`commands_repl`], but with a custom [`UpdateListener`]. /// -/// [`commands_repl`]: crate::dispatching::commands_repl +/// # 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 +/// [`commands_repl`]: crate::dispatching::commands_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener pub fn commands_repl_with_listener<'a, Cmd, H, Fut, UL, ListenerE>( bot: Bot, diff --git a/src/dispatching/repl.rs b/src/dispatching/repl.rs index 31577939..5c3bf7e8 100644 --- a/src/dispatching/repl.rs +++ b/src/dispatching/repl.rs @@ -11,13 +11,12 @@ use std::{future::Future, sync::Arc}; /// A [REPL] for messages. /// /// # Caution -/// **DO NOT** use this function together with [`Dispatcher`] and -/// [`commands_repl`], because Telegram disallow multiple requests at the same -/// time from the same bot. +/// **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 /// [`Dispatcher`]: crate::dispatching::Dispatcher -/// [`commands_repl`]: crate::dispatching::commands_repl pub async fn repl(bot: Bot, handler: H) where H: Fn(UpdateWithCx) -> Fut + Send + Sync + 'static, From 02c71f72cba05a75e26b74d30de9e7f6f3bd562a Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 00:16:21 +0600 Subject: [PATCH 15/99] Use the generic HandlerE in REPLs --- README.md | 2 +- examples/dices_bot/src/main.rs | 2 +- src/dispatching/commands_repl.rs | 17 ++++++++++++----- src/dispatching/repl.rs | 11 +++++++---- src/lib.rs | 2 +- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 790828be..bc32b491 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ async fn main() { teloxide::repl(bot, |message| async move { message.answer_dice().send().await?; - Ok(()) + ResponseResult::<()>::Ok(()) }) .await; } diff --git a/examples/dices_bot/src/main.rs b/examples/dices_bot/src/main.rs index e73b4197..ea7f4424 100644 --- a/examples/dices_bot/src/main.rs +++ b/examples/dices_bot/src/main.rs @@ -15,7 +15,7 @@ async fn run() { teloxide::repl(bot, |message| async move { message.answer_dice().send().await?; - Ok(()) + ResponseResult::<()>::Ok(()) }) .await; } diff --git a/src/dispatching/commands_repl.rs b/src/dispatching/commands_repl.rs index dd6964b7..ba801445 100644 --- a/src/dispatching/commands_repl.rs +++ b/src/dispatching/commands_repl.rs @@ -4,7 +4,6 @@ use crate::{ DispatcherHandlerRxExt, UpdateWithCx, }, error_handlers::{LoggingErrorHandler, OnError}, - requests::ResponseResult, types::Message, utils::command::BotCommand, Bot, @@ -14,6 +13,8 @@ use std::{fmt::Debug, future::Future, sync::Arc}; /// A [REPL] for commands. /// +/// All errors from an update listener will be logged. +/// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and other REPLs, /// because Telegram disallow multiple requests at the same time from the same @@ -21,7 +22,7 @@ use std::{fmt::Debug, future::Future, sync::Arc}; /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher -pub fn commands_repl( +pub fn commands_repl( bot: Bot, bot_name: &'static str, handler: H, @@ -29,7 +30,9 @@ pub fn commands_repl( where Cmd: BotCommand + Send + 'static, H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + 'static, + Fut: Future> + Send + 'static, + Result<(), HandlerE>: OnError, + HandlerE: Debug + Send, { let cloned_bot = bot.clone(); @@ -43,6 +46,8 @@ where /// Like [`commands_repl`], but with a custom [`UpdateListener`]. /// +/// All errors from an update listener will be logged. +/// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and other REPLs, /// because Telegram disallow multiple requests at the same time from the same @@ -51,7 +56,7 @@ where /// [`Dispatcher`]: crate::dispatching::Dispatcher /// [`commands_repl`]: crate::dispatching::commands_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener -pub fn commands_repl_with_listener<'a, Cmd, H, Fut, UL, ListenerE>( +pub fn commands_repl_with_listener<'a, Cmd, H, Fut, UL, ListenerE, HandlerE>( bot: Bot, bot_name: &'static str, handler: H, @@ -60,9 +65,11 @@ pub fn commands_repl_with_listener<'a, Cmd, H, Fut, UL, ListenerE>( where Cmd: BotCommand + Send + 'static, H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + 'static, + Fut: Future> + Send + 'static, UL: UpdateListener + Send + 'a, ListenerE: Debug + Send + 'a, + Result<(), HandlerE>: OnError, + HandlerE: Debug + Send, { let handler = Arc::new(handler); diff --git a/src/dispatching/repl.rs b/src/dispatching/repl.rs index 5c3bf7e8..f9fa3019 100644 --- a/src/dispatching/repl.rs +++ b/src/dispatching/repl.rs @@ -1,15 +1,16 @@ use crate::{ dispatching::{Dispatcher, DispatcherHandlerRx, UpdateWithCx}, error_handlers::OnError, - requests::ResponseResult, types::Message, Bot, }; use futures::StreamExt; -use std::{future::Future, sync::Arc}; +use std::{fmt::Debug, future::Future, sync::Arc}; /// A [REPL] for messages. /// +/// All errors from an update listener will be logged. +/// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and other REPLs, /// because Telegram disallow multiple requests at the same time from the same @@ -17,10 +18,12 @@ use std::{future::Future, sync::Arc}; /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher -pub async fn repl(bot: Bot, handler: H) +pub async fn repl(bot: Bot, handler: H) where H: Fn(UpdateWithCx) -> Fut + Send + Sync + 'static, - Fut: Future> + Send + 'static, + Fut: Future> + Send + 'static, + Result<(), E>: OnError, + E: Debug + Send, { let handler = Arc::new(handler); diff --git a/src/lib.rs b/src/lib.rs index 6e379d13..4b0542c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ //! //! teloxide::repl(bot, |message| async move { //! message.answer_dice().send().await?; -//! Ok(()) +//! ResponseResult::<()>::Ok(()) //! }) //! .await; //! # } From f29138f4975771ba8ef7013f73860a8f1090add4 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 00:29:31 +0600 Subject: [PATCH 16/99] Add repl_with_listener --- src/dispatching/commands_repl.rs | 57 ++++++++++++++------------------ src/dispatching/mod.rs | 2 +- src/dispatching/repl.rs | 25 ++++++++++++-- src/lib.rs | 2 +- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/dispatching/commands_repl.rs b/src/dispatching/commands_repl.rs index ba801445..09323799 100644 --- a/src/dispatching/commands_repl.rs +++ b/src/dispatching/commands_repl.rs @@ -8,12 +8,12 @@ use crate::{ utils::command::BotCommand, Bot, }; -use futures::{future::BoxFuture, FutureExt, StreamExt}; +use futures::StreamExt; use std::{fmt::Debug, future::Future, sync::Arc}; /// A [REPL] for commands. /// -/// All errors from an update listener will be logged. +/// All errors from an update listener and handler will be logged. /// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and other REPLs, @@ -22,11 +22,7 @@ use std::{fmt::Debug, future::Future, sync::Arc}; /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher -pub fn commands_repl( - bot: Bot, - bot_name: &'static str, - handler: H, -) -> BoxFuture<'static, ()> +pub async fn commands_repl(bot: Bot, bot_name: &'static str, handler: H) where Cmd: BotCommand + Send + 'static, H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, @@ -42,11 +38,12 @@ where handler, update_listeners::polling_default(cloned_bot), ) + .await; } /// Like [`commands_repl`], but with a custom [`UpdateListener`]. /// -/// All errors from an update listener will be logged. +/// All errors from an update listener and handler will be logged. /// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and other REPLs, @@ -56,42 +53,38 @@ where /// [`Dispatcher`]: crate::dispatching::Dispatcher /// [`commands_repl`]: crate::dispatching::commands_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener -pub fn commands_repl_with_listener<'a, Cmd, H, Fut, UL, ListenerE, HandlerE>( +pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE>( bot: Bot, bot_name: &'static str, handler: H, - update_listener: UL, -) -> BoxFuture<'a, ()> -where + listener: L, +) where Cmd: BotCommand + Send + 'static, H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, Fut: Future> + Send + 'static, - UL: UpdateListener + Send + 'a, + L: UpdateListener + Send + 'a, ListenerE: Debug + Send + 'a, Result<(), HandlerE>: OnError, HandlerE: Debug + Send, { let handler = Arc::new(handler); - async move { - Dispatcher::new(bot) - .messages_handler(move |rx: DispatcherHandlerRx| { - rx.commands::(bot_name).for_each_concurrent( - None, - move |(cx, cmd)| { - let handler = Arc::clone(&handler); + Dispatcher::new(bot) + .messages_handler(move |rx: DispatcherHandlerRx| { + rx.commands::(bot_name).for_each_concurrent( + None, + move |(cx, cmd)| { + let handler = Arc::clone(&handler); - async move { - handler(cx, cmd).await.log_on_error().await; - } - }, - ) - }) - .dispatch_with_listener( - update_listener, - LoggingErrorHandler::with_custom_text("An error from the update listener"), + async move { + handler(cx, cmd).await.log_on_error().await; + } + }, ) - .await - } - .boxed() + }) + .dispatch_with_listener( + listener, + LoggingErrorHandler::with_custom_text("An error from the update listener"), + ) + .await } diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index eae08f1f..685ef6a6 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -56,7 +56,7 @@ pub use commands_repl::{commands_repl, commands_repl_with_listener}; pub use dispatcher::Dispatcher; pub use dispatcher_handler::DispatcherHandler; pub use dispatcher_handler_rx_ext::DispatcherHandlerRxExt; -pub use repl::repl; +pub use repl::{repl, repl_with_listener}; use tokio::sync::mpsc::UnboundedReceiver; pub use update_with_cx::UpdateWithCx; diff --git a/src/dispatching/repl.rs b/src/dispatching/repl.rs index f9fa3019..117b87cb 100644 --- a/src/dispatching/repl.rs +++ b/src/dispatching/repl.rs @@ -1,6 +1,9 @@ use crate::{ - dispatching::{Dispatcher, DispatcherHandlerRx, UpdateWithCx}, - error_handlers::OnError, + dispatching::{ + update_listeners, update_listeners::UpdateListener, Dispatcher, DispatcherHandlerRx, + UpdateWithCx, + }, + error_handlers::{LoggingErrorHandler, OnError}, types::Message, Bot, }; @@ -24,6 +27,19 @@ where Fut: Future> + Send + 'static, Result<(), E>: OnError, E: Debug + Send, +{ + let cloned_bot = bot.clone(); + repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot)).await; +} + +pub async fn repl_with_listener<'a, H, Fut, E, L, ListenerE>(bot: Bot, handler: H, listener: L) +where + H: Fn(UpdateWithCx) -> Fut + Send + Sync + 'static, + Fut: Future> + Send + 'static, + L: UpdateListener + Send + 'a, + ListenerE: Debug, + Result<(), E>: OnError, + E: Debug + Send, { let handler = Arc::new(handler); @@ -37,6 +53,9 @@ where } }) }) - .dispatch() + .dispatch_with_listener( + listener, + LoggingErrorHandler::with_custom_text("An error from the update listener"), + ) .await; } diff --git a/src/lib.rs b/src/lib.rs index 4b0542c6..2e2afb27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ #![forbid(unsafe_code)] pub use bot::{Bot, BotBuilder}; -pub use dispatching::{commands_repl, commands_repl_with_listener, repl}; +pub use dispatching::{commands_repl, commands_repl_with_listener, repl, repl_with_listener}; pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError}; mod errors; From 90338f9bace91b5c7c3ef1ceb6ae3d07f3130fb8 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 00:38:37 +0600 Subject: [PATCH 17/99] Update examples/heroku_ping_pong_bot & ngrok --- examples/heroku_ping_pong_bot/src/main.rs | 21 ++++++++++----------- examples/ngrok_ping_pong_bot/src/main.rs | 21 ++++++++++----------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/examples/heroku_ping_pong_bot/src/main.rs b/examples/heroku_ping_pong_bot/src/main.rs index daec468a..23bae8f6 100644 --- a/examples/heroku_ping_pong_bot/src/main.rs +++ b/examples/heroku_ping_pong_bot/src/main.rs @@ -73,15 +73,14 @@ async fn run() { let bot = Bot::from_env(); - Dispatcher::new(bot.clone()) - .messages_handler(|rx: DispatcherHandlerRx| { - rx.for_each(|message| async move { - message.answer_str("pong").await.log_on_error().await; - }) - }) - .dispatch_with_listener( - webhook(bot).await, - LoggingErrorHandler::with_custom_text("An error from the update listener"), - ) - .await; + let cloned_bot = bot.clone(); + teloxide::repl_with_listener( + bot, + |message| async move { + message.answer_str("pong").await?; + ResponseResult::<()>::Ok(()) + }, + webhook(cloned_bot).await, + ) + .await; } diff --git a/examples/ngrok_ping_pong_bot/src/main.rs b/examples/ngrok_ping_pong_bot/src/main.rs index 0c9b278b..0fb745fb 100644 --- a/examples/ngrok_ping_pong_bot/src/main.rs +++ b/examples/ngrok_ping_pong_bot/src/main.rs @@ -55,15 +55,14 @@ async fn run() { let bot = Bot::from_env(); - Dispatcher::new(bot.clone()) - .messages_handler(|rx: DispatcherHandlerRx| { - rx.for_each(|message| async move { - message.answer_str("pong").await.log_on_error().await; - }) - }) - .dispatch_with_listener( - webhook(bot).await, - LoggingErrorHandler::with_custom_text("An error from the update listener"), - ) - .await; + let cloned_bot = bot.clone(); + teloxide::repl_with_listener( + bot, + |message| async move { + message.answer_str("pong").await?; + ResponseResult::<()>::Ok(()) + }, + webhook(cloned_bot).await, + ) + .await; } From f5c7da2610cb18c3cd30faf37249ea3ad4706341 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 00:45:31 +0600 Subject: [PATCH 18/99] Document repl_with_listener --- src/dispatching/repl.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/dispatching/repl.rs b/src/dispatching/repl.rs index 117b87cb..49673857 100644 --- a/src/dispatching/repl.rs +++ b/src/dispatching/repl.rs @@ -12,7 +12,7 @@ use std::{fmt::Debug, future::Future, sync::Arc}; /// A [REPL] for messages. /// -/// All errors from an update listener will be logged. +/// All errors from an update listener and a handler will be logged. /// /// # Caution /// **DO NOT** use this function together with [`Dispatcher`] and other REPLs, @@ -32,6 +32,18 @@ where repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot)).await; } +/// Like [`repl`], but with a custom [`UpdateListener`]. +/// +/// All errors from an update listener and handler will be logged. +/// +/// # 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::repl() +/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener pub async fn repl_with_listener<'a, H, Fut, E, L, ListenerE>(bot: Bot, handler: H, listener: L) where H: Fn(UpdateWithCx) -> Fut + Send + Sync + 'static, From 7097dd4f34ea5df6a5f054c6304e5d80e950fb66 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 00:47:26 +0600 Subject: [PATCH 19/99] 'Insert here your bot's name' -> 'Your bot's name here' --- README.md | 2 +- examples/admin_bot/src/main.rs | 2 +- examples/simple_commands_bot/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bc32b491..eb20e9be 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ async fn main() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, panic!("Insert here your bot's name"), answer).await; + teloxide::commands_repl(bot, panic!("Your bot's name here"), answer).await; } ``` diff --git a/examples/admin_bot/src/main.rs b/examples/admin_bot/src/main.rs index 76eed1c7..ea4f9078 100644 --- a/examples/admin_bot/src/main.rs +++ b/examples/admin_bot/src/main.rs @@ -139,5 +139,5 @@ async fn run() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, panic!("Insert here your bot's name"), action).await; + teloxide::commands_repl(bot, panic!("Your bot's name here"), action).await; } diff --git a/examples/simple_commands_bot/src/main.rs b/examples/simple_commands_bot/src/main.rs index 241ad2c0..24b88345 100644 --- a/examples/simple_commands_bot/src/main.rs +++ b/examples/simple_commands_bot/src/main.rs @@ -36,5 +36,5 @@ async fn run() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, panic!("Insert here your bot's name"), answer).await; + teloxide::commands_repl(bot, panic!("Your bot's name here"), answer).await; } From 62bf55c8e6ff1e6b45b20d8dfdf70cbf0e5ee9b8 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 00:56:39 +0600 Subject: [PATCH 20/99] Don't export REPLs to teloxide::dispatching --- src/dispatching/mod.rs | 5 +---- src/dispatching/{ => repls}/commands_repl.rs | 2 +- src/dispatching/repls/mod.rs | 5 +++++ src/dispatching/{ => repls}/repl.rs | 2 +- src/lib.rs | 4 +++- 5 files changed, 11 insertions(+), 7 deletions(-) rename src/dispatching/{ => repls}/commands_repl.rs (97%) create mode 100644 src/dispatching/repls/mod.rs rename src/dispatching/{ => repls}/repl.rs (98%) diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs index 685ef6a6..05e367dd 100644 --- a/src/dispatching/mod.rs +++ b/src/dispatching/mod.rs @@ -43,20 +43,17 @@ //! [`tokio::sync::mpsc::UnboundedReceiver`]: https://docs.rs/tokio/0.2.11/tokio/sync/mpsc/struct.UnboundedReceiver.html //! [examples/dialogue_bot]: https://github.com/teloxide/teloxide/tree/master/examples/dialogue_bot -mod commands_repl; pub mod dialogue; mod dispatcher; mod dispatcher_handler; mod dispatcher_handler_rx_ext; -mod repl; +pub(crate) mod repls; pub mod update_listeners; mod update_with_cx; -pub use commands_repl::{commands_repl, commands_repl_with_listener}; pub use dispatcher::Dispatcher; pub use dispatcher_handler::DispatcherHandler; pub use dispatcher_handler_rx_ext::DispatcherHandlerRxExt; -pub use repl::{repl, repl_with_listener}; use tokio::sync::mpsc::UnboundedReceiver; pub use update_with_cx::UpdateWithCx; diff --git a/src/dispatching/commands_repl.rs b/src/dispatching/repls/commands_repl.rs similarity index 97% rename from src/dispatching/commands_repl.rs rename to src/dispatching/repls/commands_repl.rs index 09323799..c842fd7a 100644 --- a/src/dispatching/commands_repl.rs +++ b/src/dispatching/repls/commands_repl.rs @@ -51,7 +51,7 @@ where /// bot. /// /// [`Dispatcher`]: crate::dispatching::Dispatcher -/// [`commands_repl`]: crate::dispatching::commands_repl() +/// [`commands_repl`]: crate::dispatching::repls::commands_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE>( bot: Bot, diff --git a/src/dispatching/repls/mod.rs b/src/dispatching/repls/mod.rs new file mode 100644 index 00000000..29f782f7 --- /dev/null +++ b/src/dispatching/repls/mod.rs @@ -0,0 +1,5 @@ +mod commands_repl; +mod repl; + +pub use commands_repl::{commands_repl, commands_repl_with_listener}; +pub use repl::{repl, repl_with_listener}; diff --git a/src/dispatching/repl.rs b/src/dispatching/repls/repl.rs similarity index 98% rename from src/dispatching/repl.rs rename to src/dispatching/repls/repl.rs index 49673857..9a50355f 100644 --- a/src/dispatching/repl.rs +++ b/src/dispatching/repls/repl.rs @@ -42,7 +42,7 @@ where /// bot. /// /// [`Dispatcher`]: crate::dispatching::Dispatcher -/// [`repl`]: crate::dispatching::repl() +/// [`repl`]: crate::dispatching::repls::repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener pub async fn repl_with_listener<'a, H, Fut, E, L, ListenerE>(bot: Bot, handler: H, listener: L) where diff --git a/src/lib.rs b/src/lib.rs index 2e2afb27..c3ae1ef4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,9 @@ #![forbid(unsafe_code)] pub use bot::{Bot, BotBuilder}; -pub use dispatching::{commands_repl, commands_repl_with_listener, repl, repl_with_listener}; +pub use dispatching::repls::{ + commands_repl, commands_repl_with_listener, repl, repl_with_listener, +}; pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError}; mod errors; From 559d3344a2e8471aee8efd5fa853bc36e3007563 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 14:56:41 +0600 Subject: [PATCH 21/99] Attempt to develop dialogue_repl(with_listener) --- src/dispatching/repls/dialogues_repl.rs | 91 +++++++++++++++++++++++++ src/dispatching/repls/mod.rs | 2 + 2 files changed, 93 insertions(+) create mode 100644 src/dispatching/repls/dialogues_repl.rs diff --git a/src/dispatching/repls/dialogues_repl.rs b/src/dispatching/repls/dialogues_repl.rs new file mode 100644 index 00000000..16d54a55 --- /dev/null +++ b/src/dispatching/repls/dialogues_repl.rs @@ -0,0 +1,91 @@ +use crate::{ + dispatching::{ + dialogue::{DialogueDispatcher, DialogueStage, DialogueWithCx, GetChatId}, + update_listeners, + update_listeners::UpdateListener, + Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx, + }, + error_handlers::{LoggingErrorHandler, OnError}, + types::Message, + utils::command::BotCommand, + Bot, +}; +use futures::StreamExt; +use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc}; + +/// A [REPL] for dialogues. +/// +/// All errors from an update listener and handler will be logged. This function +/// uses [`InMemStorage`]. +/// +/// # 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 +/// [`Dispatcher`]: crate::dispatching::Dispatcher +pub async fn dialogues_repl<'a, H, Upd, D, Fut, HandlerE>( + bot: Bot, + bot_name: &'static str, + handler: H, +) where + H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, + D: Default + Send + 'static, + Fut: Future, HandlerE>> + Send + Sync + 'static, + Result, HandlerE>: OnError, + HandlerE: Debug + Send, +{ + let cloned_bot = bot.clone(); + + dialogues_repl_with_listener( + bot, + bot_name, + handler, + update_listeners::polling_default(cloned_bot), + ) + .await; +} + +/// Like [`dialogue_repl`], but with a custom [`UpdateListener`]. +/// +/// All errors from an update listener and handler will be logged. This function +/// uses [`InMemStorage`]. +/// +/// # 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 +/// [`dialogue_repl`]: crate::dispatching::repls::dialogue_repl() +/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener +pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE, HandlerE>( + bot: Bot, + bot_name: &'static str, + handler: H, + listener: L, +) where + H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, + D: Default + Send + 'static, + Fut: Future, HandlerE>> + Send + Sync + 'static, + L: UpdateListener + Send + 'a, + ListenerE: Debug + Send + 'a, + Result, HandlerE>: OnError, + HandlerE: Debug + Send, +{ + let handler = Arc::new(handler); + + Dispatcher::new(bot) + .messages_handler(DialogueDispatcher::new( + |DialogueWithCx { cx, dialogue }: DialogueWithCx| async move { + let dialogue = dialogue.expect("std::convert::Infallible"); + handler(cx, dialogue).await.log_on_error().await + }, + )) + .dispatch_with_listener( + listener, + LoggingErrorHandler::with_custom_text("An error from the update listener"), + ) + .await +} diff --git a/src/dispatching/repls/mod.rs b/src/dispatching/repls/mod.rs index 29f782f7..f6bf31f0 100644 --- a/src/dispatching/repls/mod.rs +++ b/src/dispatching/repls/mod.rs @@ -1,5 +1,7 @@ mod commands_repl; +mod dialogues_repl; mod repl; pub use commands_repl::{commands_repl, commands_repl_with_listener}; +pub use dialogues_repl::{dialogues_repl, dialogues_repl_with_listener}; pub use repl::{repl, repl_with_listener}; From 9115622ee370b64a6e0b2d3b76eb47d12d1621a9 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 16:01:13 +0600 Subject: [PATCH 22/99] Fix a typo in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb20e9be..5ff8225d 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ ## Highlights - - **Functioal reactive design.** teloxide has [functional reactive design], allowing you to declaratively manipulate streams of updates from Telegram using filters, maps, folds, zips, and a lot of [other adaptors]. + - **Functional reactive design.** teloxide has [functional reactive design], allowing you to declaratively manipulate streams of updates from Telegram using filters, maps, folds, zips, and a lot of [other adaptors]. [functional reactive design]: https://en.wikipedia.org/wiki/Functional_reactive_programming [other adaptors]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html From 3e01e0f65fb0fcab5573979981db035f2174a980 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 16:16:14 +0600 Subject: [PATCH 23/99] Remove Arc from dialogues_repl --- src/dispatching/repls/dialogues_repl.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/dispatching/repls/dialogues_repl.rs b/src/dispatching/repls/dialogues_repl.rs index 16d54a55..672afe13 100644 --- a/src/dispatching/repls/dialogues_repl.rs +++ b/src/dispatching/repls/dialogues_repl.rs @@ -1,17 +1,15 @@ use crate::{ dispatching::{ - dialogue::{DialogueDispatcher, DialogueStage, DialogueWithCx, GetChatId}, + dialogue::{DialogueDispatcher, DialogueStage, DialogueWithCx}, update_listeners, update_listeners::UpdateListener, - Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx, + Dispatcher, UpdateWithCx, }, error_handlers::{LoggingErrorHandler, OnError}, types::Message, - utils::command::BotCommand, Bot, }; -use futures::StreamExt; -use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc}; +use std::{convert::Infallible, fmt::Debug, future::Future}; /// A [REPL] for dialogues. /// @@ -74,8 +72,6 @@ pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE, HandlerE> Result, HandlerE>: OnError, HandlerE: Debug + Send, { - let handler = Arc::new(handler); - Dispatcher::new(bot) .messages_handler(DialogueDispatcher::new( |DialogueWithCx { cx, dialogue }: DialogueWithCx| async move { From fda07ddd15917b29c58cef99338898db421c85ce Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 16:18:23 +0600 Subject: [PATCH 24/99] Fix one compilation error --- src/dispatching/repls/dialogues_repl.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/dispatching/repls/dialogues_repl.rs b/src/dispatching/repls/dialogues_repl.rs index 672afe13..89bad804 100644 --- a/src/dispatching/repls/dialogues_repl.rs +++ b/src/dispatching/repls/dialogues_repl.rs @@ -23,12 +23,9 @@ use std::{convert::Infallible, fmt::Debug, future::Future}; /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher -pub async fn dialogues_repl<'a, H, Upd, D, Fut, HandlerE>( - bot: Bot, - bot_name: &'static str, - handler: H, -) where - H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, +pub async fn dialogues_repl<'a, H, D, Fut, HandlerE>(bot: Bot, bot_name: &'static str, handler: H) +where + H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, D: Default + Send + 'static, Fut: Future, HandlerE>> + Send + Sync + 'static, Result, HandlerE>: OnError, From 114267f14c3408d48d27e46edf65e8551613e65e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 17:40:02 +0600 Subject: [PATCH 25/99] Push code --- src/dispatching/repls/dialogues_repl.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/dispatching/repls/dialogues_repl.rs b/src/dispatching/repls/dialogues_repl.rs index 89bad804..91ebc60b 100644 --- a/src/dispatching/repls/dialogues_repl.rs +++ b/src/dispatching/repls/dialogues_repl.rs @@ -55,7 +55,7 @@ where /// [`Dispatcher`]: crate::dispatching::Dispatcher /// [`dialogue_repl`]: crate::dispatching::repls::dialogue_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener -pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE, HandlerE>( +pub async fn dialogues_repl_with_listener<'a, H, D, Fut, HandlerE, L, ListenerE>( bot: Bot, bot_name: &'static str, handler: H, @@ -69,16 +69,14 @@ pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE, HandlerE> Result, HandlerE>: OnError, HandlerE: Debug + Send, { - Dispatcher::new(bot) - .messages_handler(DialogueDispatcher::new( - |DialogueWithCx { cx, dialogue }: DialogueWithCx| async move { - let dialogue = dialogue.expect("std::convert::Infallible"); - handler(cx, dialogue).await.log_on_error().await - }, - )) + Dispatcher::new(todo!()) + .messages_handler(DialogueDispatcher::new(|x| async move { + // let dialogue = dialogue.expect("std::convert::Infallible"); + // handler(cx, dialogue).await.log_on_error().await + })) .dispatch_with_listener( listener, LoggingErrorHandler::with_custom_text("An error from the update listener"), ) - .await + .await; } From 13fb15f24eb5171bbcb377a2791d49edc9b836fc Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 18:33:43 +0600 Subject: [PATCH 26/99] Fix compilation --- src/dispatching/repls/dialogues_repl.rs | 43 ++++++++++++------------- src/lib.rs | 3 +- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/dispatching/repls/dialogues_repl.rs b/src/dispatching/repls/dialogues_repl.rs index 91ebc60b..b03d110d 100644 --- a/src/dispatching/repls/dialogues_repl.rs +++ b/src/dispatching/repls/dialogues_repl.rs @@ -5,11 +5,11 @@ use crate::{ update_listeners::UpdateListener, Dispatcher, UpdateWithCx, }, - error_handlers::{LoggingErrorHandler, OnError}, + error_handlers::LoggingErrorHandler, types::Message, Bot, }; -use std::{convert::Infallible, fmt::Debug, future::Future}; +use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc}; /// A [REPL] for dialogues. /// @@ -23,23 +23,15 @@ use std::{convert::Infallible, fmt::Debug, future::Future}; /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher -pub async fn dialogues_repl<'a, H, D, Fut, HandlerE>(bot: Bot, bot_name: &'static str, handler: H) +pub async fn dialogues_repl<'a, H, D, Fut>(bot: Bot, handler: H) where H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, D: Default + Send + 'static, - Fut: Future, HandlerE>> + Send + Sync + 'static, - Result, HandlerE>: OnError, - HandlerE: Debug + Send, + Fut: Future> + Send + Sync + 'static, { let cloned_bot = bot.clone(); - dialogues_repl_with_listener( - bot, - bot_name, - handler, - update_listeners::polling_default(cloned_bot), - ) - .await; + dialogues_repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot)).await; } /// Like [`dialogue_repl`], but with a custom [`UpdateListener`]. @@ -55,25 +47,30 @@ where /// [`Dispatcher`]: crate::dispatching::Dispatcher /// [`dialogue_repl`]: crate::dispatching::repls::dialogue_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener -pub async fn dialogues_repl_with_listener<'a, H, D, Fut, HandlerE, L, ListenerE>( +pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE>( bot: Bot, - bot_name: &'static str, handler: H, listener: L, ) where H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, D: Default + Send + 'static, - Fut: Future, HandlerE>> + Send + Sync + 'static, + Fut: Future> + Send + Sync + 'static, L: UpdateListener + Send + 'a, ListenerE: Debug + Send + 'a, - Result, HandlerE>: OnError, - HandlerE: Debug + Send, { - Dispatcher::new(todo!()) - .messages_handler(DialogueDispatcher::new(|x| async move { - // let dialogue = dialogue.expect("std::convert::Infallible"); - // handler(cx, dialogue).await.log_on_error().await - })) + let handler = Arc::new(handler); + + Dispatcher::new(bot) + .messages_handler(DialogueDispatcher::new( + move |DialogueWithCx { cx, dialogue }: DialogueWithCx| { + let handler = Arc::clone(&handler); + + async move { + let dialogue = dialogue.expect("std::convert::Infallible"); + handler(cx, dialogue).await + } + }, + )) .dispatch_with_listener( listener, LoggingErrorHandler::with_custom_text("An error from the update listener"), diff --git a/src/lib.rs b/src/lib.rs index c3ae1ef4..c3116be2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,8 @@ pub use bot::{Bot, BotBuilder}; pub use dispatching::repls::{ - commands_repl, commands_repl_with_listener, repl, repl_with_listener, + commands_repl, commands_repl_with_listener, dialogues_repl, dialogues_repl_with_listener, repl, + repl_with_listener, }; pub use errors::{ApiErrorKind, DownloadError, KnownApiErrorKind, RequestError}; From 0445a803ca4df6e792ea58a9c708612351dc73fb Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 18:37:51 +0600 Subject: [PATCH 27/99] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5ff8225d..124c80e2 100644 --- a/README.md +++ b/README.md @@ -405,6 +405,10 @@ Q: Why Rust? A: Most programming languages have their own implementations of Telegram bots frameworks, so why not Rust? We think Rust provides enough good ecosystem and the language itself to be suitable for writing bots. +UPD: The current design spreads wide and deep trait bounds, thereby increasing cognitive complexity. It can be avoided using [mux-stream], but currently the stable Rust channel doesn't support necessary features to use [mux-stream] conveniently. + +[mux-stream]: https://github.com/Hirrolot/mux-stream + Q: Can I use webhooks? A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](examples/heroku_ping_pong_bot/src/main.rs). From e2d536bc910f8e15f9435d8c6536fbd8d6256ebe Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 18:47:20 +0600 Subject: [PATCH 28/99] Update examples/dialogue_bot --- README.md | 16 ++++------------ examples/dialogue_bot/src/main.rs | 16 ++++------------ src/dispatching/repls/dialogues_repl.rs | 4 ++-- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 124c80e2..c6bf09b7 100644 --- a/README.md +++ b/README.md @@ -309,8 +309,6 @@ Finally, the `main` function looks like this: ```rust // Imports are omitted... -type In = DialogueWithCx; - #[tokio::main] async fn main() { teloxide::enable_logging!(); @@ -318,15 +316,10 @@ async fn main() { let bot = Bot::from_env(); - Dispatcher::new(bot) - .messages_handler(DialogueDispatcher::new( - |DialogueWithCx { cx, dialogue }: In| async move { - let dialogue = dialogue.expect("std::convert::Infallible"); - handle_message(cx, dialogue).await.expect("Something wrong with the bot!") - }, - )) - .dispatch() - .await; + teloxide::dialogues_repl(bot, |message, dialogue| async move { + handle_message(message, dialogue).await.expect("Something wrong with the bot!") + }) + .await; } async fn handle_message(cx: UpdateWithCx, dialogue: Dialogue) -> TransitionOut { @@ -338,7 +331,6 @@ async fn handle_message(cx: UpdateWithCx, dialogue: Dialogue) -> Transi Some(ans) => dialogue.react(cx, ans).await, } } - ```
diff --git a/examples/dialogue_bot/src/main.rs b/examples/dialogue_bot/src/main.rs index e738eaa1..e2c64b07 100644 --- a/examples/dialogue_bot/src/main.rs +++ b/examples/dialogue_bot/src/main.rs @@ -23,11 +23,8 @@ extern crate frunk; mod dialogue; use crate::dialogue::Dialogue; -use std::convert::Infallible; use teloxide::prelude::*; -type In = DialogueWithCx; - #[tokio::main] async fn main() { run().await; @@ -39,15 +36,10 @@ async fn run() { let bot = Bot::from_env(); - Dispatcher::new(bot) - .messages_handler(DialogueDispatcher::new( - |DialogueWithCx { cx, dialogue }: In| async move { - let dialogue = dialogue.expect("std::convert::Infallible"); - handle_message(cx, dialogue).await.expect("Something wrong with the bot!") - }, - )) - .dispatch() - .await; + teloxide::dialogues_repl(bot, |message, dialogue| async move { + handle_message(message, dialogue).await.expect("Something wrong with the bot!") + }) + .await; } async fn handle_message(cx: UpdateWithCx, dialogue: Dialogue) -> TransitionOut { diff --git a/src/dispatching/repls/dialogues_repl.rs b/src/dispatching/repls/dialogues_repl.rs index b03d110d..e608c725 100644 --- a/src/dispatching/repls/dialogues_repl.rs +++ b/src/dispatching/repls/dialogues_repl.rs @@ -27,7 +27,7 @@ pub async fn dialogues_repl<'a, H, D, Fut>(bot: Bot, handler: H) where H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, D: Default + Send + 'static, - Fut: Future> + Send + Sync + 'static, + Fut: Future> + Send + 'static, { let cloned_bot = bot.clone(); @@ -54,7 +54,7 @@ pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE>( ) where H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, D: Default + Send + 'static, - Fut: Future> + Send + Sync + 'static, + Fut: Future> + Send + 'static, L: UpdateListener + Send + 'a, ListenerE: Debug + Send + 'a, { From 1c1b2005b4e0b4463a1f447075a24ff23da514b9 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 18:48:15 +0600 Subject: [PATCH 29/99] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 082f78a1..339b2b33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Let users inspect an unknown API error using `ApiErrorKind::Unknown(String)`. All the known API errors are placed into `KnownApiErrorKind`. - Setters to all the API types. - `teloxide::dispatching::dialogue::serializer` -- various serializers for memory storages. The `Serializer` trait, `Bincode`, `CBOR`, `JSON`. - - `teloxide::dispatching::{repl, commands_repl` + - `teloxide::{repl, repl_with_listener, commands_repl, commands_repl_with_listener, dialogues_repl, dialogues_repl_with_listener}` ### Deprecated - `Bot::{from_env_with_client, new, with_client}` From 337b89112b51036efffc9d594301d0f3d32b8e55 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 19:42:11 +0600 Subject: [PATCH 30/99] Use only required Tokio features --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a1ee05cc..cb5d01f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ frunk- = ["frunk"] serde_json = "1.0.55" serde = { version = "1.0.114", features = ["derive"] } -tokio = { version = "0.2.21", features = ["full"] } +tokio = { version = "0.2.21", features = ["fs", "stream"] } tokio-util = { version = "0.3.1", features = ["full"] } reqwest = { version = "0.10.6", features = ["json", "stream"] } @@ -62,3 +62,4 @@ smart-default = "0.6.0" rand = "0.7.3" pretty_env_logger = "0.4.0" lazy_static = "1.4.0" +tokio = { version = "0.2.21", features = ["fs", "stream", "rt-threaded", "macros"] } From 62a116dbc0be453ee5526cee6aab9c4ab422fc91 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 19:58:41 +0600 Subject: [PATCH 31/99] Use only required tokio-util features --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cb5d01f4..a543e931 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ serde_json = "1.0.55" serde = { version = "1.0.114", features = ["derive"] } tokio = { version = "0.2.21", features = ["fs", "stream"] } -tokio-util = { version = "0.3.1", features = ["full"] } +tokio-util = "0.3.1" reqwest = { version = "0.10.6", features = ["json", "stream"] } log = "0.4.8" From 0ce9c7a5b0d694bd01d74d7f47b990063765f94b Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 20:18:00 +0600 Subject: [PATCH 32/99] Compile tests/redis.rs only if all the features are satisfied --- tests/redis.rs | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/tests/redis.rs b/tests/redis.rs index 41e21a73..3d9da600 100644 --- a/tests/redis.rs +++ b/tests/redis.rs @@ -1,28 +1,45 @@ +#![cfg(feature = "redis_storage")] + use std::{ fmt::{Debug, Display}, future::Future, sync::Arc, }; -use teloxide::dispatching::dialogue::{ - serializer::{Bincode, CBOR, JSON}, - RedisStorage, Serializer, Storage, -}; +use teloxide::dispatching::dialogue::{RedisStorage, Serializer, Storage}; #[tokio::test] +#[cfg(feature = "redis_storage")] async fn test_redis_json() { - let storage = RedisStorage::open("redis://127.0.0.1:7777", JSON).await.unwrap(); + let storage = RedisStorage::open( + "redis://127.0.0.1:7777", + teloxide::dispatching::dialogue::serializer::JSON, + ) + .await + .unwrap(); test_redis(storage).await; } +#[cfg(feature = "bincode_serializer")] #[tokio::test] async fn test_redis_bincode() { - let storage = RedisStorage::open("redis://127.0.0.1:7778", Bincode).await.unwrap(); + let storage = RedisStorage::open( + "redis://127.0.0.1:7778", + teloxide::dispatching::dialogue::serializer::Bincode, + ) + .await + .unwrap(); test_redis(storage).await; } +#[cfg(feature = "cbor_serializer")] #[tokio::test] async fn test_redis_cbor() { - let storage = RedisStorage::open("redis://127.0.0.1:7779", CBOR).await.unwrap(); + let storage = RedisStorage::open( + "redis://127.0.0.1:7779", + teloxide::dispatching::dialogue::serializer::CBOR, + ) + .await + .unwrap(); test_redis(storage).await; } From ba65a3371f59422886dd53835c49d2a93bc6e838 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 20:22:39 +0600 Subject: [PATCH 33/99] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 339b2b33..3193f093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Setters to all the API types. - `teloxide::dispatching::dialogue::serializer` -- various serializers for memory storages. The `Serializer` trait, `Bincode`, `CBOR`, `JSON`. - `teloxide::{repl, repl_with_listener, commands_repl, commands_repl_with_listener, dialogues_repl, dialogues_repl_with_listener}` + - `InputFile::Memory` + - Option to hide a command from description ([issue 217](https://github.com/teloxide/teloxide/issues/217)). ### Deprecated - `Bot::{from_env_with_client, new, with_client}` @@ -32,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Now provided description of unknown telegram error, by splitting ApiErrorKind at `ApiErrorKind` and `ApiErrorKindKnown` enums ([issue 199](https://github.com/teloxide/teloxide/issues/199)). - Extract `Bot` from `Arc` ([issue 216](https://github.com/teloxide/teloxide/issues/230)). - Mark all the API types as `#[non_exhaustive]`. + - Replace all `mime_type: String` with `MimeWrapper`. ### Fixed - Now methods which can send file to Telegram returns `tokio::io::Result`. Early its could panic ([issue 216](https://github.com/teloxide/teloxide/issues/216)). From d4a14df5c81dfafd09974c7618fd455e198578bf Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 21:15:21 +0600 Subject: [PATCH 34/99] Reduce duplication in bot/api.rs --- src/bot/api.rs | 100 +++++++++++++----------- src/dispatching/repls/dialogues_repl.rs | 6 +- 2 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/bot/api.rs b/src/bot/api.rs index 3d0bd5af..619d0777 100644 --- a/src/bot/api.rs +++ b/src/bot/api.rs @@ -17,7 +17,7 @@ use crate::{ }, types::{ BotCommand, ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult, InputFile, - InputMedia, LabeledPrice, StickerType, + InputMedia, LabeledPrice, ParseMode, StickerType, }, Bot, }; @@ -115,12 +115,10 @@ impl Bot { C: Into, T: Into, { - match self.parse_mode.deref() { - None => SendMessage::new(self.clone(), chat_id, text), - Some(parse_mode) => { - SendMessage::new(self.clone(), chat_id, text).parse_mode(*parse_mode.deref()) - } - } + self.with_default_parse_mode_if_specified( + SendMessage::new(self.clone(), chat_id, text), + SendMessage::parse_mode, + ) } /// Use this method to forward messages of any kind. @@ -179,12 +177,10 @@ impl Bot { where C: Into, { - match self.parse_mode.deref() { - None => SendPhoto::new(self.clone(), chat_id, photo), - Some(parse_mode) => { - SendPhoto::new(self.clone(), chat_id, photo).parse_mode(*parse_mode.deref()) - } - } + self.with_default_parse_mode_if_specified( + SendPhoto::new(self.clone(), chat_id, photo), + SendPhoto::parse_mode, + ) } /// @@ -202,12 +198,10 @@ impl Bot { where C: Into, { - match self.parse_mode.deref() { - None => SendAudio::new(self.clone(), chat_id, audio), - Some(parse_mode) => { - SendAudio::new(self.clone(), chat_id, audio).parse_mode(*parse_mode.deref()) - } - } + self.with_default_parse_mode_if_specified( + SendAudio::new(self.clone(), chat_id, audio), + SendAudio::parse_mode, + ) } /// Use this method to send general files. @@ -238,12 +232,10 @@ impl Bot { where C: Into, { - match self.parse_mode.deref() { - None => SendDocument::new(self.clone(), chat_id, document), - Some(parse_mode) => { - SendDocument::new(self.clone(), chat_id, document).parse_mode(*parse_mode.deref()) - } - } + self.with_default_parse_mode_if_specified( + SendDocument::new(self.clone(), chat_id, document), + SendDocument::parse_mode, + ) } /// Use this method to send video files, Telegram clients support mp4 videos @@ -277,12 +269,10 @@ impl Bot { where C: Into, { - match self.parse_mode.deref() { - None => SendVideo::new(self.clone(), chat_id, video), - Some(parse_mode) => { - SendVideo::new(self.clone(), chat_id, video).parse_mode(*parse_mode.deref()) - } - } + self.with_default_parse_mode_if_specified( + SendVideo::new(self.clone(), chat_id, video), + SendVideo::parse_mode, + ) } /// Use this method to send animation files (GIF or H.264/MPEG-4 AVC video @@ -307,12 +297,10 @@ impl Bot { where C: Into, { - match self.parse_mode.deref() { - None => SendAnimation::new(self.clone(), chat_id, animation), - Some(parse_mode) => { - SendAnimation::new(self.clone(), chat_id, animation).parse_mode(*parse_mode.deref()) - } - } + self.with_default_parse_mode_if_specified( + SendAnimation::new(self.clone(), chat_id, animation), + SendAnimation::parse_mode, + ) } /// Use this method to send audio files, if you want Telegram clients to @@ -352,12 +340,10 @@ impl Bot { where C: Into, { - match self.parse_mode.deref() { - None => SendVoice::new(self.clone(), chat_id, voice), - Some(parse_mode) => { - SendVoice::new(self.clone(), chat_id, voice).parse_mode(*parse_mode.deref()) - } - } + self.with_default_parse_mode_if_specified( + SendVoice::new(self.clone(), chat_id, voice), + SendVoice::parse_mode, + ) } /// As of [v.4.0], Telegram clients support rounded square mp4 videos of up @@ -513,21 +499,32 @@ impl Bot { /// /// [The official docs](https://core.telegram.org/bots/api#sendpoll). /// - /// /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). /// - `question`: Poll question, 1-255 characters. /// - `options`: List of answer options, 2-10 strings 1-100 characters /// each. + /// + /// # Notes + /// Uses [a default parse mode] ([`SendPoll::explanation_parse_mode`]) if + /// specified in [`BotBuilder`]. + /// + /// [a default parse mode]: crate::BotBuilder::parse_mode + /// [`BotBuilder`]: crate::BotBuilder + /// [`SendPoll::explanation_parse_mode`]: + /// [`SendPoll::explanation_parse_mode`]: + /// crate::types::SendPoll::explanation_parse_mode pub fn send_poll(&self, chat_id: C, question: Q, options: O) -> SendPoll where C: Into, Q: Into, O: Into>, { - // FIXME: parse_mode - SendPoll::new(self.clone(), chat_id, question, options) + self.with_default_parse_mode_if_specified( + SendPoll::new(self.clone(), chat_id, question, options), + SendPoll::explanation_parse_mode, + ) } /// Use this method when you need to tell the user that something is @@ -1527,4 +1524,15 @@ impl Bot { { SetStickerSetThumb::new(self.clone(), name, user_id) } + + fn with_default_parse_mode_if_specified( + &self, + builder: Builder, + f: fn(Builder, ParseMode) -> Builder, + ) -> Builder { + match self.parse_mode.deref() { + None => builder, + Some(parse_mode) => f(builder, *parse_mode.deref()), + } + } } diff --git a/src/dispatching/repls/dialogues_repl.rs b/src/dispatching/repls/dialogues_repl.rs index e608c725..883e74de 100644 --- a/src/dispatching/repls/dialogues_repl.rs +++ b/src/dispatching/repls/dialogues_repl.rs @@ -23,6 +23,7 @@ use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc}; /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher +/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage pub async fn dialogues_repl<'a, H, D, Fut>(bot: Bot, handler: H) where H: Fn(UpdateWithCx, D) -> Fut + Send + Sync + 'static, @@ -34,7 +35,7 @@ where dialogues_repl_with_listener(bot, handler, update_listeners::polling_default(cloned_bot)).await; } -/// Like [`dialogue_repl`], but with a custom [`UpdateListener`]. +/// Like [`dialogues_repl`], but with a custom [`UpdateListener`]. /// /// All errors from an update listener and handler will be logged. This function /// uses [`InMemStorage`]. @@ -45,8 +46,9 @@ where /// bot. /// /// [`Dispatcher`]: crate::dispatching::Dispatcher -/// [`dialogue_repl`]: crate::dispatching::repls::dialogue_repl() +/// [`dialogues_repl`]: crate::dispatching::repls::dialogues_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener +/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage pub async fn dialogues_repl_with_listener<'a, H, D, Fut, L, ListenerE>( bot: Bot, handler: H, From 6bb8482f3dc16b202a3b3bfed085e7e8b4fe2964 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 21:34:48 +0600 Subject: [PATCH 35/99] Respect TELOXIDE_PROXY in Bot::from_env & BotBuilder --- CHANGELOG.md | 1 + src/bot/mod.rs | 45 ++++++++++++++++++++++++++---------- src/utils/client_from_env.rs | 14 +++++------ 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3193f093..7e98be30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `teloxide::{repl, repl_with_listener, commands_repl, commands_repl_with_listener, dialogues_repl, dialogues_repl_with_listener}` - `InputFile::Memory` - Option to hide a command from description ([issue 217](https://github.com/teloxide/teloxide/issues/217)). + - Respect the `TELOXIDE_PROXY` environment variable in `Bot::from_env`. ### Deprecated - `Bot::{from_env_with_client, new, with_client}` diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 10454a32..65a024bf 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -8,6 +8,9 @@ use std::{sync::Arc, time::Duration}; mod api; mod download; +pub(crate) const TELOXIDE_TOKEN: &str = "TELOXIDE_TOKEN"; +pub(crate) const TELOXIDE_PROXY: &str = "TELOXIDE_PROXY"; + /// A requests sender. /// /// No need to put it into [`Arc`], because it's already in. @@ -21,17 +24,24 @@ pub struct Bot { } impl Bot { - /// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a - /// bot's token) and the default [`reqwest::Client`]. + /// Creates a new `Bot` with the `TELOXIDE_TOKEN` & `TELOXIDE_PROXY` + /// environmental variables (a bot's token & a proxy) and the default + /// [`reqwest::Client`]. + /// + /// This function passes the value of `TELOXIDE_PROXY` into + /// [`reqwest::Proxy::all`], if it exists, otherwise returns the default + /// client. /// /// # Panics - /// - If cannot get the `TELOXIDE_TOKEN` environmental variable. + /// - If cannot get the `TELOXIDE_TOKEN` and `TELOXIDE_PROXY` environmental + /// variables. /// - If it cannot create [`reqwest::Client`]. /// /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html - #[allow(deprecated)] + /// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all + #[must_use] pub fn from_env() -> Self { - Self::from_env_with_client(build_sound_bot()) + BotBuilder::new().build() } /// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a @@ -49,7 +59,7 @@ impl Bot { #[deprecated] #[allow(deprecated)] pub fn from_env_with_client(client: Client) -> Self { - Self::with_client(&get_token_from_env(), client) + Self::with_client(&get_env(TELOXIDE_TOKEN), client) } /// Creates a new `Bot` with the specified token and the default @@ -115,8 +125,8 @@ pub(crate) fn build_sound_bot() -> Client { sound_bot().build().expect("creating reqwest::Client") } -fn get_token_from_env() -> String { - std::env::var("TELOXIDE_TOKEN").expect("Cannot get the TELOXIDE_TOKEN env variable") +fn get_env(env: &'static str) -> String { + std::env::var(env).unwrap_or_else(|_| panic!("Cannot get the {} env variable", env)) } impl Bot { @@ -150,10 +160,15 @@ impl BotBuilder { /// Specifies a custom HTTPS client. Otherwise, the default will be used. /// /// # Caution - /// Your custom client might not be configured correctly to be able to work + /// - Your custom client might not be configured correctly to be able to + /// work /// in long time durations, see [issue 223]. /// + /// - If this method is used, the `TELOXIDE_PROXY` environmental variable + /// won't be extracted in [`BotBuilder::build`]. + /// /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 + /// [`BotBuilder::build`]: crate::BotBuilder::build #[must_use] pub fn client(mut self, client: Client) -> Self { self.client = Some(client); @@ -204,18 +219,24 @@ impl BotBuilder { /// Builds [`Bot`]. /// + /// This method will attempt to build a new client with a proxy, specified + /// in the `TELOXIDE_PROXY` (passed into [`reqwest::Proxy::all`]) + /// environmental variable, if a client haven't been specified. + /// /// # Panics - /// - If cannot get the `TELOXIDE_TOKEN` environmental variable. + /// - If cannot get the `TELOXIDE_TOKEN` and `TELOXIDE_PROXY` environmental + /// variables. /// - If it cannot create [`reqwest::Client`]. /// /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html /// /// [`Bot`]: crate::Bot + /// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all #[must_use] pub fn build(self) -> Bot { Bot { - client: self.client.unwrap_or_else(build_sound_bot), - token: self.token.unwrap_or_else(get_token_from_env).into(), + client: self.client.unwrap_or_else(crate::utils::client_from_env), + token: self.token.unwrap_or_else(|| get_env(TELOXIDE_TOKEN)).into(), parse_mode: Arc::new(self.parse_mode), } } diff --git a/src/utils/client_from_env.rs b/src/utils/client_from_env.rs index 7c5c7b06..8857e387 100644 --- a/src/utils/client_from_env.rs +++ b/src/utils/client_from_env.rs @@ -1,4 +1,4 @@ -use crate::bot::sound_bot; +use crate::bot::{sound_bot, TELOXIDE_PROXY}; /// Constructs a client from the `TELOXIDE_PROXY` environmental variable. /// @@ -13,13 +13,13 @@ use crate::bot::sound_bot; /// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 pub fn client_from_env() -> reqwest::Client { - use reqwest::{Client, Proxy}; + use reqwest::Proxy; - match std::env::var("TELOXIDE_PROXY").ok() { - Some(proxy) => { - Client::builder().proxy(Proxy::all(&proxy).expect("creating reqwest::Proxy")) - } - None => sound_bot(), + let builder = sound_bot(); + + match std::env::var(TELOXIDE_PROXY).ok() { + Some(proxy) => builder.proxy(Proxy::all(&proxy).expect("creating reqwest::Proxy")), + None => builder, } .build() .expect("creating reqwest::Client") From 09d3db9f9beefb032b7fdaeea0f84d809b65916f Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 21:43:28 +0600 Subject: [PATCH 36/99] Fix Cargo.toml files in the examples --- README.md | 2 +- examples/admin_bot/Cargo.toml | 3 +-- examples/dialogue_bot/Cargo.toml | 8 +++++--- examples/dices_bot/Cargo.toml | 2 +- examples/heroku_ping_pong_bot/Cargo.toml | 5 ++--- examples/ngrok_ping_pong_bot/Cargo.toml | 4 +--- examples/redis_remember_bot/Cargo.toml | 4 +++- examples/shared_state_bot/Cargo.toml | 5 ++--- examples/simple_commands_bot/Cargo.toml | 3 +-- 9 files changed, 17 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index c6bf09b7..5422502b 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ teloxide-macros = "0.3.2" log = "0.4.8" pretty_env_logger = "0.4.0" -tokio = "0.2.11" +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } ``` ## API overview diff --git a/examples/admin_bot/Cargo.toml b/examples/admin_bot/Cargo.toml index cbbe1b8d..3a4950a8 100644 --- a/examples/admin_bot/Cargo.toml +++ b/examples/admin_bot/Cargo.toml @@ -8,9 +8,8 @@ edition = "2018" [dependencies] log = "0.4.8" -futures = "0.3.4" -tokio = "0.2.9" pretty_env_logger = "0.4.0" +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } teloxide = { path = "../../" } [profile.release] diff --git a/examples/dialogue_bot/Cargo.toml b/examples/dialogue_bot/Cargo.toml index 7defcc1b..1f08c16a 100644 --- a/examples/dialogue_bot/Cargo.toml +++ b/examples/dialogue_bot/Cargo.toml @@ -8,16 +8,18 @@ edition = "2018" [dependencies] log = "0.4.8" -tokio = "0.2.9" +pretty_env_logger = "0.4.0" frunk = "0.3.1" frunk_core = "0.3.1" -pretty_env_logger = "0.4.0" futures = "0.3.5" -derive_more = "0.99.9" +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } + teloxide = { path = "../../", features = ["frunk"] } teloxide-macros = "0.3.2" +derive_more = "0.99.9" + [profile.release] lto = true diff --git a/examples/dices_bot/Cargo.toml b/examples/dices_bot/Cargo.toml index a5db82ee..3c2a6ed8 100644 --- a/examples/dices_bot/Cargo.toml +++ b/examples/dices_bot/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" [dependencies] log = "0.4.8" -tokio = "0.2.9" pretty_env_logger = "0.4.0" +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } teloxide = { path = "../../" } [profile.release] diff --git a/examples/heroku_ping_pong_bot/Cargo.toml b/examples/heroku_ping_pong_bot/Cargo.toml index d5d8d1f1..d568e8a8 100644 --- a/examples/heroku_ping_pong_bot/Cargo.toml +++ b/examples/heroku_ping_pong_bot/Cargo.toml @@ -8,10 +8,9 @@ edition = "2018" [dependencies] log = "0.4.8" -futures = "0.3.4" -tokio = "0.2.9" pretty_env_logger = "0.4.0" -teloxide = { path = "../../" } +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } +teloxide = { path = "../../" } # Used to setup a webhook warp = "0.2.2" diff --git a/examples/ngrok_ping_pong_bot/Cargo.toml b/examples/ngrok_ping_pong_bot/Cargo.toml index 31d91b31..9522426f 100644 --- a/examples/ngrok_ping_pong_bot/Cargo.toml +++ b/examples/ngrok_ping_pong_bot/Cargo.toml @@ -8,10 +8,8 @@ edition = "2018" [dependencies] log = "0.4.8" -futures = "0.3.4" -tokio = "0.2.9" pretty_env_logger = "0.4.0" - +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } teloxide = { path = "../../" } # Used to setup a webhook diff --git a/examples/redis_remember_bot/Cargo.toml b/examples/redis_remember_bot/Cargo.toml index 12e62055..6927b9d8 100644 --- a/examples/redis_remember_bot/Cargo.toml +++ b/examples/redis_remember_bot/Cargo.toml @@ -5,7 +5,9 @@ authors = ["Maximilian Siling "] edition = "2018" [dependencies] -tokio = "0.2.9" +log = "0.4.8" +pretty_env_logger = "0.4.0" +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } # You can also choose "cbor-serializer" or built-in JSON serializer teloxide = { path = "../../", features = ["redis-storage", "bincode-serializer"] } diff --git a/examples/shared_state_bot/Cargo.toml b/examples/shared_state_bot/Cargo.toml index 136c2ec0..fc26da82 100644 --- a/examples/shared_state_bot/Cargo.toml +++ b/examples/shared_state_bot/Cargo.toml @@ -8,7 +8,6 @@ edition = "2018" [dependencies] log = "0.4.8" -tokio = "0.2.9" pretty_env_logger = "0.4.0" -lazy_static = "1.4.0" -teloxide = { path = "../../" } \ No newline at end of file +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } +teloxide = { path = "../../" } diff --git a/examples/simple_commands_bot/Cargo.toml b/examples/simple_commands_bot/Cargo.toml index 6dd8047b..7acc2030 100644 --- a/examples/simple_commands_bot/Cargo.toml +++ b/examples/simple_commands_bot/Cargo.toml @@ -8,7 +8,6 @@ edition = "2018" [dependencies] log = "0.4.8" -futures = "0.3.4" -tokio = "0.2.9" pretty_env_logger = "0.4.0" +tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } teloxide = { path = "../../" } From 1e7919455b0e16ee0ed6ab7d59ed329fe08cdb52 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 21:49:22 +0600 Subject: [PATCH 37/99] Import lazy_static into examples/shared_state_bot --- examples/shared_state_bot/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/shared_state_bot/Cargo.toml b/examples/shared_state_bot/Cargo.toml index fc26da82..be1fbf6b 100644 --- a/examples/shared_state_bot/Cargo.toml +++ b/examples/shared_state_bot/Cargo.toml @@ -11,3 +11,4 @@ log = "0.4.8" pretty_env_logger = "0.4.0" tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } teloxide = { path = "../../" } +lazy_static = "1.4.0" From a0064b7befaa1de25d77de5dc5cb9a5811bf0dbc Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 21:52:41 +0600 Subject: [PATCH 38/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5422502b..044b43a6 100644 --- a/README.md +++ b/README.md @@ -397,7 +397,7 @@ Q: Why Rust? A: Most programming languages have their own implementations of Telegram bots frameworks, so why not Rust? We think Rust provides enough good ecosystem and the language itself to be suitable for writing bots. -UPD: The current design spreads wide and deep trait bounds, thereby increasing cognitive complexity. It can be avoided using [mux-stream], but currently the stable Rust channel doesn't support necessary features to use [mux-stream] conveniently. +UPD: The current design spreads wide and deep trait bounds, thereby increasing cognitive complexity. It can be avoided using [mux-stream], but currently the stable Rust channel doesn't support necessary features to use [mux-stream] conveniently. What is even more interesting is that [mux-stream] could make a library from teloxide, not a framework, since the design could be defined by just combining streams of updates. [mux-stream]: https://github.com/Hirrolot/mux-stream From b68d03ae83efa66cb7fa003de2544fab4168f208 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 21:54:52 +0600 Subject: [PATCH 39/99] v0.3.0 Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a543e931..a8661289 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "teloxide" -version = "0.2.0" +version = "0.3.0" edition = "2018" description = "An elegant Telegram bots framework for Rust" repository = "https://github.com/teloxide/teloxide" From b98932437b0b38be5b7b7dbf08cffa30bc818a82 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 21:56:27 +0600 Subject: [PATCH 40/99] v0.3.0 CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e98be30..fd3cf8cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.3.0] - ??? +## [0.3.0] - 2020-07-31 ### Added - Support for typed bot commands ([issue 152](https://github.com/teloxide/teloxide/issues/152)). - `BotBuilder`, which allows setting a default `ParseMode`. From 5985f62bfe97ce3104d1b794cd44a65421cc91d4 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 22:04:39 +0600 Subject: [PATCH 41/99] v0.3.0 README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 044b43a6..2c09106e 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@

teloxide

- + - + @@ -76,7 +76,7 @@ $ rustup override set nightly 5. Execute `cargo new my_bot`, enter the directory and put these lines into your `Cargo.toml`: ```toml [dependencies] -teloxide = "0.2.0" +teloxide = "0.3.0" teloxide-macros = "0.3.2" log = "0.4.8" From 2f4006f5ea16551d49cca36f6ee7f4b97de80fc4 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 23:18:13 +0600 Subject: [PATCH 42/99] Update the API coverage badge to 0.4.9 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c09106e..19fa1b36 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - + A full-featured framework that empowers you to easily build [Telegram bots](https://telegram.org/blog/bot-revolution) using the [`async`/`.await`](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) syntax in [Rust](https://www.rust-lang.org/). It handles all the difficult stuff so you can focus only on your business logic. From f2618ad7ed7f42f7b7bc9fde4b6bbb70ff5ca035 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 31 Jul 2020 23:49:43 +0600 Subject: [PATCH 43/99] Fix wrong documentation about TELOXIDE_PROXY --- src/bot/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 65a024bf..1c205a21 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -33,8 +33,7 @@ impl Bot { /// client. /// /// # Panics - /// - If cannot get the `TELOXIDE_TOKEN` and `TELOXIDE_PROXY` environmental - /// variables. + /// - If cannot get the `TELOXIDE_TOKEN` environmental variable. /// - If it cannot create [`reqwest::Client`]. /// /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html @@ -221,11 +220,11 @@ impl BotBuilder { /// /// This method will attempt to build a new client with a proxy, specified /// in the `TELOXIDE_PROXY` (passed into [`reqwest::Proxy::all`]) - /// environmental variable, if a client haven't been specified. + /// environmental variable, if a client haven't been specified. If + /// `TELOXIDE_PROXY` is unspecified, it'll use no proxy. /// /// # Panics - /// - If cannot get the `TELOXIDE_TOKEN` and `TELOXIDE_PROXY` environmental - /// variables. + /// - If cannot get the `TELOXIDE_TOKEN` environmental variable. /// - If it cannot create [`reqwest::Client`]. /// /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html From 08d0d7f2f4e7ac58a3d845999d003ddb57b3834f Mon Sep 17 00:00:00 2001 From: Kirill Mironov Date: Fri, 31 Jul 2020 21:10:18 +0300 Subject: [PATCH 44/99] Unpair TransitionOut from concrete Error type resolves #242 --- src/dispatching/dialogue/transition.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dispatching/dialogue/transition.rs b/src/dispatching/dialogue/transition.rs index d15ce303..5a53a004 100644 --- a/src/dispatching/dialogue/transition.rs +++ b/src/dispatching/dialogue/transition.rs @@ -1,6 +1,5 @@ use crate::{ dispatching::{dialogue::DialogueStage, UpdateWithCx}, - requests::ResponseResult, types::Message, }; use futures::future::BoxFuture; @@ -51,4 +50,4 @@ impl SubtransitionOutputType for TransitionOut { pub type TransitionIn = UpdateWithCx; /// A type returned from a FSM (sub)transition function. -pub type TransitionOut = ResponseResult>; +pub type TransitionOut = Result, E>; From ffb5f2936212309a313d0016c7e8f64051b77fbd Mon Sep 17 00:00:00 2001 From: Kirill Mironov Date: Sat, 1 Aug 2020 00:18:52 +0300 Subject: [PATCH 45/99] Allow for custom error types in TransitionOut --- Cargo.toml | 2 +- src/dispatching/dialogue/dialogue_stage.rs | 4 ++-- src/dispatching/dialogue/mod.rs | 2 +- src/dispatching/dialogue/transition.rs | 16 ++++++++++++---- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a8661289..d1db35be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ serde_cbor = { version = "0.11.1", optional = true } bincode = { version = "1.3.1", optional = true } frunk = { version = "0.3.1", optional = true } -teloxide-macros = "0.3.2" +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "feature/arbitrary-transition-result-types" } [dev-dependencies] smart-default = "0.6.0" diff --git a/src/dispatching/dialogue/dialogue_stage.rs b/src/dispatching/dialogue/dialogue_stage.rs index 7dcafec3..ad731e74 100644 --- a/src/dispatching/dialogue/dialogue_stage.rs +++ b/src/dispatching/dialogue/dialogue_stage.rs @@ -21,7 +21,7 @@ pub enum DialogueStage { /// /// [`From`]: std::convert::From /// [derive-more]: https://crates.io/crates/derive_more -pub fn next(new_state: State) -> TransitionOut +pub fn next(new_state: State) -> TransitionOut where Dialogue: From, { @@ -32,6 +32,6 @@ where /// /// See [the module-level documentation for the design /// overview](crate::dispatching::dialogue). -pub fn exit() -> TransitionOut { +pub fn exit() -> TransitionOut { Ok(DialogueStage::Exit) } diff --git a/src/dispatching/dialogue/mod.rs b/src/dispatching/dialogue/mod.rs index 420a755b..5030fd4b 100644 --- a/src/dispatching/dialogue/mod.rs +++ b/src/dispatching/dialogue/mod.rs @@ -39,7 +39,7 @@ //! struct _2State; //! struct _3State; //! -//! type Out = TransitionOut; +//! type Out = TransitionOut; //! //! #[teloxide(subtransition)] //! async fn _1_transition(_state: _1State, _cx: TransitionIn) -> Out { diff --git a/src/dispatching/dialogue/transition.rs b/src/dispatching/dialogue/transition.rs index 5a53a004..a811db4c 100644 --- a/src/dispatching/dialogue/transition.rs +++ b/src/dispatching/dialogue/transition.rs @@ -7,11 +7,16 @@ use futures::future::BoxFuture; /// Represents a transition function of a dialogue FSM. pub trait Transition: Sized { type Aux; + type Error; /// Turns itself into another state, depending on the input message. /// /// `aux` will be passed to each subtransition function. - fn react(self, cx: TransitionIn, aux: Self::Aux) -> BoxFuture<'static, TransitionOut>; + fn react( + self, + cx: TransitionIn, + aux: Self::Aux, + ) -> BoxFuture<'static, TransitionOut>; } /// Like [`Transition`], but from `StateN` -> `Dialogue`. @@ -23,6 +28,7 @@ where { type Aux; type Dialogue; + type Error; /// Turns itself into another state, depending on the input message. /// @@ -32,7 +38,7 @@ where self, cx: TransitionIn, aux: Self::Aux, - ) -> BoxFuture<'static, TransitionOut>; + ) -> BoxFuture<'static, TransitionOut>; } /// A type returned from a FSM subtransition function. @@ -40,14 +46,16 @@ where /// Now it is used only inside `#[teloxide(subtransition)]` for type inference. pub trait SubtransitionOutputType { type Output; + type Error; } -impl SubtransitionOutputType for TransitionOut { +impl SubtransitionOutputType for TransitionOut { type Output = D; + type Error = E; } /// An input passed into a FSM (sub)transition function. pub type TransitionIn = UpdateWithCx; /// A type returned from a FSM (sub)transition function. -pub type TransitionOut = Result, E>; +pub type TransitionOut = Result, E>; From 245355ea3e025a5054d13c99d406cdeca47d58b0 Mon Sep 17 00:00:00 2001 From: Kirill Mironov Date: Sat, 1 Aug 2020 11:58:24 +0300 Subject: [PATCH 46/99] set default error type --- src/dispatching/dialogue/transition.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dispatching/dialogue/transition.rs b/src/dispatching/dialogue/transition.rs index a811db4c..3150db98 100644 --- a/src/dispatching/dialogue/transition.rs +++ b/src/dispatching/dialogue/transition.rs @@ -58,4 +58,4 @@ impl SubtransitionOutputType for TransitionOut { pub type TransitionIn = UpdateWithCx; /// A type returned from a FSM (sub)transition function. -pub type TransitionOut = Result, E>; +pub type TransitionOut = Result, E>; From 90a65c0f9e8f07bd9209e8c932a04cd0ae030be2 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 1 Aug 2020 15:15:45 +0600 Subject: [PATCH 47/99] Update examples/README.md --- examples/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index db492ce7..6a41c295 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,11 +2,11 @@ Just enter the directory (for example, `cd dialogue_bot`) and execute `cargo run` to run an example. Don't forget to initialise the `TELOXIDE_TOKEN` environmental variable. | Bot | Description | |---|-----------| -| [dices_bot](dices_bot) | This bot throws a dice on each incoming message. | +| [dices_bot](dices_bot) | Throws a dice on each incoming message. | | [ngrok_ping_pong_bot](ngrok_ping_pong_bot) | The ngrok version of ping-pong-bot that uses webhooks. | | [heroku_ping_pong_bot](heroku_ping_pong_bot) | The Heroku version of ping-pong-bot that uses webhooks. | | [simple_commands_bot](simple_commands_bot) | Shows how to deal with bot's commands. | -| [guess_a_number_bot](guess_a_number_bot) | The "guess a number" game. | -| [dialogue_bot](dialogue_bot) | Drive a dialogue with a user using a type-safe finite automaton. | -| [admin_bot](admin_bot) | A bot, which can ban, kick, and mute on a command. | -| [shared_state_bot](shared_state_bot) | A bot that shows how to deal with shared state. | +| [redis_remember_bot](redis_remember) | Uses `RedisStorage` instead of `InMemStorage`. | +| [dialogue_bot](dialogue_bot) | How to deal with dialogues. | +| [admin_bot](admin_bot) | Ban, kick, and mute on a command. | +| [shared_state_bot](shared_state_bot) | How to deal with shared state. | From 71414b812f1c1363495d8d36c607d8bb221c9b69 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 1 Aug 2020 15:16:28 +0600 Subject: [PATCH 48/99] Update examples/README.md --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index 6a41c295..21515200 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +6,7 @@ Just enter the directory (for example, `cd dialogue_bot`) and execute `cargo run | [ngrok_ping_pong_bot](ngrok_ping_pong_bot) | The ngrok version of ping-pong-bot that uses webhooks. | | [heroku_ping_pong_bot](heroku_ping_pong_bot) | The Heroku version of ping-pong-bot that uses webhooks. | | [simple_commands_bot](simple_commands_bot) | Shows how to deal with bot's commands. | -| [redis_remember_bot](redis_remember) | Uses `RedisStorage` instead of `InMemStorage`. | +| [redis_remember_bot](redis_remember_bot) | Uses `RedisStorage` instead of `InMemStorage`. | | [dialogue_bot](dialogue_bot) | How to deal with dialogues. | | [admin_bot](admin_bot) | Ban, kick, and mute on a command. | | [shared_state_bot](shared_state_bot) | How to deal with shared state. | From 8b14fb5122581e19c2827bfd287174a4aa720f96 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 1 Aug 2020 16:07:01 +0600 Subject: [PATCH 49/99] Download teloxide-macros from git in the examples --- examples/dialogue_bot/Cargo.toml | 2 +- examples/redis_remember_bot/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/dialogue_bot/Cargo.toml b/examples/dialogue_bot/Cargo.toml index 1f08c16a..c5dc6c01 100644 --- a/examples/dialogue_bot/Cargo.toml +++ b/examples/dialogue_bot/Cargo.toml @@ -17,7 +17,7 @@ futures = "0.3.5" tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } teloxide = { path = "../../", features = ["frunk"] } -teloxide-macros = "0.3.2" +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "feature/arbitrary-transition-result-types" } derive_more = "0.99.9" diff --git a/examples/redis_remember_bot/Cargo.toml b/examples/redis_remember_bot/Cargo.toml index 6927b9d8..992b2a2d 100644 --- a/examples/redis_remember_bot/Cargo.toml +++ b/examples/redis_remember_bot/Cargo.toml @@ -11,7 +11,7 @@ tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } # You can also choose "cbor-serializer" or built-in JSON serializer teloxide = { path = "../../", features = ["redis-storage", "bincode-serializer"] } -teloxide-macros = "0.3.2" +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "feature/arbitrary-transition-result-types" } serde = "1.0.104" futures = "0.3.5" From b3aa539c4d989057c5f81ec6c4aa85e70ddbd80e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 1 Aug 2020 17:52:50 +0600 Subject: [PATCH 50/99] Download the master branch of teloxide-macros --- Cargo.toml | 2 +- examples/dialogue_bot/Cargo.toml | 2 +- examples/redis_remember_bot/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1db35be..2497c1c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ serde_cbor = { version = "0.11.1", optional = true } bincode = { version = "1.3.1", optional = true } frunk = { version = "0.3.1", optional = true } -teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "feature/arbitrary-transition-result-types" } +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" } [dev-dependencies] smart-default = "0.6.0" diff --git a/examples/dialogue_bot/Cargo.toml b/examples/dialogue_bot/Cargo.toml index c5dc6c01..3d36bb3c 100644 --- a/examples/dialogue_bot/Cargo.toml +++ b/examples/dialogue_bot/Cargo.toml @@ -17,7 +17,7 @@ futures = "0.3.5" tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } teloxide = { path = "../../", features = ["frunk"] } -teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "feature/arbitrary-transition-result-types" } +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" } derive_more = "0.99.9" diff --git a/examples/redis_remember_bot/Cargo.toml b/examples/redis_remember_bot/Cargo.toml index 992b2a2d..f7843219 100644 --- a/examples/redis_remember_bot/Cargo.toml +++ b/examples/redis_remember_bot/Cargo.toml @@ -11,7 +11,7 @@ tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } # You can also choose "cbor-serializer" or built-in JSON serializer teloxide = { path = "../../", features = ["redis-storage", "bincode-serializer"] } -teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "feature/arbitrary-transition-result-types" } +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" } serde = "1.0.104" futures = "0.3.5" From 6f13d38812c0b92f5a34e628844bba0b0a7fae9e Mon Sep 17 00:00:00 2001 From: DCjanus Date: Sun, 2 Aug 2020 02:43:30 +0800 Subject: [PATCH 51/99] remove unnecessary type bound --- src/dispatching/repls/commands_repl.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/dispatching/repls/commands_repl.rs b/src/dispatching/repls/commands_repl.rs index c842fd7a..d80138ca 100644 --- a/src/dispatching/repls/commands_repl.rs +++ b/src/dispatching/repls/commands_repl.rs @@ -22,13 +22,14 @@ use std::{fmt::Debug, future::Future, sync::Arc}; /// /// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop /// [`Dispatcher`]: crate::dispatching::Dispatcher -pub async fn commands_repl(bot: Bot, bot_name: &'static str, handler: H) +pub async fn commands_repl(bot: Bot, bot_name: N, handler: H) where Cmd: BotCommand + Send + 'static, H: Fn(UpdateWithCx, Cmd) -> Fut + Send + Sync + 'static, Fut: Future> + Send + 'static, Result<(), HandlerE>: OnError, HandlerE: Debug + Send, + N: Into + Send + 'static, { let cloned_bot = bot.clone(); @@ -53,9 +54,9 @@ where /// [`Dispatcher`]: crate::dispatching::Dispatcher /// [`commands_repl`]: crate::dispatching::repls::commands_repl() /// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener -pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE>( +pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE, N>( bot: Bot, - bot_name: &'static str, + bot_name: N, handler: H, listener: L, ) where @@ -66,21 +67,19 @@ pub async fn commands_repl_with_listener<'a, Cmd, H, Fut, L, ListenerE, HandlerE ListenerE: Debug + Send + 'a, Result<(), HandlerE>: OnError, HandlerE: Debug + Send, + N: Into + Send + 'static, { let handler = Arc::new(handler); Dispatcher::new(bot) .messages_handler(move |rx: DispatcherHandlerRx| { - rx.commands::(bot_name).for_each_concurrent( - None, - move |(cx, cmd)| { - let handler = Arc::clone(&handler); + rx.commands::(bot_name).for_each_concurrent(None, move |(cx, cmd)| { + let handler = Arc::clone(&handler); - async move { - handler(cx, cmd).await.log_on_error().await; - } - }, - ) + async move { + handler(cx, cmd).await.log_on_error().await; + } + }) }) .dispatch_with_listener( listener, From 7b9f7e869030f90fcfe22df1dec0d1e4ae88408d Mon Sep 17 00:00:00 2001 From: DCjanus Date: Sun, 2 Aug 2020 12:11:09 +0800 Subject: [PATCH 52/99] fix example code --- README.md | 3 ++- examples/admin_bot/src/main.rs | 3 ++- examples/simple_commands_bot/src/main.rs | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 19fa1b36..5a30bab9 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,8 @@ async fn main() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, panic!("Your bot's name here"), answer).await; + let bot_name: String = panic!("Your bot's name here"); + teloxide::commands_repl(bot, bot_name, action).await; } ``` diff --git a/examples/admin_bot/src/main.rs b/examples/admin_bot/src/main.rs index ea4f9078..ee239fa0 100644 --- a/examples/admin_bot/src/main.rs +++ b/examples/admin_bot/src/main.rs @@ -139,5 +139,6 @@ async fn run() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, panic!("Your bot's name here"), action).await; + let bot_name: String = panic!("Your bot's name here"); + teloxide::commands_repl(bot, bot_name, action).await; } diff --git a/examples/simple_commands_bot/src/main.rs b/examples/simple_commands_bot/src/main.rs index 24b88345..86a61bb6 100644 --- a/examples/simple_commands_bot/src/main.rs +++ b/examples/simple_commands_bot/src/main.rs @@ -36,5 +36,6 @@ async fn run() { let bot = Bot::from_env(); - teloxide::commands_repl(bot, panic!("Your bot's name here"), answer).await; + let bot_name: String = panic!("Your bot's name here"); + teloxide::commands_repl(bot, bot_name, answer).await; } From 05e32336faa7cd3bd824fb4c62647fbf484ee55e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 2 Aug 2020 13:08:43 +0600 Subject: [PATCH 53/99] Add requests::respond --- README.md | 2 +- examples/dices_bot/src/main.rs | 2 +- src/prelude.rs | 2 +- src/requests/mod.rs | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5a30bab9..427b78d3 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ async fn main() { teloxide::repl(bot, |message| async move { message.answer_dice().send().await?; - ResponseResult::<()>::Ok(()) + respond(()) }) .await; } diff --git a/examples/dices_bot/src/main.rs b/examples/dices_bot/src/main.rs index ea7f4424..0f5e46bd 100644 --- a/examples/dices_bot/src/main.rs +++ b/examples/dices_bot/src/main.rs @@ -15,7 +15,7 @@ async fn run() { teloxide::repl(bot, |message| async move { message.answer_dice().send().await?; - ResponseResult::<()>::Ok(()) + respond(()) }) .await; } diff --git a/src/prelude.rs b/src/prelude.rs index 3b2032d9..a7ce757e 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,7 +9,7 @@ pub use crate::{ Dispatcher, DispatcherHandlerRx, DispatcherHandlerRxExt, UpdateWithCx, }, error_handlers::{LoggingErrorHandler, OnError}, - requests::{Request, ResponseResult}, + requests::{respond, Request, ResponseResult}, types::{Message, Update}, Bot, RequestError, }; diff --git a/src/requests/mod.rs b/src/requests/mod.rs index 09f2af6c..bb104ddf 100644 --- a/src/requests/mod.rs +++ b/src/requests/mod.rs @@ -9,6 +9,11 @@ pub use all::*; /// A type that is returned after making a request to Telegram. pub type ResponseResult = Result; +/// A shortcut for `ResponseResult::Ok(val)`. +pub fn respond(val: T) -> ResponseResult { + ResponseResult::Ok(val) +} + /// Designates an API request. #[async_trait::async_trait] pub trait Request { From d7ad1f26ed3c0a6ab2ae0fda2b1c8824c3ea819f Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 2 Aug 2020 13:16:53 +0600 Subject: [PATCH 54/99] Update CHANGELOG.md --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3cf8cd..db431426 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [unreleased] + +### Added + - Allow arbitrary error types to be returned from (sub)transitions ([issue 242](https://github.com/teloxide/teloxide/issues/242)). + - The `respond` function, a shortcut for `ResponseResult::Ok(())`. + +### Changed + - Allow `bot_name` be `N`, where `N: Into + ...` in `commands_repl` & `commands_repl_with_listener`. + ## [0.3.0] - 2020-07-31 ### Added - Support for typed bot commands ([issue 152](https://github.com/teloxide/teloxide/issues/152)). From 817f492223332295bbd8f426822bac7c85e98844 Mon Sep 17 00:00:00 2001 From: PatriotRossii Date: Fri, 7 Aug 2020 05:55:06 +0500 Subject: [PATCH 55/99] Un Arc<_> Bot::parse_mode --- src/bot/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 1c205a21..bb008ef0 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -20,7 +20,7 @@ pub(crate) const TELOXIDE_PROXY: &str = "TELOXIDE_PROXY"; pub struct Bot { token: Arc, client: Client, - parse_mode: Arc>, + parse_mode: Option, } impl Bot { @@ -95,7 +95,7 @@ impl Bot { Self { token: Into::>::into(Into::::into(token)), client, - parse_mode: Arc::new(None), + parse_mode: None, } } } @@ -236,7 +236,7 @@ impl BotBuilder { Bot { client: self.client.unwrap_or_else(crate::utils::client_from_env), token: self.token.unwrap_or_else(|| get_env(TELOXIDE_TOKEN)).into(), - parse_mode: Arc::new(self.parse_mode), + parse_mode: self.parse_mode, } } } From 517afc0cfe80d8982835f330a28e8267b1fc3693 Mon Sep 17 00:00:00 2001 From: PatriotRossii Date: Fri, 7 Aug 2020 06:08:22 +0500 Subject: [PATCH 56/99] Remove unnecessary derefs --- src/bot/api.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bot/api.rs b/src/bot/api.rs index 619d0777..a4d0c2db 100644 --- a/src/bot/api.rs +++ b/src/bot/api.rs @@ -1007,10 +1007,10 @@ impl Bot { where T: Into, { - match self.parse_mode.deref() { + match self.parse_mode { None => EditMessageText::new(self.clone(), chat_or_inline_message, text), Some(parse_mode) => EditMessageText::new(self.clone(), chat_or_inline_message, text) - .parse_mode(*parse_mode.deref()), + .parse_mode(parse_mode), } } @@ -1033,10 +1033,10 @@ impl Bot { &self, chat_or_inline_message: ChatOrInlineMessage, ) -> EditMessageCaption { - match self.parse_mode.deref() { + match self.parse_mode { None => EditMessageCaption::new(self.clone(), chat_or_inline_message), Some(parse_mode) => EditMessageCaption::new(self.clone(), chat_or_inline_message) - .parse_mode(*parse_mode.deref()), + .parse_mode(parse_mode), } } @@ -1530,9 +1530,9 @@ impl Bot { builder: Builder, f: fn(Builder, ParseMode) -> Builder, ) -> Builder { - match self.parse_mode.deref() { + match self.parse_mode { None => builder, - Some(parse_mode) => f(builder, *parse_mode.deref()), + Some(parse_mode) => f(builder, parse_mode), } } } From b1ac80e244bc29943e1253238fb0f7577cb87a9b Mon Sep 17 00:00:00 2001 From: Eoan Ermine Date: Fri, 7 Aug 2020 12:02:30 +0500 Subject: [PATCH 57/99] Fix code formatting, remove unused import --- src/bot/api.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bot/api.rs b/src/bot/api.rs index a4d0c2db..f90c5123 100644 --- a/src/bot/api.rs +++ b/src/bot/api.rs @@ -21,7 +21,6 @@ use crate::{ }, Bot, }; -use std::ops::Deref; impl Bot { /// Use this method to receive incoming updates using long polling ([wiki]). @@ -1035,8 +1034,9 @@ impl Bot { ) -> EditMessageCaption { match self.parse_mode { None => EditMessageCaption::new(self.clone(), chat_or_inline_message), - Some(parse_mode) => EditMessageCaption::new(self.clone(), chat_or_inline_message) - .parse_mode(parse_mode), + Some(parse_mode) => { + EditMessageCaption::new(self.clone(), chat_or_inline_message).parse_mode(parse_mode) + } } } From 503f406eddedb701df2a7276ce451a519f835816 Mon Sep 17 00:00:00 2001 From: Waffle Date: Fri, 7 Aug 2020 00:48:17 +0300 Subject: [PATCH 58/99] Fix `edit_*` and `stop_inline_message_live_location` methods Previously they have been broken because of the wrong type of `ChatOrInlineMessage::Inline::inline_message_id` (`i32` instead of `String`), and wrong return type in case of inline editing messages (`Message` instead of `True`). This commit splits the methods into inline and non-inline versions, fixing the issue. --- src/bot/api.rs | 292 +++++++++++++----- src/dispatching/update_with_cx.rs | 15 +- .../all/edit_inline_message_caption.rs | 83 +++++ .../all/edit_inline_message_live_location.rs | 77 +++++ src/requests/all/edit_inline_message_media.rs | 78 +++++ .../all/edit_inline_message_reply_markup.rs | 62 ++++ src/requests/all/edit_inline_message_text.rs | 98 ++++++ src/requests/all/edit_message_caption.rs | 35 ++- .../all/edit_message_live_location.rs | 40 ++- src/requests/all/edit_message_media.rs | 55 ++-- src/requests/all/edit_message_reply_markup.rs | 33 +- src/requests/all/edit_message_text.rs | 35 ++- src/requests/all/mod.rs | 12 + .../all/stop_inline_message_live_location.rs | 62 ++++ .../all/stop_message_live_location.rs | 33 +- 15 files changed, 844 insertions(+), 166 deletions(-) create mode 100644 src/requests/all/edit_inline_message_caption.rs create mode 100644 src/requests/all/edit_inline_message_live_location.rs create mode 100644 src/requests/all/edit_inline_message_media.rs create mode 100644 src/requests/all/edit_inline_message_reply_markup.rs create mode 100644 src/requests/all/edit_inline_message_text.rs create mode 100644 src/requests/all/stop_inline_message_live_location.rs diff --git a/src/bot/api.rs b/src/bot/api.rs index f90c5123..3f3fb8c7 100644 --- a/src/bot/api.rs +++ b/src/bot/api.rs @@ -2,22 +2,24 @@ use crate::{ requests::{ AddStickerToSet, AnswerCallbackQuery, AnswerInlineQuery, AnswerPreCheckoutQuery, AnswerShippingQuery, CreateNewStickerSet, DeleteChatPhoto, DeleteChatStickerSet, - DeleteMessage, DeleteStickerFromSet, DeleteWebhook, EditMessageCaption, - EditMessageLiveLocation, EditMessageMedia, EditMessageReplyMarkup, EditMessageText, - ExportChatInviteLink, ForwardMessage, GetChat, GetChatAdministrators, GetChatMember, - GetChatMembersCount, GetFile, GetGameHighScores, GetMe, GetMyCommands, GetStickerSet, - GetUpdates, GetUserProfilePhotos, GetWebhookInfo, KickChatMember, LeaveChat, - PinChatMessage, PromoteChatMember, RestrictChatMember, SendAnimation, SendAudio, - SendChatAction, SendChatActionKind, SendContact, SendDice, SendDocument, SendGame, - SendInvoice, SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendPoll, SendSticker, - SendVenue, SendVideo, SendVideoNote, SendVoice, SetChatAdministratorCustomTitle, - SetChatDescription, SetChatPermissions, SetChatPhoto, SetChatStickerSet, SetChatTitle, - SetGameScore, SetMyCommands, SetStickerPositionInSet, SetStickerSetThumb, SetWebhook, - StopMessageLiveLocation, StopPoll, UnbanChatMember, UnpinChatMessage, UploadStickerFile, + DeleteMessage, DeleteStickerFromSet, DeleteWebhook, EditInlineMessageCaption, + EditInlineMessageLiveLocation, EditInlineMessageMedia, EditInlineMessageReplyMarkup, + EditInlineMessageText, EditMessageCaption, EditMessageLiveLocation, EditMessageMedia, + EditMessageReplyMarkup, EditMessageText, ExportChatInviteLink, ForwardMessage, GetChat, + GetChatAdministrators, GetChatMember, GetChatMembersCount, GetFile, GetGameHighScores, + GetMe, GetMyCommands, GetStickerSet, GetUpdates, GetUserProfilePhotos, GetWebhookInfo, + KickChatMember, LeaveChat, PinChatMessage, PromoteChatMember, RestrictChatMember, + SendAnimation, SendAudio, SendChatAction, SendChatActionKind, SendContact, SendDice, + SendDocument, SendGame, SendInvoice, SendLocation, SendMediaGroup, SendMessage, SendPhoto, + SendPoll, SendSticker, SendVenue, SendVideo, SendVideoNote, SendVoice, + SetChatAdministratorCustomTitle, SetChatDescription, SetChatPermissions, SetChatPhoto, + SetChatStickerSet, SetChatTitle, SetGameScore, SetMyCommands, SetStickerPositionInSet, + SetStickerSetThumb, SetWebhook, StopInlineMessageLiveLocation, StopMessageLiveLocation, + StopPoll, UnbanChatMember, UnpinChatMessage, UploadStickerFile, }, types::{ - BotCommand, ChatId, ChatOrInlineMessage, ChatPermissions, InlineQueryResult, InputFile, - InputMedia, LabeledPrice, ParseMode, StickerType, + BotCommand, ChatId, ChatPermissions, InlineQueryResult, InputFile, InputMedia, + LabeledPrice, ParseMode, StickerType, TargetMessage, }, Bot, }; @@ -409,42 +411,89 @@ impl Bot { /// Use this method to edit live location messages. /// /// A location can be edited until its live_period expires or editing is - /// explicitly disabled by a call to stopMessageLiveLocation. On success, if - /// the edited message was sent by the bot, the edited [`Message`] is - /// returned, otherwise [`True`] is returned. + /// explicitly disabled by a call to stopMessageLiveLocation. On success, + /// the edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation). /// + /// [`Message`]: crate::types::Message + /// /// # Params /// - `latitude`: Latitude of new location. /// - `longitude`: Longitude of new location. - /// - /// [`Message`]: crate::types::Message - /// [`True`]: crate::types::True - pub fn edit_message_live_location( + pub fn edit_message_live_location( &self, - chat_or_inline_message: ChatOrInlineMessage, + chat_id: C, + message_id: i32, latitude: f32, longitude: f32, - ) -> EditMessageLiveLocation { - EditMessageLiveLocation::new(self.clone(), chat_or_inline_message, latitude, longitude) + ) -> EditMessageLiveLocation + where + C: Into, + { + EditMessageLiveLocation::new(self.clone(), chat_id, message_id, latitude, longitude) + } + + /// Use this method to edit live location messages sent via the bot. + /// + /// A location can be edited until its live_period expires or editing is + /// explicitly disabled by a call to stopMessageLiveLocation. On success, + /// [`True`] is returned. + /// + /// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation). + /// + /// [`True`]: crate::types::True + /// + /// # Params + /// - `latitude`: Latitude of new location. + /// - `longitude`: Longitude of new location. + pub fn edit_inline_message_live_location( + &self, + inline_message_id: I, + latitude: f32, + longitude: f32, + ) -> EditInlineMessageLiveLocation + where + I: Into, + { + EditInlineMessageLiveLocation::new(self.clone(), inline_message_id, latitude, longitude) } /// Use this method to stop updating a live location message before /// `live_period` expires. /// - /// On success, if the message was sent by the bot, the sent [`Message`] is - /// returned, otherwise [`True`] is returned. + /// On success, the sent [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation). /// /// [`Message`]: crate::types::Message - /// [`True`]: crate::types::True - pub fn stop_message_live_location( + pub fn stop_message_live_location( &self, - chat_or_inline_message: ChatOrInlineMessage, - ) -> StopMessageLiveLocation { - StopMessageLiveLocation::new(self.clone(), chat_or_inline_message) + chat_id: C, + message_id: i32, + ) -> StopMessageLiveLocation + where + C: Into, + { + StopMessageLiveLocation::new(self.clone(), chat_id, message_id) + } + + /// Use this method to stop updating a live location message (sent via the + /// bot) before `live_period` expires. + /// + /// On success, [`True`] is returned. + /// + /// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation). + /// + /// [`True`]: crate::types::True + pub fn stop_inline_message_live_location( + &self, + inline_message_id: I, + ) -> StopInlineMessageLiveLocation + where + I: Into, + { + StopInlineMessageLiveLocation::new(self.clone(), inline_message_id) } /// Use this method to send information about a venue. @@ -982,45 +1031,103 @@ impl Bot { /// Use this method to edit text and game messages. /// - /// On success, if edited message is sent by the bot, the edited [`Message`] - /// is returned, otherwise [`True`] is returned. + /// On success, the edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagetext). /// - /// # Params - /// - New text of the message. - /// /// [`Message`]: crate::types::Message - /// [`True`]: crate::types::True + /// + /// # Params + /// + /// - `chat_id`: Unique identifier for the target chat or username of the + /// target channel (in the format `@channelusername`). + /// - `message_id`: Identifier of the message to edit. + /// - `text`: New text of the message. /// /// # Notes + /// /// Uses [a default parse mode] if specified in [`BotBuilder`]. /// /// [a default parse mode]: crate::BotBuilder::parse_mode /// [`BotBuilder`]: crate::BotBuilder - pub fn edit_message_text( - &self, - chat_or_inline_message: ChatOrInlineMessage, - text: T, - ) -> EditMessageText + pub fn edit_message_text(&self, chat_id: C, message_id: i32, text: T) -> EditMessageText where + C: Into, T: Into, { match self.parse_mode { - None => EditMessageText::new(self.clone(), chat_or_inline_message, text), - Some(parse_mode) => EditMessageText::new(self.clone(), chat_or_inline_message, text) + None => EditMessageText::new(self.clone(), chat_id, message_id, text), + Some(parse_mode) => EditMessageText::new(self.clone(), chat_id, message_id, text) .parse_mode(parse_mode), } } - /// Use this method to edit captions of messages. + /// Use this method to edit text and game messages sent via the bot. /// - /// On success, if edited message is sent by the bot, the edited [`Message`] - /// is returned, otherwise [`True`] is returned. + /// On success, [`True`] is returned. + /// + /// [The official docs](https://core.telegram.org/bots/api#editmessagetext). + /// + /// [`True`]: crate::types::True + /// + /// # Params + /// + /// - `inline_message_id`: Identifier of the inline message. + /// - `text`: New text of the message. + /// + /// # Notes + /// + /// Uses [a default parse mode] if specified in [`BotBuilder`]. + /// + /// [a default parse mode]: crate::BotBuilder::parse_mode + /// [`BotBuilder`]: crate::BotBuilder + pub fn edit_inline_message_text( + &self, + inline_message_id: I, + text: T, + ) -> EditInlineMessageText + where + I: Into, + T: Into, + { + match self.parse_mode { + None => EditInlineMessageText::new(self.clone(), inline_message_id, text), + Some(parse_mode) => EditInlineMessageText::new(self.clone(), inline_message_id, text) + .parse_mode(parse_mode), + } + } + + /// Use this method to edit captions of messages sent via the bot. + /// + /// On success, [`True`] is returned. + /// + /// [The official docs](https://core.telegram.org/bots/api#editmessagecaption). + /// + /// [`True`]: crate::types::True + /// + /// # Notes + /// + /// Uses [a default parse mode] if specified in [`BotBuilder`]. + /// + /// [a default parse mode]: crate::BotBuilder::parse_mode + /// [`BotBuilder`]: crate::BotBuilder + pub fn edit_message_caption(&self, chat_id: C, message_id: i32) -> EditMessageCaption + where + C: Into, + { + match self.parse_mode { + None => EditMessageCaption::new(self.clone(), chat_id, message_id), + Some(parse_mode) => EditMessageCaption::new(self.clone(), chat_id, message_id) + .parse_mode(parse_mode), + } + } + + /// Use this method to edit captions of messages sent via the bot. + /// + /// On success, [`True`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagecaption). /// - /// [`Message`]: crate::types::Message /// [`True`]: crate::types::True /// /// # Notes @@ -1028,15 +1135,14 @@ impl Bot { /// /// [a default parse mode]: crate::BotBuilder::parse_mode /// [`BotBuilder`]: crate::BotBuilder - pub fn edit_message_caption( - &self, - chat_or_inline_message: ChatOrInlineMessage, - ) -> EditMessageCaption { + pub fn edit_inline_message_caption(&self, inline_message_id: I) -> EditInlineMessageCaption + where + I: Into, + { match self.parse_mode { - None => EditMessageCaption::new(self.clone(), chat_or_inline_message), - Some(parse_mode) => { - EditMessageCaption::new(self.clone(), chat_or_inline_message).parse_mode(parse_mode) - } + None => EditInlineMessageCaption::new(self.clone(), inline_message_id), + Some(parse_mode) => EditInlineMessageCaption::new(self.clone(), inline_message_id) + .parse_mode(parse_mode), } } @@ -1045,37 +1151,81 @@ impl Bot { /// /// If a message is a part of a message album, then it can be edited only to /// a photo or a video. Otherwise, message type can be changed - /// arbitrarily. When inline message is edited, new file can't be - /// uploaded. Use previously uploaded file via its `file_id` or specify - /// a URL. On success, if the edited message was sent by the bot, the - /// edited [`Message`] is returned, otherwise [`True`] is returned. + /// arbitrarily. On success, the edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagemedia). /// /// [`Message`]: crate::types::Message - /// [`True`]: crate::types::True - pub fn edit_message_media( + pub fn edit_message_media( &self, - chat_or_inline_message: ChatOrInlineMessage, + chat_id: C, + message_id: i32, media: InputMedia, - ) -> EditMessageMedia { - EditMessageMedia::new(self.clone(), chat_or_inline_message, media) + ) -> EditMessageMedia + where + C: Into, + { + EditMessageMedia::new(self.clone(), chat_id, message_id, media) + } + + /// Use this method to edit animation, audio, document, photo, or video + /// messages sent via the bot. + /// + /// If a message is a part of a message album, then it can be edited only to + /// a photo or a video. Otherwise, message type can be changed + /// arbitrarily. When this method is used, new file can't be uploaded. + /// Use previously uploaded file via its `file_id` or specify a URL. On + /// success, [`True`] is returned. + /// + /// [The official docs](https://core.telegram.org/bots/api#editmessagemedia). + /// + /// [`True`]: crate::types::True + pub fn edit_inline_message_media( + &self, + inline_message_id: I, + media: InputMedia, + ) -> EditInlineMessageMedia + where + I: Into, + { + EditInlineMessageMedia::new(self.clone(), inline_message_id, media) } /// Use this method to edit only the reply markup of messages. /// - /// On success, if edited message is sent by the bot, the edited [`Message`] - /// is returned, otherwise [`True`] is returned. + /// On success, the edited [`Message`] is returned. + /// + /// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup). + /// + /// [`Message`]: crate::types::Message + pub fn edit_message_reply_markup( + &self, + chat_id: C, + message_id: i32, + ) -> EditMessageReplyMarkup + where + C: Into, + { + EditMessageReplyMarkup::new(self.clone(), chat_id, message_id) + } + + /// Use this method to edit only the reply markup of messages sent via the + /// bot. + /// + /// On success, [`True`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup). /// /// [`Message`]: crate::types::Message /// [`True`]: crate::types::True - pub fn edit_message_reply_markup( + pub fn edit_inline_message_reply_markup( &self, - chat_or_inline_message: ChatOrInlineMessage, - ) -> EditMessageReplyMarkup { - EditMessageReplyMarkup::new(self.clone(), chat_or_inline_message) + inline_message_id: I, + ) -> EditInlineMessageReplyMarkup + where + I: Into, + { + EditInlineMessageReplyMarkup::new(self.clone(), inline_message_id) } /// Use this method to stop a poll which was sent by the bot. diff --git a/src/dispatching/update_with_cx.rs b/src/dispatching/update_with_cx.rs index 66c0beec..f3fa74e1 100644 --- a/src/dispatching/update_with_cx.rs +++ b/src/dispatching/update_with_cx.rs @@ -6,7 +6,7 @@ use crate::{ SendLocation, SendMediaGroup, SendMessage, SendPhoto, SendSticker, SendVenue, SendVideo, SendVideoNote, SendVoice, }, - types::{ChatId, ChatOrInlineMessage, InputFile, InputMedia, Message}, + types::{ChatId, InputFile, InputMedia, Message}, Bot, }; @@ -130,20 +130,11 @@ impl UpdateWithCx { where T: Into, { - self.bot.edit_message_text( - ChatOrInlineMessage::Chat { - chat_id: self.update.chat.id.into(), - message_id: self.update.id, - }, - text, - ) + self.bot.edit_message_text(self.update.chat.id, self.update.id, text) } pub fn edit_message_caption(&self) -> EditMessageCaption { - self.bot.edit_message_caption(ChatOrInlineMessage::Chat { - chat_id: self.update.chat.id.into(), - message_id: self.update.id, - }) + self.bot.edit_message_caption(self.update.chat.id, self.update.id) } pub fn delete_message(&self) -> DeleteMessage { diff --git a/src/requests/all/edit_inline_message_caption.rs b/src/requests/all/edit_inline_message_caption.rs new file mode 100644 index 00000000..e777f17c --- /dev/null +++ b/src/requests/all/edit_inline_message_caption.rs @@ -0,0 +1,83 @@ +use serde::Serialize; + +use crate::{ + net, + requests::{Request, ResponseResult}, + types::{InlineKeyboardMarkup, ParseMode, True}, + Bot, +}; + +/// Use this method to edit captions of messages sent via the bot. +/// +/// On success, [`True`] is returned. +/// +/// [The official docs](https://core.telegram.org/bots/api#editmessagecaption). +/// +/// [`True`]: crate::types::True +#[serde_with_macros::skip_serializing_none] +#[derive(Debug, Clone, Serialize)] +pub struct EditInlineMessageCaption { + #[serde(skip_serializing)] + bot: Bot, + inline_message_id: String, + caption: Option, + parse_mode: Option, + reply_markup: Option, +} + +#[async_trait::async_trait] +impl Request for EditInlineMessageCaption { + type Output = True; + + async fn send(&self) -> ResponseResult { + net::request_json(self.bot.client(), self.bot.token(), "editMessageCaption", &self).await + } +} + +impl EditInlineMessageCaption { + pub(crate) fn new(bot: Bot, inline_message_id: I) -> Self + where + I: Into, + { + let inline_message_id = inline_message_id.into(); + Self { bot, inline_message_id, caption: None, parse_mode: None, reply_markup: None } + } + + /// Identifier of the inline message. + pub fn inline_message_id(mut self, val: T) -> Self + where + T: Into, + { + self.inline_message_id = val.into(); + self + } + + /// New caption of the message. + pub fn caption(mut self, val: T) -> Self + where + T: Into, + { + self.caption = Some(val.into()); + self + } + + /// Send [Markdown] or [HTML], if you want Telegram apps to show + /// [bold, italic, fixed-width text or inline URLs] in the media caption. + /// + /// [Markdown]: crate::types::ParseMode::Markdown + /// [HTML]: crate::types::ParseMode::HTML + /// [bold, italic, fixed-width text or inline URLs]: + /// crate::types::ParseMode + pub fn parse_mode(mut self, val: ParseMode) -> Self { + self.parse_mode = Some(val); + self + } + + /// A JSON-serialized object for an [inline keyboard]. + /// + /// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating + pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self { + self.reply_markup = Some(val); + self + } +} diff --git a/src/requests/all/edit_inline_message_live_location.rs b/src/requests/all/edit_inline_message_live_location.rs new file mode 100644 index 00000000..4b267427 --- /dev/null +++ b/src/requests/all/edit_inline_message_live_location.rs @@ -0,0 +1,77 @@ +use serde::Serialize; + +use crate::{ + net, + requests::{Request, ResponseResult}, + types::{InlineKeyboardMarkup, True}, + Bot, +}; + +/// Use this method to edit live location messages sent via the bot. +/// +/// A location can be edited until its live_period expires or editing is +/// explicitly disabled by a call to stopMessageLiveLocation. On success, +/// [`True`] is returned. +/// +/// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation). +/// +/// [`True`]: crate::types::True +#[serde_with_macros::skip_serializing_none] +#[derive(Debug, Clone, Serialize)] +pub struct EditInlineMessageLiveLocation { + #[serde(skip_serializing)] + bot: Bot, + inline_message_id: String, + latitude: f32, + longitude: f32, + reply_markup: Option, +} + +#[async_trait::async_trait] +impl Request for EditInlineMessageLiveLocation { + type Output = True; + + async fn send(&self) -> ResponseResult { + net::request_json(self.bot.client(), self.bot.token(), "editMessageLiveLocation", &self) + .await + } +} + +impl EditInlineMessageLiveLocation { + pub(crate) fn new(bot: Bot, inline_message_id: I, latitude: f32, longitude: f32) -> Self + where + I: Into, + { + let inline_message_id = inline_message_id.into(); + Self { bot, inline_message_id, latitude, longitude, reply_markup: None } + } + + /// Identifier of the inline message. + pub fn inline_message_id(mut self, val: T) -> Self + where + T: Into, + { + self.inline_message_id = val.into(); + self + } + + /// Latitude of new location. + pub fn latitude(mut self, val: f32) -> Self { + self.latitude = val; + self + } + + /// Longitude of new location. + pub fn longitude(mut self, val: f32) -> Self { + self.longitude = val; + self + } + + /// A JSON-serialized object for a new [inline keyboard]. + /// + /// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating + pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self { + self.reply_markup = Some(val); + self + } +} diff --git a/src/requests/all/edit_inline_message_media.rs b/src/requests/all/edit_inline_message_media.rs new file mode 100644 index 00000000..9a11f126 --- /dev/null +++ b/src/requests/all/edit_inline_message_media.rs @@ -0,0 +1,78 @@ +use crate::{ + net, + requests::{form_builder::FormBuilder, Request, ResponseResult}, + types::{InlineKeyboardMarkup, InputMedia, True}, + Bot, +}; + +/// Use this method to edit animation, audio, document, photo, or video +/// messages sent via the bot. +/// +/// If a message is a part of a message album, then it can be edited only to a +/// photo or a video. Otherwise, message type can be changed arbitrarily. When +/// this method is used, new file can't be uploaded. Use previously +/// uploaded file via its `file_id` or specify a URL. On success, [`True`] is +/// returned. +/// +/// [The official docs](https://core.telegram.org/bots/api#editmessagemedia). +/// +/// [`True`]: crate::types::True +#[derive(Debug, Clone)] +pub struct EditInlineMessageMedia { + bot: Bot, + inline_message_id: String, + media: InputMedia, + reply_markup: Option, +} + +#[async_trait::async_trait] +impl Request for EditInlineMessageMedia { + type Output = True; + + async fn send(&self) -> ResponseResult { + net::request_multipart( + self.bot.client(), + self.bot.token(), + "editMessageMedia", + FormBuilder::new() + .add_text("media", &self.media) + .add_text("reply_markup", &self.reply_markup) + .add_text("inline_message_id", &self.inline_message_id) + .build(), + ) + .await + } +} + +impl EditInlineMessageMedia { + pub(crate) fn new(bot: Bot, inline_message_id: I, media: InputMedia) -> Self + where + I: Into, + { + let inline_message_id = inline_message_id.into(); + Self { bot, inline_message_id, media, reply_markup: None } + } + + /// Identifier of the inline message. + pub fn inline_message_id(mut self, val: T) -> Self + where + T: Into, + { + self.inline_message_id = val.into(); + self + } + + /// A JSON-serialized object for a new media content of the message. + pub fn media(mut self, val: InputMedia) -> Self { + self.media = val; + self + } + + /// A JSON-serialized object for a new [inline keyboard]. + /// + /// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating + pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self { + self.reply_markup = Some(val); + self + } +} diff --git a/src/requests/all/edit_inline_message_reply_markup.rs b/src/requests/all/edit_inline_message_reply_markup.rs new file mode 100644 index 00000000..cd96c686 --- /dev/null +++ b/src/requests/all/edit_inline_message_reply_markup.rs @@ -0,0 +1,62 @@ +use serde::Serialize; + +use crate::{ + net, + requests::{Request, ResponseResult}, + types::{InlineKeyboardMarkup, True}, + Bot, +}; + +/// Use this method to edit only the reply markup of messages sent via the bot. +/// +/// On success, [`True`] is returned. +/// +/// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup). +/// +/// [`Message`]: crate::types::Message +/// [`True`]: crate::types::True +#[serde_with_macros::skip_serializing_none] +#[derive(Debug, Clone, Serialize)] +pub struct EditInlineMessageReplyMarkup { + #[serde(skip_serializing)] + bot: Bot, + inline_message_id: String, + reply_markup: Option, +} + +#[async_trait::async_trait] +impl Request for EditInlineMessageReplyMarkup { + type Output = True; + + async fn send(&self) -> ResponseResult { + net::request_json(self.bot.client(), self.bot.token(), "editMessageReplyMarkup", &self) + .await + } +} + +impl EditInlineMessageReplyMarkup { + pub(crate) fn new(bot: Bot, inline_message_id: I) -> Self + where + I: Into, + { + let inline_message_id = inline_message_id.into(); + Self { bot, inline_message_id, reply_markup: None } + } + + /// Identifier of the inline message. + pub fn inline_message_id(mut self, val: T) -> Self + where + T: Into, + { + self.inline_message_id = val.into(); + self + } + + /// A JSON-serialized object for an [inline keyboard]. + /// + /// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating + pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self { + self.reply_markup = Some(val); + self + } +} diff --git a/src/requests/all/edit_inline_message_text.rs b/src/requests/all/edit_inline_message_text.rs new file mode 100644 index 00000000..2b266314 --- /dev/null +++ b/src/requests/all/edit_inline_message_text.rs @@ -0,0 +1,98 @@ +use serde::Serialize; + +use crate::{ + net, + requests::{Request, ResponseResult}, + types::{InlineKeyboardMarkup, Message, ParseMode}, + Bot, +}; + +/// Use this method to edit text and game messages sent via the bot. +/// +/// On success, [`True`] is returned. +/// +/// [The official docs](https://core.telegram.org/bots/api#editmessagetext). +/// +/// [`True`]: crate::types::True +#[serde_with_macros::skip_serializing_none] +#[derive(Debug, Clone, Serialize)] +pub struct EditInlineMessageText { + #[serde(skip_serializing)] + bot: Bot, + inline_message_id: String, + text: String, + parse_mode: Option, + disable_web_page_preview: Option, + reply_markup: Option, +} + +#[async_trait::async_trait] +impl Request for EditInlineMessageText { + type Output = Message; + + async fn send(&self) -> ResponseResult { + net::request_json(self.bot.client(), self.bot.token(), "editMessageText", &self).await + } +} + +impl EditInlineMessageText { + pub(crate) fn new(bot: Bot, inline_message_id: I, text: T) -> Self + where + I: Into, + T: Into, + { + let inline_message_id = inline_message_id.into(); + let text = text.into(); + Self { + bot, + inline_message_id, + text, + parse_mode: None, + disable_web_page_preview: None, + reply_markup: None, + } + } + + /// Identifier of the inline message. + pub fn inline_message_id(mut self, val: T) -> Self + where + T: Into, + { + self.inline_message_id = val.into(); + self + } + + /// New text of the message. + pub fn text(mut self, val: T) -> Self + where + T: Into, + { + self.text = val.into(); + self + } + + /// Send [Markdown] or [HTML], if you want Telegram apps to show [bold, + /// italic, fixed-width text or inline URLs] in your bot's message. + /// + /// [Markdown]: https://core.telegram.org/bots/api#markdown-style + /// [HTML]: https://core.telegram.org/bots/api#html-style + /// [bold, italic, fixed-width text or inline URLs]: https://core.telegram.org/bots/api#formatting-options + pub fn parse_mode(mut self, val: ParseMode) -> Self { + self.parse_mode = Some(val); + self + } + + /// Disables link previews for links in this message. + pub fn disable_web_page_preview(mut self, val: bool) -> Self { + self.disable_web_page_preview = Some(val); + self + } + + /// A JSON-serialized object for an [inline keyboard]. + /// + /// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating + pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self { + self.reply_markup = Some(val); + self + } +} diff --git a/src/requests/all/edit_message_caption.rs b/src/requests/all/edit_message_caption.rs index 2b9f2839..9294af93 100644 --- a/src/requests/all/edit_message_caption.rs +++ b/src/requests/all/edit_message_caption.rs @@ -3,26 +3,24 @@ use serde::Serialize; use crate::{ net, requests::{Request, ResponseResult}, - types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode}, + types::{ChatId, InlineKeyboardMarkup, Message, ParseMode}, Bot, }; -/// Use this method to edit captions of messages. +/// Use this method to edit captions of messages sent by the bot. /// -/// On success, if edited message is sent by the bot, the edited [`Message`] is -/// returned, otherwise [`True`] is returned. +/// On success, the edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagecaption). /// /// [`Message`]: crate::types::Message -/// [`True`]: crate::types::True #[serde_with_macros::skip_serializing_none] #[derive(Debug, Clone, Serialize)] pub struct EditMessageCaption { #[serde(skip_serializing)] bot: Bot, - #[serde(flatten)] - chat_or_inline_message: ChatOrInlineMessage, + chat_id: ChatId, + message_id: i32, caption: Option, parse_mode: Option, reply_markup: Option, @@ -38,12 +36,27 @@ impl Request for EditMessageCaption { } impl EditMessageCaption { - pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self { - Self { bot, chat_or_inline_message, caption: None, parse_mode: None, reply_markup: None } + pub(crate) fn new(bot: Bot, chat_id: C, message_id: i32) -> Self + where + C: Into, + { + let chat_id = chat_id.into(); + Self { bot, chat_id, message_id, caption: None, parse_mode: None, reply_markup: None } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Unique identifier for the target chat or username of the target channel + /// (in the format `@channelusername`) + pub fn chat_id(mut self, val: T) -> Self + where + T: Into, + { + self.chat_id = val.into(); + self + } + + /// Identifier of the message to edit + pub fn message_id(mut self, val: i32) -> Self { + self.message_id = val; self } diff --git a/src/requests/all/edit_message_live_location.rs b/src/requests/all/edit_message_live_location.rs index 78fd163e..c5afd295 100644 --- a/src/requests/all/edit_message_live_location.rs +++ b/src/requests/all/edit_message_live_location.rs @@ -3,28 +3,26 @@ use serde::Serialize; use crate::{ net, requests::{Request, ResponseResult}, - types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message}, + types::{ChatId, InlineKeyboardMarkup, Message}, Bot, }; /// Use this method to edit live location messages. /// /// A location can be edited until its live_period expires or editing is -/// explicitly disabled by a call to stopMessageLiveLocation. On success, if the -/// edited message was sent by the bot, the edited [`Message`] is returned, -/// otherwise [`True`] is returned. +/// explicitly disabled by a call to stopMessageLiveLocation. On success, the +/// edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagelivelocation). /// /// [`Message`]: crate::types::Message -/// [`True`]: crate::types::True #[serde_with_macros::skip_serializing_none] #[derive(Debug, Clone, Serialize)] pub struct EditMessageLiveLocation { #[serde(skip_serializing)] bot: Bot, - #[serde(flatten)] - chat_or_inline_message: ChatOrInlineMessage, + chat_id: ChatId, + message_id: i32, latitude: f32, longitude: f32, reply_markup: Option, @@ -41,17 +39,33 @@ impl Request for EditMessageLiveLocation { } impl EditMessageLiveLocation { - pub(crate) fn new( + pub(crate) fn new( bot: Bot, - chat_or_inline_message: ChatOrInlineMessage, + chat_id: C, + message_id: i32, latitude: f32, longitude: f32, - ) -> Self { - Self { bot, chat_or_inline_message, latitude, longitude, reply_markup: None } + ) -> Self + where + C: Into, + { + let chat_id = chat_id.into(); + Self { bot, chat_id, message_id, latitude, longitude, reply_markup: None } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Unique identifier for the target chat or username of the target channel + /// (in the format `@channelusername`) + pub fn chat_id(mut self, val: T) -> Self + where + T: Into, + { + self.chat_id = val.into(); + self + } + + /// Identifier of the message to edit + pub fn message_id(mut self, val: i32) -> Self { + self.message_id = val; self } diff --git a/src/requests/all/edit_message_media.rs b/src/requests/all/edit_message_media.rs index fd49c5c0..7f15ed5f 100644 --- a/src/requests/all/edit_message_media.rs +++ b/src/requests/all/edit_message_media.rs @@ -1,7 +1,7 @@ use crate::{ net, requests::{form_builder::FormBuilder, Request, ResponseResult}, - types::{ChatOrInlineMessage, InlineKeyboardMarkup, InputMedia, Message}, + types::{ChatId, InlineKeyboardMarkup, InputMedia, Message}, Bot, }; @@ -9,20 +9,17 @@ use crate::{ /// messages. /// /// If a message is a part of a message album, then it can be edited only to a -/// photo or a video. Otherwise, message type can be changed arbitrarily. When -/// inline message is edited, new file can't be uploaded. Use previously -/// uploaded file via its `file_id` or specify a URL. On success, if the edited -/// message was sent by the bot, the edited [`Message`] is returned, -/// otherwise [`True`] is returned. +/// photo or a video. Otherwise, message type can be changed arbitrarily. On +/// success, the edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagemedia). /// /// [`Message`]: crate::types::Message -/// [`True`]: crate::types::True #[derive(Debug, Clone)] pub struct EditMessageMedia { bot: Bot, - chat_or_inline_message: ChatOrInlineMessage, + chat_id: ChatId, + message_id: i32, media: InputMedia, reply_markup: Option, } @@ -32,22 +29,13 @@ impl Request for EditMessageMedia { type Output = Message; async fn send(&self) -> ResponseResult { - let mut params = FormBuilder::new(); - - match &self.chat_or_inline_message { - ChatOrInlineMessage::Chat { chat_id, message_id } => { - params = params.add_text("chat_id", chat_id).add_text("message_id", message_id); - } - ChatOrInlineMessage::Inline { inline_message_id } => { - params = params.add_text("inline_message_id", inline_message_id); - } - } - net::request_multipart( self.bot.client(), self.bot.token(), "editMessageMedia", - params + FormBuilder::new() + .add_text("chat_id", &self.chat_id) + .add_text("message_id", &self.message_id) .add_text("media", &self.media) .add_text("reply_markup", &self.reply_markup) .build(), @@ -57,16 +45,27 @@ impl Request for EditMessageMedia { } impl EditMessageMedia { - pub(crate) fn new( - bot: Bot, - chat_or_inline_message: ChatOrInlineMessage, - media: InputMedia, - ) -> Self { - Self { bot, chat_or_inline_message, media, reply_markup: None } + pub(crate) fn new(bot: Bot, chat_id: C, message_id: i32, media: InputMedia) -> Self + where + C: Into, + { + let chat_id = chat_id.into(); + Self { bot, chat_id, message_id, media, reply_markup: None } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Unique identifier for the target chat or username of the target channel + /// (in the format `@channelusername`) + pub fn chat_id(mut self, val: T) -> Self + where + T: Into, + { + self.chat_id = val.into(); + self + } + + /// Identifier of the message to edit + pub fn message_id(mut self, val: i32) -> Self { + self.message_id = val; self } diff --git a/src/requests/all/edit_message_reply_markup.rs b/src/requests/all/edit_message_reply_markup.rs index cdfd9e67..66aab5bf 100644 --- a/src/requests/all/edit_message_reply_markup.rs +++ b/src/requests/all/edit_message_reply_markup.rs @@ -3,26 +3,24 @@ use serde::Serialize; use crate::{ net, requests::{Request, ResponseResult}, - types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message}, + types::{ChatId, InlineKeyboardMarkup, Message}, Bot, }; /// Use this method to edit only the reply markup of messages. /// -/// On success, if edited message is sent by the bot, the edited [`Message`] is -/// returned, otherwise [`True`] is returned. +/// On success, the edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagereplymarkup). /// /// [`Message`]: crate::types::Message -/// [`True`]: crate::types::True #[serde_with_macros::skip_serializing_none] #[derive(Debug, Clone, Serialize)] pub struct EditMessageReplyMarkup { #[serde(skip_serializing)] bot: Bot, - #[serde(flatten)] - chat_or_inline_message: ChatOrInlineMessage, + chat_id: ChatId, + message_id: i32, reply_markup: Option, } @@ -37,12 +35,27 @@ impl Request for EditMessageReplyMarkup { } impl EditMessageReplyMarkup { - pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self { - Self { bot, chat_or_inline_message, reply_markup: None } + pub(crate) fn new(bot: Bot, chat_id: C, message_id: i32) -> Self + where + C: Into, + { + let chat_id = chat_id.into(); + Self { bot, chat_id, message_id, reply_markup: None } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Unique identifier for the target chat or username of the target channel + /// (in the format `@channelusername`) + pub fn chat_id(mut self, val: T) -> Self + where + T: Into, + { + self.chat_id = val.into(); + self + } + + /// Identifier of the message to edit + pub fn message_id(mut self, val: i32) -> Self { + self.message_id = val; self } diff --git a/src/requests/all/edit_message_text.rs b/src/requests/all/edit_message_text.rs index 71c7aeed..12251313 100644 --- a/src/requests/all/edit_message_text.rs +++ b/src/requests/all/edit_message_text.rs @@ -3,26 +3,24 @@ use serde::Serialize; use crate::{ net, requests::{Request, ResponseResult}, - types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message, ParseMode}, + types::{ChatId, InlineKeyboardMarkup, Message, ParseMode}, Bot, }; /// Use this method to edit text and game messages. /// -/// On success, if edited message is sent by the bot, the edited [`Message`] is -/// returned, otherwise [`True`] is returned. +/// On success, the edited [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#editmessagetext). /// /// [`Message`]: crate::types::Message -/// [`True`]: crate::types::True #[serde_with_macros::skip_serializing_none] #[derive(Debug, Clone, Serialize)] pub struct EditMessageText { #[serde(skip_serializing)] bot: Bot, - #[serde(flatten)] - chat_or_inline_message: ChatOrInlineMessage, + chat_id: ChatId, + message_id: i32, text: String, parse_mode: Option, disable_web_page_preview: Option, @@ -39,22 +37,37 @@ impl Request for EditMessageText { } impl EditMessageText { - pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, text: T) -> Self + pub(crate) fn new(bot: Bot, chat_id: C, message_id: i32, text: T) -> Self where + C: Into, T: Into, { + let chat_id = chat_id.into(); + let text = text.into(); Self { bot, - chat_or_inline_message, - text: text.into(), + chat_id, + message_id, + text, parse_mode: None, disable_web_page_preview: None, reply_markup: None, } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Unique identifier for the target chat or username of the target channel + /// (in the format `@channelusername`) + pub fn chat_id(mut self, val: T) -> Self + where + T: Into, + { + self.chat_id = val.into(); + self + } + + /// Identifier of the message to edit + pub fn message_id(mut self, val: i32) -> Self { + self.message_id = val; self } diff --git a/src/requests/all/mod.rs b/src/requests/all/mod.rs index 9a754103..3de4d87a 100644 --- a/src/requests/all/mod.rs +++ b/src/requests/all/mod.rs @@ -9,6 +9,11 @@ mod delete_chat_sticker_set; mod delete_message; mod delete_sticker_from_set; mod delete_webhook; +mod edit_inline_message_caption; +mod edit_inline_message_live_location; +mod edit_inline_message_media; +mod edit_inline_message_reply_markup; +mod edit_inline_message_text; mod edit_message_caption; mod edit_message_live_location; mod edit_message_media; @@ -62,6 +67,7 @@ mod set_my_commands; mod set_sticker_position_in_set; mod set_sticker_set_thumb; mod set_webhook; +mod stop_inline_message_live_location; mod stop_message_live_location; mod stop_poll; mod unban_chat_member; @@ -79,6 +85,11 @@ pub use delete_chat_sticker_set::*; pub use delete_message::*; pub use delete_sticker_from_set::*; pub use delete_webhook::*; +pub use edit_inline_message_caption::*; +pub use edit_inline_message_live_location::*; +pub use edit_inline_message_media::*; +pub use edit_inline_message_reply_markup::*; +pub use edit_inline_message_text::*; pub use edit_message_caption::*; pub use edit_message_live_location::*; pub use edit_message_media::*; @@ -133,6 +144,7 @@ pub use set_sticker_position_in_set::*; pub use set_sticker_set_thumb::*; pub use set_webhook::*; pub use std::pin::Pin; +pub use stop_inline_message_live_location::*; pub use stop_message_live_location::*; pub use stop_poll::*; pub use unban_chat_member::*; diff --git a/src/requests/all/stop_inline_message_live_location.rs b/src/requests/all/stop_inline_message_live_location.rs new file mode 100644 index 00000000..40fb5604 --- /dev/null +++ b/src/requests/all/stop_inline_message_live_location.rs @@ -0,0 +1,62 @@ +use serde::Serialize; + +use crate::{ + net, + requests::{Request, ResponseResult}, + types::{InlineKeyboardMarkup, Message}, + Bot, +}; + +/// Use this method to stop updating a live location message (sent via the bot) +/// before `live_period` expires. +/// +/// On success, [`True`] is returned. +/// +/// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation). +/// +/// [`True`]: crate::types::True +#[serde_with_macros::skip_serializing_none] +#[derive(Debug, Clone, Serialize)] +pub struct StopInlineMessageLiveLocation { + #[serde(skip_serializing)] + bot: Bot, + inline_message_id: String, + reply_markup: Option, +} + +#[async_trait::async_trait] +impl Request for StopInlineMessageLiveLocation { + type Output = Message; + + async fn send(&self) -> ResponseResult { + net::request_json(self.bot.client(), self.bot.token(), "stopMessageLiveLocation", &self) + .await + } +} + +impl StopInlineMessageLiveLocation { + pub(crate) fn new(bot: Bot, inline_message_id: I) -> Self + where + I: Into, + { + let inline_message_id = inline_message_id.into(); + Self { bot, inline_message_id, reply_markup: None } + } + + /// Identifier of the inline message. + pub fn inline_message_id(mut self, val: T) -> Self + where + T: Into, + { + self.inline_message_id = val.into(); + self + } + + /// A JSON-serialized object for a new [inline keyboard]. + /// + /// [inline keyboard]: https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating + pub fn reply_markup(mut self, val: InlineKeyboardMarkup) -> Self { + self.reply_markup = Some(val); + self + } +} diff --git a/src/requests/all/stop_message_live_location.rs b/src/requests/all/stop_message_live_location.rs index a0692ec8..892492ea 100644 --- a/src/requests/all/stop_message_live_location.rs +++ b/src/requests/all/stop_message_live_location.rs @@ -3,27 +3,25 @@ use serde::Serialize; use crate::{ net, requests::{Request, ResponseResult}, - types::{ChatOrInlineMessage, InlineKeyboardMarkup, Message}, + types::{ChatId, InlineKeyboardMarkup, Message}, Bot, }; /// Use this method to stop updating a live location message before /// `live_period` expires. /// -/// On success, if the message was sent by the bot, the sent [`Message`] is -/// returned, otherwise [`True`] is returned. +/// On success, the sent [`Message`] is returned. /// /// [The official docs](https://core.telegram.org/bots/api#stopmessagelivelocation). /// /// [`Message`]: crate::types::Message -/// [`True`]: crate::types::True #[serde_with_macros::skip_serializing_none] #[derive(Debug, Clone, Serialize)] pub struct StopMessageLiveLocation { #[serde(skip_serializing)] bot: Bot, - #[serde(flatten)] - chat_or_inline_message: ChatOrInlineMessage, + chat_id: ChatId, + message_id: i32, reply_markup: Option, } @@ -38,12 +36,27 @@ impl Request for StopMessageLiveLocation { } impl StopMessageLiveLocation { - pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage) -> Self { - Self { bot, chat_or_inline_message, reply_markup: None } + pub(crate) fn new(bot: Bot, chat_id: C, message_id: i32) -> Self + where + C: Into, + { + let chat_id = chat_id.into(); + Self { bot, chat_id, message_id, reply_markup: None } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Unique identifier for the target chat or username of the target channel + /// (in the format `@channelusername`) + pub fn chat_id(mut self, val: T) -> Self + where + T: Into, + { + self.chat_id = val.into(); + self + } + + /// Identifier of the message to edit + pub fn message_id(mut self, val: i32) -> Self { + self.message_id = val; self } From 851e4c6bc6dc6c998113b9fda29a491180e22ab3 Mon Sep 17 00:00:00 2001 From: Waffle Date: Fri, 7 Aug 2020 00:49:47 +0300 Subject: [PATCH 59/99] refactor `ChatOrInlineMessage` - Rename `ChatOrInlineMessage` => `TargetMessage` - Change type of `TargetMessage::inline_message_id` `i32` => `String` - Remove `#[non_exhaustive]` annotation as this enum is unlikely to be changed in future - Implement `From` - Use `From` impl in `get_game_high_scores` and `set_game_score` methods - Leave a deprecated pub use as `ChatOrInlineMessage` for a bit of backward compat --- src/bot/api.rs | 27 ++++++++++---------- src/requests/all/get_game_high_scores.rs | 23 +++++++++++------ src/requests/all/set_game_score.rs | 32 +++++++++++------------- src/types/chat_or_inline_message.rs | 12 --------- src/types/mod.rs | 4 +-- src/types/target_message.rs | 20 +++++++++++++++ 6 files changed, 65 insertions(+), 53 deletions(-) delete mode 100644 src/types/chat_or_inline_message.rs create mode 100644 src/types/target_message.rs diff --git a/src/bot/api.rs b/src/bot/api.rs index 3f3fb8c7..5278d357 100644 --- a/src/bot/api.rs +++ b/src/bot/api.rs @@ -1563,18 +1563,18 @@ impl Bot { /// [The official docs](https://core.telegram.org/bots/api#setgamescore). /// /// # Params + /// - `target`: Target message, either chat id and message id or inline + /// message id. /// - `user_id`: User identifier. /// - `score`: New score, must be non-negative. /// /// [`Message`]: crate::types::Message /// [`True`]: crate::types::True - pub fn set_game_score( - &self, - chat_or_inline_message: ChatOrInlineMessage, - user_id: i32, - score: i32, - ) -> SetGameScore { - SetGameScore::new(self.clone(), chat_or_inline_message, user_id, score) + pub fn set_game_score(&self, target: T, user_id: i32, score: i32) -> SetGameScore + where + T: Into, + { + SetGameScore::new(self.clone(), target, user_id, score) } /// Use this method to get data for high score tables. @@ -1591,13 +1591,14 @@ impl Bot { /// [The official docs](https://core.telegram.org/bots/api#getgamehighscores). /// /// # Params + /// - `target`: Target message, either chat id and message id or inline + /// message id. /// - `user_id`: Target user id. - pub fn get_game_high_scores( - &self, - chat_or_inline_message: ChatOrInlineMessage, - user_id: i32, - ) -> GetGameHighScores { - GetGameHighScores::new(self.clone(), chat_or_inline_message, user_id) + pub fn get_game_high_scores(&self, target: T, user_id: i32) -> GetGameHighScores + where + T: Into, + { + GetGameHighScores::new(self.clone(), target, user_id) } /// Use this method to set a custom title for an administrator in a diff --git a/src/requests/all/get_game_high_scores.rs b/src/requests/all/get_game_high_scores.rs index 260098c7..1a43d63e 100644 --- a/src/requests/all/get_game_high_scores.rs +++ b/src/requests/all/get_game_high_scores.rs @@ -3,7 +3,7 @@ use serde::Serialize; use crate::{ net, requests::{Request, ResponseResult}, - types::{ChatOrInlineMessage, GameHighScore}, + types::{GameHighScore, TargetMessage}, Bot, }; @@ -18,14 +18,13 @@ use crate::{ /// the user and his neighbors are not among them. Please note that this /// behavior is subject to change. /// -/// [The official docs](https://core.telegram.org/bots/api#getgamehighscores). -#[serde_with_macros::skip_serializing_none] +/// [The official docs](https://core.telegram.org/bots/api#getgamehighscores) #[derive(Debug, Clone, Serialize)] pub struct GetGameHighScores { #[serde(skip_serializing)] bot: Bot, #[serde(flatten)] - chat_or_inline_message: ChatOrInlineMessage, + target: TargetMessage, user_id: i32, } @@ -39,12 +38,20 @@ impl Request for GetGameHighScores { } impl GetGameHighScores { - pub(crate) fn new(bot: Bot, chat_or_inline_message: ChatOrInlineMessage, user_id: i32) -> Self { - Self { bot, chat_or_inline_message, user_id } + pub(crate) fn new(bot: Bot, target: T, user_id: i32) -> Self + where + T: Into, + { + let target = target.into(); + Self { bot, target, user_id } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Target message, either chat id and message id or inline message id. + pub fn target(mut self, val: T) -> Self + where + T: Into, + { + self.target = val.into(); self } diff --git a/src/requests/all/set_game_score.rs b/src/requests/all/set_game_score.rs index e3271a77..8e429e3a 100644 --- a/src/requests/all/set_game_score.rs +++ b/src/requests/all/set_game_score.rs @@ -3,7 +3,7 @@ use serde::Serialize; use crate::{ net, requests::{Request, ResponseResult}, - types::{ChatOrInlineMessage, Message}, + types::{Message, TargetMessage}, Bot, }; @@ -24,7 +24,7 @@ pub struct SetGameScore { #[serde(skip_serializing)] bot: Bot, #[serde(flatten)] - chat_or_inline_message: ChatOrInlineMessage, + target: TargetMessage, user_id: i32, score: i32, force: Option, @@ -41,24 +41,20 @@ impl Request for SetGameScore { } impl SetGameScore { - pub(crate) fn new( - bot: Bot, - chat_or_inline_message: ChatOrInlineMessage, - user_id: i32, - score: i32, - ) -> Self { - Self { - bot, - chat_or_inline_message, - user_id, - score, - force: None, - disable_edit_message: None, - } + pub(crate) fn new(bot: Bot, target: T, user_id: i32, score: i32) -> Self + where + T: Into, + { + let target = target.into(); + Self { bot, target, user_id, score, force: None, disable_edit_message: None } } - pub fn chat_or_inline_message(mut self, val: ChatOrInlineMessage) -> Self { - self.chat_or_inline_message = val; + /// Target message, either chat id and message id or inline message id. + pub fn target(mut self, val: T) -> Self + where + T: Into, + { + self.target = val.into(); self } diff --git a/src/types/chat_or_inline_message.rs b/src/types/chat_or_inline_message.rs deleted file mode 100644 index d02a522b..00000000 --- a/src/types/chat_or_inline_message.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::types::ChatId; - -use serde::{Deserialize, Serialize}; - -/// A chat message or inline message. -#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -#[non_exhaustive] -pub enum ChatOrInlineMessage { - Chat { chat_id: ChatId, message_id: i32 }, - Inline { inline_message_id: i32 }, -} diff --git a/src/types/mod.rs b/src/types/mod.rs index a8f01b30..e6f7e5fa 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -10,7 +10,6 @@ pub use chat::*; pub use chat_action::*; pub use chat_id::*; pub use chat_member::*; -pub use chat_or_inline_message::*; pub use chat_permissions::*; pub use chat_photo::*; pub use chosen_inline_result::*; @@ -83,6 +82,7 @@ pub use sticker::*; pub use sticker_set::*; pub use sticker_type::*; pub use successful_payment::*; +pub use target_message::*; pub use unit_false::*; pub use unit_true::*; pub use update::*; @@ -104,7 +104,6 @@ mod chat; mod chat_action; mod chat_id; mod chat_member; -mod chat_or_inline_message; mod chat_permissions; mod chat_photo; mod chosen_inline_result; @@ -150,6 +149,7 @@ mod sticker; mod sticker_set; mod sticker_type; mod successful_payment; +mod target_message; mod unit_false; mod unit_true; mod update; diff --git a/src/types/target_message.rs b/src/types/target_message.rs new file mode 100644 index 00000000..aff9a0b6 --- /dev/null +++ b/src/types/target_message.rs @@ -0,0 +1,20 @@ +use crate::types::ChatId; + +use serde::{Deserialize, Serialize}; + +/// A message in chat or inline message. +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum TargetMessage { + Chat { chat_id: ChatId, message_id: i32 }, + Inline { inline_message_id: String }, +} + +#[deprecated = "Was renamed to `TargetMessage`, please use renamed version"] +pub use TargetMessage as ChatOrInlineMessage; + +impl From for TargetMessage { + fn from(inline_message_id: String) -> Self { + Self::Inline { inline_message_id } + } +} From 02400b18ab3c0a091c60909a8664d431be8b4c68 Mon Sep 17 00:00:00 2001 From: Waffle Date: Mon, 10 Aug 2020 18:14:52 +0300 Subject: [PATCH 60/99] remove TargetMessage as ChatOrInlineMessage reexport as it couldn't be deprecated Also rename `TargetMessage::{Chat => Common}` variant. (anyway `ChatOrInlineMessage`/`TargetMessage` refactoring is not backward compatible) --- src/types/target_message.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/types/target_message.rs b/src/types/target_message.rs index aff9a0b6..0c0d8cc1 100644 --- a/src/types/target_message.rs +++ b/src/types/target_message.rs @@ -6,13 +6,10 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[serde(untagged)] pub enum TargetMessage { - Chat { chat_id: ChatId, message_id: i32 }, + Common { chat_id: ChatId, message_id: i32 }, Inline { inline_message_id: String }, } -#[deprecated = "Was renamed to `TargetMessage`, please use renamed version"] -pub use TargetMessage as ChatOrInlineMessage; - impl From for TargetMessage { fn from(inline_message_id: String) -> Self { Self::Inline { inline_message_id } From b06d3e7b7e96c70d4acd0cfd78a504156bc2793d Mon Sep 17 00:00:00 2001 From: Waffle Date: Mon, 10 Aug 2020 18:36:43 +0300 Subject: [PATCH 61/99] add edit-methods and `TargetMessage` refactoring changes to CHANGELOG.md --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db431426..7ef4a38f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Allow `bot_name` be `N`, where `N: Into + ...` in `commands_repl` & `commands_repl_with_listener`. + - 'Edit methods' (namely `edit_message_live_location`, `stop_message_live_location`, `edit_message_text`, + `edit_message_caption`, `edit_message_media` and `edit_message_reply_markup`) are split into common and inline + versions (e.g.: `edit_message_text` and `edit_inline_message_text`). Instead of `ChatOrInlineMessage` common versions + accept `chat_id: impl Into` and `message_id: i32` whereas inline versions accept + `inline_message_id: impl Into`. Also note that return type of inline versions is `True` ([issue 253], [pr 257]) + - `ChatOrInlineMessage` is renamed to `TargetMessage`, it's `::Chat` variant is renamed to `::Common`, + `#[non_exhaustive]` annotation is removed from the enum, type of `TargetMessage::Inline::inline_message_id` changed + `i32` => `String`. `TargetMessage` now implements `From`, `get_game_high_scores` and `set_game_score` use + `Into` to accept `String`s. ([issue 253], [pr 257]) + +[issue 253]: https://github.com/teloxide/teloxide/issues/253 +[pr 257]: https://github.com/teloxide/teloxide/pull/257 ## [0.3.0] - 2020-07-31 ### Added From b81bfd3b2ad1b9d9061d36581e9ab3dfab49a1f3 Mon Sep 17 00:00:00 2001 From: Waffle Date: Mon, 10 Aug 2020 18:39:30 +0300 Subject: [PATCH 62/99] fix fmt --- src/bot/api.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/bot/api.rs b/src/bot/api.rs index 5278d357..8fe0fc80 100644 --- a/src/bot/api.rs +++ b/src/bot/api.rs @@ -1057,8 +1057,9 @@ impl Bot { { match self.parse_mode { None => EditMessageText::new(self.clone(), chat_id, message_id, text), - Some(parse_mode) => EditMessageText::new(self.clone(), chat_id, message_id, text) - .parse_mode(parse_mode), + Some(parse_mode) => { + EditMessageText::new(self.clone(), chat_id, message_id, text).parse_mode(parse_mode) + } } } @@ -1117,8 +1118,9 @@ impl Bot { { match self.parse_mode { None => EditMessageCaption::new(self.clone(), chat_id, message_id), - Some(parse_mode) => EditMessageCaption::new(self.clone(), chat_id, message_id) - .parse_mode(parse_mode), + Some(parse_mode) => { + EditMessageCaption::new(self.clone(), chat_id, message_id).parse_mode(parse_mode) + } } } From f521f08470ebc955ced1317957e58c9fb2f634b5 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 12 Aug 2020 22:31:35 +0300 Subject: [PATCH 63/99] Use local ./ paths instead of github links in README --- README.md | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 427b78d3..81a54c1f 100644 --- a/README.md +++ b/README.md @@ -22,17 +22,17 @@
## Table of contents - - [Highlights](https://github.com/teloxide/teloxide#highlights) - - [Setting up your environment](https://github.com/teloxide/teloxide#setting-up-your-environment) - - [API overview](https://github.com/teloxide/teloxide#api-overview) - - [The dices bot](https://github.com/teloxide/teloxide#the-dices-bot) - - [Commands](https://github.com/teloxide/teloxide#commands) - - [Dialogues management](https://github.com/teloxide/teloxide#dialogues-management) - - [Recommendations](https://github.com/teloxide/teloxide#recommendations) - - [Cargo features](https://github.com/teloxide/teloxide#cargo-features) - - [FAQ](https://github.com/teloxide/teloxide#faq) - - [Community bots](https://github.com/teloxide/teloxide#community-bots) - - [Contributing](https://github.com/teloxide/teloxide#contributing) + - [Highlights](#highlights) + - [Setting up your environment](#setting-up-your-environment) + - [API overview](#api-overview) + - [The dices bot](#the-dices-bot) + - [Commands](#commands) + - [Dialogues management](#dialogues-management) + - [Recommendations](#recommendations) + - [Cargo features](#cargo-features) + - [FAQ](#faq) + - [Community bots](#community-bots) + - [Contributing](#contributing) ## Highlights @@ -90,7 +90,7 @@ tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } ### The dices bot This bot throws a dice on each incoming message: -([Full](https://github.com/teloxide/teloxide/blob/master/examples/dices_bot/src/main.rs)) +([Full](./examples/dices_bot/src/main.rs)) ```rust use teloxide::prelude::*; @@ -112,7 +112,7 @@ async fn main() {
- +
@@ -126,7 +126,7 @@ Commands are strongly typed and defined declaratively, similar to how we define [structopt]: https://docs.rs/structopt/0.3.9/structopt/ [serde-json]: https://github.com/serde-rs/json -([Full](https://github.com/teloxide/teloxide/blob/master/examples/simple_commands_bot/src/main.rs)) +([Full](./examples/simple_commands_bot/src/main.rs)) ```rust // Imports are omitted... @@ -169,7 +169,7 @@ async fn main() {
- +
@@ -180,7 +180,7 @@ A dialogue is described by an enumeration, where each variant is one of possible Below is a bot, which asks you three questions and then sends the answers back to you. First, let's start with an enumeration (a collection of our dialogue's states): -([dialogue_bot/src/dialogue/mod.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/mod.rs)) +([dialogue_bot/src/dialogue/mod.rs](./examples/dialogue_bot/src/dialogue/mod.rs)) ```rust // Imports are omitted... @@ -204,7 +204,7 @@ When a user sends a message to our bot, and such a dialogue does not yet exist,
Dialogue::Start -([dialogue_bot/src/dialogue/states/start.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/start.rs)) +([dialogue_bot/src/dialogue/states/start.rs](./examples/dialogue_bot/src/dialogue/states/start.rs)) ```rust // Imports are omitted... @@ -222,7 +222,7 @@ async fn start(_state: StartState, cx: TransitionIn, _ans: String) -> Transition
Dialogue::ReceiveFullName -([dialogue_bot/src/dialogue/states/receive_full_name.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_full_name.rs)) +([dialogue_bot/src/dialogue/states/receive_full_name.rs](./examples/dialogue_bot/src/dialogue/states/receive_full_name.rs)) ```rust // Imports are omitted... @@ -245,7 +245,7 @@ async fn receive_full_name(
Dialogue::ReceiveAge -([dialogue_bot/src/dialogue/states/receive_age.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_age.rs)) +([dialogue_bot/src/dialogue/states/receive_age.rs](./examples/dialogue_bot/src/dialogue/states/receive_age.rs)) ```rust // Imports are omitted... @@ -278,7 +278,7 @@ async fn receive_age_state(
Dialogue::ReceiveLocation -([dialogue_bot/src/dialogue/states/receive_location.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_location.rs)) +([dialogue_bot/src/dialogue/states/receive_location.rs](./examples/dialogue_bot/src/dialogue/states/receive_location.rs)) ```rust // Imports are omitted... @@ -306,7 +306,7 @@ All these subtransitions accept a corresponding state (one of the many variants Finally, the `main` function looks like this: -([dialogue_bot/src/main.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/main.rs)) +([dialogue_bot/src/main.rs](./examples/dialogue_bot/src/main.rs)) ```rust // Imports are omitted... @@ -336,11 +336,11 @@ async fn handle_message(cx: UpdateWithCx, dialogue: Dialogue) -> Transi
- +
-[More examples!](https://github.com/teloxide/teloxide/tree/master/examples) +[More examples!](./examples) ## Recommendations - Use this pattern: @@ -404,7 +404,7 @@ UPD: The current design spreads wide and deep trait bounds, thereby increasing c Q: Can I use webhooks? -A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](examples/heroku_ping_pong_bot/src/main.rs). +A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](./examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](./examples/heroku_ping_pong_bot/src/main.rs). Associated links: - [Marvin's Marvellous Guide to All Things Webhook](https://core.telegram.org/bots/webhooks) From 7a3ce7f05c0b9e57a8d2d79f5774c5a61e130038 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 12 Aug 2020 22:44:56 +0300 Subject: [PATCH 64/99] Remove confusing use of `respond` from README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81a54c1f..b1b0a584 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ async fn main() { teloxide::repl(bot, |message| async move { message.answer_dice().send().await?; - respond(()) + ResponseResult::<()>::Ok(()) }) .await; } From 00e39e8d35c3ad279f81e31acce2f1c74e2c0312 Mon Sep 17 00:00:00 2001 From: Waffle Date: Wed, 12 Aug 2020 22:48:36 +0300 Subject: [PATCH 65/99] enable all features for `docs.rs` doc build --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 2497c1c4..d4475692 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,3 +63,6 @@ rand = "0.7.3" pretty_env_logger = "0.4.0" lazy_static = "1.4.0" tokio = { version = "0.2.21", features = ["fs", "stream", "rt-threaded", "macros"] } + +[package.metadata."docs.rs"] +all-features = true From f765278c6892a4e0e5c87b6556d02089287b9342 Mon Sep 17 00:00:00 2001 From: Waffle Date: Wed, 12 Aug 2020 22:49:58 +0300 Subject: [PATCH 66/99] add docs|master badge and netlify config --- README.md | 15 +++++++++------ netlify.toml | 12 ++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 netlify.toml diff --git a/README.md b/README.md index 427b78d3..ca7ad4c6 100644 --- a/README.md +++ b/README.md @@ -2,21 +2,24 @@

teloxide

- - - + + + + + + - - - + + + A full-featured framework that empowers you to easily build [Telegram bots](https://telegram.org/blog/bot-revolution) using the [`async`/`.await`](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) syntax in [Rust](https://www.rust-lang.org/). It handles all the difficult stuff so you can focus only on your business logic.
diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 00000000..27cffb2f --- /dev/null +++ b/netlify.toml @@ -0,0 +1,12 @@ +[build] +# Directory (relative to root of your repo) that contains the deploy-ready +# HTML files and assets generated by the build. If a base directory has +# been specified, include it in the publish directory path. +publish = "target/doc" + +# Default build command. +command = 'curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly --profile minimal && source $HOME/.cargo/env && RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --no-deps --all-features' + +[[redirects]] + from = "/*" + to = "/teloxide" From 3157305105dae855529d092173fab8ee54d15234 Mon Sep 17 00:00:00 2001 From: Waffle Date: Wed, 12 Aug 2020 23:21:13 +0300 Subject: [PATCH 67/99] add automatic test of code blocks from readme --- Cargo.toml | 2 ++ README.md | 20 ++++++++++---------- src/lib.rs | 5 +++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d4475692..37109156 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,8 @@ bincode-serializer = ["bincode"] frunk- = ["frunk"] +nightly = [] # currently used only for `README.md` tests + [dependencies] serde_json = "1.0.55" serde = { version = "1.0.114", features = ["derive"] } diff --git a/README.md b/README.md index ca7ad4c6..4cdc75c3 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } This bot throws a dice on each incoming message: ([Full](https://github.com/teloxide/teloxide/blob/master/examples/dices_bot/src/main.rs)) -```rust +```rust,no_run use teloxide::prelude::*; #[tokio::main] @@ -130,8 +130,8 @@ Commands are strongly typed and defined declaratively, similar to how we define [serde-json]: https://github.com/serde-rs/json ([Full](https://github.com/teloxide/teloxide/blob/master/examples/simple_commands_bot/src/main.rs)) -```rust -// Imports are omitted... +```rust,no_run +use teloxide::{utils::command::BotCommand, prelude::*}; #[derive(BotCommand)] #[command(rename = "lowercase", description = "These commands are supported:")] @@ -166,7 +166,7 @@ async fn main() { let bot = Bot::from_env(); let bot_name: String = panic!("Your bot's name here"); - teloxide::commands_repl(bot, bot_name, action).await; + teloxide::commands_repl(bot, bot_name, answer).await; } ``` @@ -184,7 +184,7 @@ A dialogue is described by an enumeration, where each variant is one of possible Below is a bot, which asks you three questions and then sends the answers back to you. First, let's start with an enumeration (a collection of our dialogue's states): ([dialogue_bot/src/dialogue/mod.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/mod.rs)) -```rust +```rust,ignore // Imports are omitted... #[derive(Transition, From)] @@ -208,7 +208,7 @@ When a user sends a message to our bot, and such a dialogue does not yet exist, Dialogue::Start ([dialogue_bot/src/dialogue/states/start.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/start.rs)) -```rust +```rust,ignore // Imports are omitted... pub struct StartState; @@ -226,7 +226,7 @@ async fn start(_state: StartState, cx: TransitionIn, _ans: String) -> Transition Dialogue::ReceiveFullName ([dialogue_bot/src/dialogue/states/receive_full_name.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_full_name.rs)) -```rust +```rust,ignore // Imports are omitted... #[derive(Generic)] @@ -249,7 +249,7 @@ async fn receive_full_name( Dialogue::ReceiveAge ([dialogue_bot/src/dialogue/states/receive_age.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_age.rs)) -```rust +```rust,ignore // Imports are omitted... #[derive(Generic)] @@ -282,7 +282,7 @@ async fn receive_age_state( Dialogue::ReceiveLocation ([dialogue_bot/src/dialogue/states/receive_location.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/dialogue/states/receive_location.rs)) -```rust +```rust,ignore // Imports are omitted... #[derive(Generic)] @@ -310,7 +310,7 @@ All these subtransitions accept a corresponding state (one of the many variants Finally, the `main` function looks like this: ([dialogue_bot/src/main.rs](https://github.com/teloxide/teloxide/blob/master/examples/dialogue_bot/src/main.rs)) -```rust +```rust,ignore // Imports are omitted... #[tokio::main] diff --git a/src/lib.rs b/src/lib.rs index c3116be2..7ffb1775 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,7 @@ )] #![allow(clippy::match_bool)] #![forbid(unsafe_code)] +#![cfg_attr(all(feature = "nightly", doctest), feature(external_doc))] pub use bot::{Bot, BotBuilder}; pub use dispatching::repls::{ @@ -61,3 +62,7 @@ pub mod types; pub mod utils; extern crate teloxide_macros; + +#[cfg(all(feature = "nightly", doctest))] +#[doc(include = "../README.md")] +enum ReadmeDocTests {} From 981ba237c9917f9315f192daf7b82d4d5b2940fb Mon Sep 17 00:00:00 2001 From: Waffle Date: Wed, 12 Aug 2020 23:53:58 +0300 Subject: [PATCH 68/99] redis test fix & beta/nightly ci This commit fixes redis storage test, those were not ran before. Also, introduces beta&nightly tests to CI --- .github/workflows/ci.yml | 42 ++++++++++++++++++++++++++++++---------- Cargo.toml | 5 +++++ tests/redis.rs | 5 ----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c7b3cda1..588ea79a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,23 +27,45 @@ jobs: override: true - name: Cargo clippy run: cargo clippy --all --all-targets --all-features -- -D warnings - stable-test: + + test: runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - beta + - nightly + + include: + - rust: stable + features: "--features \"redis-storage cbor-serializer bincode-serializer frunk-\"" + - rust: beta + features: "--features \"redis-storage cbor-serializer bincode-serializer frunk-\"" + - rust: nightly + features: "--all-features" + steps: - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: ${{ matrix.rust }} override: true - - name: Setup redis - run: | - sudo apt install redis-server - redis-server --port 7777 > /dev/null & - redis-server --port 7778 > /dev/null & - redis-server --port 7779 > /dev/null & - - name: Cargo test - run: cargo test --all --all-features + + - name: build + uses: actions-rs/cargo@v1 + with: + command: build + args: --verbose ${{ matrix.features }} + + - name: test + uses: actions-rs/cargo@v1 + with: + command: test + args: --verbose ${{ matrix.features }} + build-example: runs-on: ubuntu-latest strategy: diff --git a/Cargo.toml b/Cargo.toml index 37109156..9e85b94f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,3 +68,8 @@ tokio = { version = "0.2.21", features = ["fs", "stream", "rt-threaded", "macros [package.metadata."docs.rs"] all-features = true + +[[test]] +name = "redis" +path = "tests/redis.rs" +required-features = ["redis-storage", "cbor-serializer", "bincode-serializer"] diff --git a/tests/redis.rs b/tests/redis.rs index 3d9da600..0a06c06e 100644 --- a/tests/redis.rs +++ b/tests/redis.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "redis_storage")] - use std::{ fmt::{Debug, Display}, future::Future, @@ -8,7 +6,6 @@ use std::{ use teloxide::dispatching::dialogue::{RedisStorage, Serializer, Storage}; #[tokio::test] -#[cfg(feature = "redis_storage")] async fn test_redis_json() { let storage = RedisStorage::open( "redis://127.0.0.1:7777", @@ -19,7 +16,6 @@ async fn test_redis_json() { test_redis(storage).await; } -#[cfg(feature = "bincode_serializer")] #[tokio::test] async fn test_redis_bincode() { let storage = RedisStorage::open( @@ -31,7 +27,6 @@ async fn test_redis_bincode() { test_redis(storage).await; } -#[cfg(feature = "cbor_serializer")] #[tokio::test] async fn test_redis_cbor() { let storage = RedisStorage::open( From 94bc8504a514df2e1941cf2e594144c0559bdfe7 Mon Sep 17 00:00:00 2001 From: Waffle Date: Thu, 13 Aug 2020 00:07:16 +0300 Subject: [PATCH 69/99] oops, i've accidentally removed redis setup from ci --- .github/workflows/ci.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 588ea79a..d2dfc583 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,13 +54,20 @@ jobs: toolchain: ${{ matrix.rust }} override: true - - name: build + - name: Build uses: actions-rs/cargo@v1 with: command: build args: --verbose ${{ matrix.features }} - - name: test + - name: Setup redis + run: | + sudo apt install redis-server + redis-server --port 7777 > /dev/null & + redis-server --port 7778 > /dev/null & + redis-server --port 7779 > /dev/null & + + - name: Test uses: actions-rs/cargo@v1 with: command: test @@ -87,5 +94,5 @@ jobs: profile: minimal toolchain: stable override: true - - name: Test the example + - name: Check the example run: cd examples && cd ${{ matrix.example }} && cargo check From d88f92d26c03126bfeb15643670fe6bd983b3a58 Mon Sep 17 00:00:00 2001 From: Waffle Date: Mon, 17 Aug 2020 18:10:03 +0300 Subject: [PATCH 70/99] make 'dev' default branch in docs --- CONTRIBUTING.md | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b81f9695..4587993e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,8 @@ # Contributing + Before contributing, please read [our code style](https://github.com/teloxide/teloxide/blob/master/CODE_STYLE.md) and [the license](https://github.com/teloxide/teloxide/blob/master/LICENSE). -To change the source code, fork the `master` branch of this repository and work inside your own branch. Then send us a PR into `master` branch and wait for the CI to check everything. However, you'd better check changes first locally: +To change the source code, fork the `dev` branch of this repository and work inside your own branch. Then send us a PR into `dev` branch and wait for the CI to check everything. However, you'd better check changes first locally: ``` cargo clippy --all --all-features --all-targets diff --git a/README.md b/README.md index 76c90ea8..9bafee33 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ - + From 7527179f3f8ebce7abe333e0aa48ef4f9ef07de6 Mon Sep 17 00:00:00 2001 From: Waffle Date: Mon, 17 Aug 2020 18:21:41 +0300 Subject: [PATCH 71/99] add deprecation note to Bot constructors --- src/bot/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 65a024bf..d9b3c687 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -56,9 +56,9 @@ impl Bot { /// /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 - #[deprecated] - #[allow(deprecated)] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode and env defaults)"] pub fn from_env_with_client(client: Client) -> Self { + #[allow(deprecated)] Self::with_client(&get_env(TELOXIDE_TOKEN), client) } @@ -69,12 +69,12 @@ impl Bot { /// If it cannot create [`reqwest::Client`]. /// /// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html - #[deprecated] - #[allow(deprecated)] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode and env defaults)"] pub fn new(token: S) -> Self where S: Into, { + #[allow(deprecated)] Self::with_client(token, build_sound_bot()) } @@ -87,8 +87,7 @@ impl Bot { /// /// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 - #[deprecated] - #[allow(deprecated)] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode and env defaults)"] pub fn with_client(token: S, client: Client) -> Self where S: Into, From 7cbbf4396611441ac877095d1562a547ee75d0ab Mon Sep 17 00:00:00 2001 From: Waffle Date: Mon, 17 Aug 2020 18:30:19 +0300 Subject: [PATCH 72/99] run CI for pull requests against dev --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d2dfc583..a9a4c47a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ on: push: branches: [ master ] pull_request: - branches: [ master ] + branches: [ master, dev ] name: Continuous integration From 060dd5f6b4733ac8a2fa5d89ceac34617a388ecd Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Tue, 18 Aug 2020 09:23:18 +0600 Subject: [PATCH 73/99] Add cognito_bot to README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 76c90ea8..7ae679f3 100644 --- a/README.md +++ b/README.md @@ -428,6 +428,7 @@ Feel free to push your own bot into our collection! - [_Rust subreddit reader_](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/subreddit_reader) - [_vzmuinebot -- Telegram bot for food menu navigate_](https://github.com/ArtHome12/vzmuinebot) - [_Tepe -- A CLI to command a bot to send messages and files over Telegram_](https://lib.rs/crates/tepe) + - [_cognito_bot -- The bot is designed to anonymize messages to a group_](https://github.com/ArtHome12/cognito_bot) ## Contributing See [CONRIBUTING.md](https://github.com/teloxide/teloxide/blob/master/CONTRIBUTING.md). From fc4324b91f0b553a8d1e7f52c311a0d0ef56db8e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Fri, 21 Aug 2020 16:24:09 +0600 Subject: [PATCH 74/99] Remove useless spaces from README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7ae679f3..44cc99d4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ @@ -110,7 +110,6 @@ async fn main() { }) .await; } - ```
From 4c2681ca2765c96222a7de07633a2654bf849e4e Mon Sep 17 00:00:00 2001 From: Waffle Date: Fri, 21 Aug 2020 14:29:25 +0300 Subject: [PATCH 75/99] add `Bot::builder` method --- src/bot/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 65a024bf..89a9fb2a 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -24,6 +24,14 @@ pub struct Bot { } impl Bot { + /// Creates new [`BotBuilder`] see it's [docs] for more + /// + /// [docs]: BotBuilder + #[must_use] + pub fn builder() -> BotBuilder { + BotBuilder::new() + } + /// Creates a new `Bot` with the `TELOXIDE_TOKEN` & `TELOXIDE_PROXY` /// environmental variables (a bot's token & a proxy) and the default /// [`reqwest::Client`]. @@ -143,7 +151,7 @@ impl Bot { /// A builder of [`Bot`], supporting some extra settings. /// -/// [`Bot`] crate::Bot +/// [`Bot`]: crate::Bot #[derive(Debug, Default)] pub struct BotBuilder { token: Option, From ac4f7f88e74c856e1f8d7cd7de7b512041193ce9 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 21 Aug 2020 14:31:25 +0300 Subject: [PATCH 76/99] Update src/bot/mod.rs Co-authored-by: Temirkhan Myrzamadi --- src/bot/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index d9b3c687..d9aa69a2 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -56,7 +56,7 @@ impl Bot { /// /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 - #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode and env defaults)"] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode)"] pub fn from_env_with_client(client: Client) -> Self { #[allow(deprecated)] Self::with_client(&get_env(TELOXIDE_TOKEN), client) From de9ce863d5ebfefcc2a4403b1fc183864c32efd4 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Fri, 21 Aug 2020 14:31:59 +0300 Subject: [PATCH 77/99] Apply suggestions from code review Co-authored-by: Temirkhan Myrzamadi --- src/bot/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index d9aa69a2..2ce6e6bf 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -69,7 +69,7 @@ impl Bot { /// If it cannot create [`reqwest::Client`]. /// /// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html - #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode and env defaults)"] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode)"] pub fn new(token: S) -> Self where S: Into, @@ -87,7 +87,7 @@ impl Bot { /// /// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 - #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode and env defaults)"] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode)"] pub fn with_client(token: S, client: Client) -> Self where S: Into, From 2cdb200ccf69e86bff16ad7e08f9b5d2bfe30487 Mon Sep 17 00:00:00 2001 From: Waffle Date: Fri, 21 Aug 2020 14:35:14 +0300 Subject: [PATCH 78/99] update CHANGELOG.md with `Bot::builder` method --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3cf8cd..81e63969 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [unreleased] + +### Added + - `Bot::builder` method ([PR 269](https://github.com/teloxide/teloxide/pull/269)). + ## [0.3.0] - 2020-07-31 ### Added - Support for typed bot commands ([issue 152](https://github.com/teloxide/teloxide/issues/152)). From 04f8ed5df7da5f21a7d617e2570ca5f807a5fbdd Mon Sep 17 00:00:00 2001 From: Waffle Date: Tue, 25 Aug 2020 17:45:16 +0300 Subject: [PATCH 79/99] v0.3.1 release --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- README.md | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81e63969..deaea888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [unreleased] +## [0.3.1] - 2020-08-25 ### Added - `Bot::builder` method ([PR 269](https://github.com/teloxide/teloxide/pull/269)). diff --git a/Cargo.toml b/Cargo.toml index a8661289..dc1562ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "teloxide" -version = "0.3.0" +version = "0.3.1" edition = "2018" description = "An elegant Telegram bots framework for Rust" repository = "https://github.com/teloxide/teloxide" diff --git a/README.md b/README.md index 2c09106e..9dad8c5a 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@

teloxide

- + - + @@ -76,7 +76,7 @@ $ rustup override set nightly 5. Execute `cargo new my_bot`, enter the directory and put these lines into your `Cargo.toml`: ```toml [dependencies] -teloxide = "0.3.0" +teloxide = "0.3.1" teloxide-macros = "0.3.2" log = "0.4.8" From 4fa2d30411a2b2c8d82af78c08c10faf88dde533 Mon Sep 17 00:00:00 2001 From: Waffle Date: Tue, 25 Aug 2020 18:21:34 +0300 Subject: [PATCH 80/99] fmt --- src/bot/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 4e4d82ab..462da3eb 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -64,7 +64,8 @@ impl Bot { /// /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 - #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode)"] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options \ + (notably default parse_mode)"] pub fn from_env_with_client(client: Client) -> Self { #[allow(deprecated)] Self::with_client(&get_env(TELOXIDE_TOKEN), client) @@ -77,7 +78,8 @@ impl Bot { /// If it cannot create [`reqwest::Client`]. /// /// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html - #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode)"] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options \ + (notably default parse_mode)"] pub fn new(token: S) -> Self where S: Into, @@ -95,7 +97,8 @@ impl Bot { /// /// [`reqwest::Client`]: https://docs.rs/reqwest/latest/reqwest/struct.Client.html /// [issue 223]: https://github.com/teloxide/teloxide/issues/223 - #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options (notably default parse_mode)"] + #[deprecated = "Deprecated in favour of BotBuilder because the later provides more options \ + (notably default parse_mode)"] pub fn with_client(token: S, client: Client) -> Self where S: Into, From e4449e49f3fa9deed2e904fdcbeaf53e4d19114c Mon Sep 17 00:00:00 2001 From: Robin Hundt <24554122+robinhundt@users.noreply.github.com> Date: Fri, 28 Aug 2020 23:33:16 +0200 Subject: [PATCH 81/99] Added failing test case for command with single non-String arg --- tests/command.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/command.rs b/tests/command.rs index 82bba9aa..a8bd02da 100644 --- a/tests/command.rs +++ b/tests/command.rs @@ -18,6 +18,22 @@ fn parse_command_with_args() { assert_eq!(actual, expected) } +#[test] +fn parse_command_with_non_string_arg() { + #[command(rename = "lowercase")] + #[derive(BotCommand, Debug, PartialEq)] + enum DefaultCommands { + Start(i32), + Help, + } + + let data = "/start -50"; + let expected = DefaultCommands::Start("-50".parse().unwrap()); + let actual = DefaultCommands::parse(data, "").unwrap(); + assert_eq!(actual, expected) +} + + #[test] fn attribute_prefix() { #[command(rename = "lowercase")] From abb7b9335ed5a789e9d9cc62d8bc7ca28933a3cc Mon Sep 17 00:00:00 2001 From: Robin Hundt <24554122+robinhundt@users.noreply.github.com> Date: Wed, 2 Sep 2020 16:12:59 +0200 Subject: [PATCH 82/99] Removed whitespace --- tests/command.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/command.rs b/tests/command.rs index a8bd02da..d7badef0 100644 --- a/tests/command.rs +++ b/tests/command.rs @@ -33,7 +33,6 @@ fn parse_command_with_non_string_arg() { assert_eq!(actual, expected) } - #[test] fn attribute_prefix() { #[command(rename = "lowercase")] From 4fabc083b8a7f773f01e05feb8147b67f01040ba Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 6 Sep 2020 00:48:26 +0600 Subject: [PATCH 83/99] Add tg-vimhelpbot to README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8fe657e8..42ff8600 100644 --- a/README.md +++ b/README.md @@ -428,6 +428,7 @@ Feel free to push your own bot into our collection! - [_vzmuinebot -- Telegram bot for food menu navigate_](https://github.com/ArtHome12/vzmuinebot) - [_Tepe -- A CLI to command a bot to send messages and files over Telegram_](https://lib.rs/crates/tepe) - [_cognito_bot -- The bot is designed to anonymize messages to a group_](https://github.com/ArtHome12/cognito_bot) + - [_tg-vimhelpbot -- Link `:help` for Vim in Telegram_](https://github.com/GoldsteinE/tg-vimhelpbot) ## Contributing See [CONRIBUTING.md](https://github.com/teloxide/teloxide/blob/master/CONTRIBUTING.md). From b2126162570512f9925e34415bc6586005139276 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 12 Sep 2020 21:23:50 +0600 Subject: [PATCH 84/99] Add authors of bots to README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 42ff8600..3b8da7da 100644 --- a/README.md +++ b/README.md @@ -424,11 +424,11 @@ A: Yes. You can setup any logger, for example, [fern], e.g. teloxide has no spec ## Community bots Feel free to push your own bot into our collection! - - [_Rust subreddit reader_](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/subreddit_reader) - - [_vzmuinebot -- Telegram bot for food menu navigate_](https://github.com/ArtHome12/vzmuinebot) - - [_Tepe -- A CLI to command a bot to send messages and files over Telegram_](https://lib.rs/crates/tepe) - - [_cognito_bot -- The bot is designed to anonymize messages to a group_](https://github.com/ArtHome12/cognito_bot) - - [_tg-vimhelpbot -- Link `:help` for Vim in Telegram_](https://github.com/GoldsteinE/tg-vimhelpbot) + - [_steadylearner/subreddit_reader_](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/subreddit_reader) + - [_ArtHome12/vzmuinebot -- Telegram bot for food menu navigate_](https://github.com/ArtHome12/vzmuinebot) + - [_Hermitter/tepe -- A CLI to command a bot to send messages and files over Telegram_](https://github.com/Hermitter/tepe) + - [_ArtHome12/cognito_bot -- The bot is designed to anonymize messages to a group_](https://github.com/ArtHome12/cognito_bot) + - [_GoldsteinE/tg-vimhelpbot -- Link `:help` for Vim in Telegram_](https://github.com/GoldsteinE/tg-vimhelpbot) ## Contributing See [CONRIBUTING.md](https://github.com/teloxide/teloxide/blob/master/CONTRIBUTING.md). From 4db66eaa83e62d117c6f1b3c4079ede57556ae42 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 26 Sep 2020 21:27:13 +0600 Subject: [PATCH 85/99] Highlight dialogues management (README.md) --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3b8da7da..91f20a81 100644 --- a/README.md +++ b/README.md @@ -39,17 +39,18 @@ ## Highlights - - **Functional reactive design.** teloxide has [functional reactive design], allowing you to declaratively manipulate streams of updates from Telegram using filters, maps, folds, zips, and a lot of [other adaptors]. + - **Functional reactive design.** teloxide follows [functional reactive design], allowing you to declaratively manipulate streams of updates from Telegram using filters, maps, folds, zips, and a lot of [other adaptors]. [functional reactive design]: https://en.wikipedia.org/wiki/Functional_reactive_programming [other adaptors]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html - - **Persistence.** Dialogues management is independent of how/where dialogues are stored: you can just replace one line and make them [persistent]. Out-of-the-box storages include [Redis]. + - **Dialogues management subsystem.** Dialogues are represented as [finite-state machines] augmented with some syntax sugar, thanks to attribute macros. We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored; for example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis]. -[persistent]: https://en.wikipedia.org/wiki/Persistence_(computer_science) +[persistence]: https://en.wikipedia.org/wiki/Persistence_(computer_science) +[finite-state machines]: https://en.wikipedia.org/wiki/Finite-state_machine [Redis]: https://redis.io/ - - **Strongly typed bot commands.** You can describe bot commands as enumerations, and then they'll be automatically constructed from strings. Just like you describe JSON structures in [serde-json] and command-line arguments in [structopt]. + - **Strongly typed bot commands.** You can describe bot commands as enumerations, and then they'll be automatically constructed from strings -- just like JSON structures in [serde-json] and command-line arguments in [structopt]. [structopt]: https://github.com/TeXitoi/structopt [serde-json]: https://github.com/serde-rs/json From 1c6b97ae392ba4de7708efceb2fe011893d41325 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 26 Sep 2020 21:29:32 +0600 Subject: [PATCH 86/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 91f20a81..f4d2a521 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ [functional reactive design]: https://en.wikipedia.org/wiki/Functional_reactive_programming [other adaptors]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html - - **Dialogues management subsystem.** Dialogues are represented as [finite-state machines] augmented with some syntax sugar, thanks to attribute macros. We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored; for example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis]. + - **Dialogues management subsystem.** We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored; for example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis]. [persistence]: https://en.wikipedia.org/wiki/Persistence_(computer_science) [finite-state machines]: https://en.wikipedia.org/wiki/Finite-state_machine From 4a1ba8d9b45becf556cd887f08cceeb6fb1d6e78 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 26 Sep 2020 21:30:08 +0600 Subject: [PATCH 87/99] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f4d2a521..a87cd5bf 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ [functional reactive design]: https://en.wikipedia.org/wiki/Functional_reactive_programming [other adaptors]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html - - **Dialogues management subsystem.** We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored; for example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis]. + - **Dialogues management subsystem.** We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored. For example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis]. [persistence]: https://en.wikipedia.org/wiki/Persistence_(computer_science) [finite-state machines]: https://en.wikipedia.org/wiki/Finite-state_machine From e894ae868e3a53b0d73a7c1e7ee881d998d422fb Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 26 Sep 2020 21:42:36 +0600 Subject: [PATCH 88/99] Update README.md Co-authored-by: Waffle Lapkin --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a87cd5bf..d511ece9 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ [finite-state machines]: https://en.wikipedia.org/wiki/Finite-state_machine [Redis]: https://redis.io/ - - **Strongly typed bot commands.** You can describe bot commands as enumerations, and then they'll be automatically constructed from strings -- just like JSON structures in [serde-json] and command-line arguments in [structopt]. + - **Strongly typed bot commands.** You can describe bot commands as enumerations, and then they'll be automatically constructed from strings — just like JSON structures in [serde-json] and command-line arguments in [structopt]. [structopt]: https://github.com/TeXitoi/structopt [serde-json]: https://github.com/serde-rs/json From eb79c7099da20e19c25ff79ee6ee65310799322e Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sat, 26 Sep 2020 21:50:22 +0600 Subject: [PATCH 89/99] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d511ece9..6740c43d 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,6 @@ - **Dialogues management subsystem.** We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored. For example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis]. [persistence]: https://en.wikipedia.org/wiki/Persistence_(computer_science) -[finite-state machines]: https://en.wikipedia.org/wiki/Finite-state_machine [Redis]: https://redis.io/ - **Strongly typed bot commands.** You can describe bot commands as enumerations, and then they'll be automatically constructed from strings — just like JSON structures in [serde-json] and command-line arguments in [structopt]. From 9cb44bef0d399d16f4de5e6182066c87ab881ba7 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Sun, 27 Sep 2020 06:53:43 +0600 Subject: [PATCH 90/99] Box::pin -> .boxed() --- .../dialogue/dialogue_dispatcher.rs | 40 ++++++++++--------- .../dialogue/dialogue_dispatcher_handler.rs | 4 +- .../dialogue/storage/in_mem_storage.rs | 6 +-- .../dialogue/storage/redis_storage.rs | 11 ++--- src/dispatching/dispatcher_handler.rs | 4 +- src/dispatching/dispatcher_handler_rx_ext.rs | 12 +++--- src/error_handlers.rs | 15 +++---- 7 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/dispatching/dialogue/dialogue_dispatcher.rs b/src/dispatching/dialogue/dialogue_dispatcher.rs index 18565824..0e1f97b6 100644 --- a/src/dispatching/dialogue/dialogue_dispatcher.rs +++ b/src/dispatching/dialogue/dialogue_dispatcher.rs @@ -6,7 +6,7 @@ use crate::dispatching::{ }; use std::{convert::Infallible, marker::PhantomData}; -use futures::{future::BoxFuture, StreamExt}; +use futures::{future::BoxFuture, FutureExt, StreamExt}; use tokio::sync::mpsc; use lockfree::map::Map; @@ -137,28 +137,30 @@ where { let this = Arc::new(self); - Box::pin(updates.for_each(move |cx| { - let this = Arc::clone(&this); - let chat_id = cx.update.chat_id(); + updates + .for_each(move |cx| { + let this = Arc::clone(&this); + let chat_id = cx.update.chat_id(); - match this.senders.get(&chat_id) { - // An old dialogue - Some(tx) => { - if tx.1.send(cx).is_err() { - panic!("We are not dropping a receiver or call .close() on it",); + match this.senders.get(&chat_id) { + // An old dialogue + Some(tx) => { + if tx.1.send(cx).is_err() { + panic!("We are not dropping a receiver or call .close() on it",); + } + } + None => { + let tx = this.new_tx(); + if tx.send(cx).is_err() { + panic!("We are not dropping a receiver or call .close() on it",); + } + this.senders.insert(chat_id, tx); } } - None => { - let tx = this.new_tx(); - if tx.send(cx).is_err() { - panic!("We are not dropping a receiver or call .close() on it",); - } - this.senders.insert(chat_id, tx); - } - } - async {} - })) + async {} + }) + .boxed() } } diff --git a/src/dispatching/dialogue/dialogue_dispatcher_handler.rs b/src/dispatching/dialogue/dialogue_dispatcher_handler.rs index 1a596bcc..5e8ad2bd 100644 --- a/src/dispatching/dialogue/dialogue_dispatcher_handler.rs +++ b/src/dispatching/dialogue/dialogue_dispatcher_handler.rs @@ -1,5 +1,5 @@ use crate::prelude::{DialogueStage, DialogueWithCx}; -use futures::future::BoxFuture; +use futures::{future::BoxFuture, FutureExt}; use std::{future::Future, sync::Arc}; /// An asynchronous handler of an update used in [`DialogueDispatcher`]. @@ -27,6 +27,6 @@ where where DialogueWithCx: Send + 'static, { - Box::pin(async move { self(cx).await }) + async move { self(cx).await }.boxed() } } diff --git a/src/dispatching/dialogue/storage/in_mem_storage.rs b/src/dispatching/dialogue/storage/in_mem_storage.rs index 78fc842f..e4c4fa62 100644 --- a/src/dispatching/dialogue/storage/in_mem_storage.rs +++ b/src/dispatching/dialogue/storage/in_mem_storage.rs @@ -1,5 +1,5 @@ use super::Storage; -use futures::future::BoxFuture; +use futures::{future::BoxFuture, FutureExt}; use std::{collections::HashMap, sync::Arc}; use tokio::sync::Mutex; @@ -32,7 +32,7 @@ impl Storage for InMemStorage { where D: Send + 'static, { - Box::pin(async move { Ok(self.map.lock().await.remove(&chat_id)) }) + async move { Ok(self.map.lock().await.remove(&chat_id)) }.boxed() } fn update_dialogue( @@ -43,6 +43,6 @@ impl Storage for InMemStorage { where D: Send + 'static, { - Box::pin(async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) }) + async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) }.boxed() } } diff --git a/src/dispatching/dialogue/storage/redis_storage.rs b/src/dispatching/dialogue/storage/redis_storage.rs index a8514355..a3b8c6d7 100644 --- a/src/dispatching/dialogue/storage/redis_storage.rs +++ b/src/dispatching/dialogue/storage/redis_storage.rs @@ -1,5 +1,5 @@ use super::{serializer::Serializer, Storage}; -use futures::future::BoxFuture; +use futures::{future::BoxFuture, FutureExt}; use redis::{AsyncCommands, FromRedisValue, IntoConnectionInfo}; use serde::{de::DeserializeOwned, Serialize}; use std::{ @@ -57,7 +57,7 @@ where self: Arc, chat_id: i64, ) -> BoxFuture<'static, Result, Self::Error>> { - Box::pin(async move { + async move { let res = redis::pipe() .atomic() .get(chat_id) @@ -80,7 +80,7 @@ where } _ => unreachable!(), } - }) + }.boxed() } fn update_dialogue( @@ -88,7 +88,7 @@ where chat_id: i64, dialogue: D, ) -> BoxFuture<'static, Result, Self::Error>> { - Box::pin(async move { + async move { let dialogue = self.serializer.serialize(&dialogue).map_err(RedisStorageError::SerdeError)?; Ok(self @@ -99,6 +99,7 @@ where .await? .map(|d| self.serializer.deserialize(&d).map_err(RedisStorageError::SerdeError)) .transpose()?) - }) + } + .boxed() } } diff --git a/src/dispatching/dispatcher_handler.rs b/src/dispatching/dispatcher_handler.rs index 94ec6dbd..430c89cf 100644 --- a/src/dispatching/dispatcher_handler.rs +++ b/src/dispatching/dispatcher_handler.rs @@ -1,7 +1,7 @@ use std::future::Future; use crate::dispatching::{DispatcherHandlerRx, UpdateWithCx}; -use futures::future::BoxFuture; +use futures::{future::BoxFuture, FutureExt}; /// An asynchronous handler of a stream of updates used in [`Dispatcher`]. /// @@ -25,6 +25,6 @@ where where UpdateWithCx: Send + 'static, { - Box::pin(async move { self(updates).await }) + async move { self(updates).await }.boxed() } } diff --git a/src/dispatching/dispatcher_handler_rx_ext.rs b/src/dispatching/dispatcher_handler_rx_ext.rs index 12e26146..6142b133 100644 --- a/src/dispatching/dispatcher_handler_rx_ext.rs +++ b/src/dispatching/dispatcher_handler_rx_ext.rs @@ -30,7 +30,7 @@ where where Self: Stream>, { - Box::pin(self.filter_map(|cx| async move { cx.update.text_owned().map(|text| (cx, text)) })) + self.filter_map(|cx| async move { cx.update.text_owned().map(|text| (cx, text)) }).boxed() } fn commands(self, bot_name: N) -> BoxStream<'static, (UpdateWithCx, C)> @@ -41,10 +41,12 @@ where { let bot_name = bot_name.into(); - Box::pin(self.text_messages().filter_map(move |(cx, text)| { - let bot_name = bot_name.clone(); + self.text_messages() + .filter_map(move |(cx, text)| { + let bot_name = bot_name.clone(); - async move { C::parse(&text, &bot_name).map(|command| (cx, command)).ok() } - })) + async move { C::parse(&text, &bot_name).map(|command| (cx, command)).ok() } + }) + .boxed() } } diff --git a/src/error_handlers.rs b/src/error_handlers.rs index 740ae427..f2b8572f 100644 --- a/src/error_handlers.rs +++ b/src/error_handlers.rs @@ -1,6 +1,6 @@ //! Convenient error handling. -use futures::future::BoxFuture; +use futures::{future::BoxFuture, FutureExt}; use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc}; /// An asynchronous handler of an error. @@ -19,7 +19,7 @@ where Fut: Future + Send, { fn handle_error(self: Arc, error: E) -> BoxFuture<'static, ()> { - Box::pin(async move { self(error).await }) + async move { self(error).await }.boxed() } } @@ -81,11 +81,12 @@ where Eh: ErrorHandler + Send + Sync, Arc: 'a, { - Box::pin(async move { + async move { if let Err(error) = self { eh.handle_error(error).await; } - }) + } + .boxed() } } @@ -114,7 +115,7 @@ impl IgnoringErrorHandler { impl ErrorHandler for IgnoringErrorHandler { fn handle_error(self: Arc, _: E) -> BoxFuture<'static, ()> { - Box::pin(async {}) + async {}.boxed() } } @@ -160,7 +161,7 @@ impl IgnoringErrorHandlerSafe { #[allow(unreachable_code)] impl ErrorHandler for IgnoringErrorHandlerSafe { fn handle_error(self: Arc, _: Infallible) -> BoxFuture<'static, ()> { - Box::pin(async {}) + async {}.boxed() } } @@ -207,6 +208,6 @@ where { fn handle_error(self: Arc, error: E) -> BoxFuture<'static, ()> { log::error!("{text}: {:?}", error, text = self.text); - Box::pin(async {}) + async {}.boxed() } } From e33bbeb027fcdad5c83c1617d7c18602fd5f5103 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 1 Oct 2020 17:56:48 +0600 Subject: [PATCH 91/99] async { ... }.boxed() -> Box::pin(async { ... }) --- .../dialogue/dialogue_dispatcher_handler.rs | 2 +- src/dispatching/dialogue/storage/in_mem_storage.rs | 4 ++-- src/dispatching/dialogue/storage/redis_storage.rs | 9 ++++----- src/dispatching/dispatcher_handler.rs | 2 +- src/error_handlers.rs | 13 ++++++------- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/dispatching/dialogue/dialogue_dispatcher_handler.rs b/src/dispatching/dialogue/dialogue_dispatcher_handler.rs index 5e8ad2bd..04900baf 100644 --- a/src/dispatching/dialogue/dialogue_dispatcher_handler.rs +++ b/src/dispatching/dialogue/dialogue_dispatcher_handler.rs @@ -27,6 +27,6 @@ where where DialogueWithCx: Send + 'static, { - async move { self(cx).await }.boxed() + Box::pin(async move { self(cx).await }) } } diff --git a/src/dispatching/dialogue/storage/in_mem_storage.rs b/src/dispatching/dialogue/storage/in_mem_storage.rs index e4c4fa62..14db6972 100644 --- a/src/dispatching/dialogue/storage/in_mem_storage.rs +++ b/src/dispatching/dialogue/storage/in_mem_storage.rs @@ -32,7 +32,7 @@ impl Storage for InMemStorage { where D: Send + 'static, { - async move { Ok(self.map.lock().await.remove(&chat_id)) }.boxed() + Box::pin(async move { Ok(self.map.lock().await.remove(&chat_id)) }) } fn update_dialogue( @@ -43,6 +43,6 @@ impl Storage for InMemStorage { where D: Send + 'static, { - async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) }.boxed() + Box::pin(async move { Ok(self.map.lock().await.insert(chat_id, dialogue)) }) } } diff --git a/src/dispatching/dialogue/storage/redis_storage.rs b/src/dispatching/dialogue/storage/redis_storage.rs index a3b8c6d7..975c4a5d 100644 --- a/src/dispatching/dialogue/storage/redis_storage.rs +++ b/src/dispatching/dialogue/storage/redis_storage.rs @@ -57,7 +57,7 @@ where self: Arc, chat_id: i64, ) -> BoxFuture<'static, Result, Self::Error>> { - async move { + Box::pin(async move { let res = redis::pipe() .atomic() .get(chat_id) @@ -80,7 +80,7 @@ where } _ => unreachable!(), } - }.boxed() + }) } fn update_dialogue( @@ -88,7 +88,7 @@ where chat_id: i64, dialogue: D, ) -> BoxFuture<'static, Result, Self::Error>> { - async move { + Box::pin(async move { let dialogue = self.serializer.serialize(&dialogue).map_err(RedisStorageError::SerdeError)?; Ok(self @@ -99,7 +99,6 @@ where .await? .map(|d| self.serializer.deserialize(&d).map_err(RedisStorageError::SerdeError)) .transpose()?) - } - .boxed() + }) } } diff --git a/src/dispatching/dispatcher_handler.rs b/src/dispatching/dispatcher_handler.rs index 430c89cf..984c0d76 100644 --- a/src/dispatching/dispatcher_handler.rs +++ b/src/dispatching/dispatcher_handler.rs @@ -25,6 +25,6 @@ where where UpdateWithCx: Send + 'static, { - async move { self(updates).await }.boxed() + Box::pin(async move { self(updates).await }) } } diff --git a/src/error_handlers.rs b/src/error_handlers.rs index f2b8572f..5d6a1e73 100644 --- a/src/error_handlers.rs +++ b/src/error_handlers.rs @@ -19,7 +19,7 @@ where Fut: Future + Send, { fn handle_error(self: Arc, error: E) -> BoxFuture<'static, ()> { - async move { self(error).await }.boxed() + Box::pin(async move { self(error).await }) } } @@ -81,12 +81,11 @@ where Eh: ErrorHandler + Send + Sync, Arc: 'a, { - async move { + Box::pin(async move { if let Err(error) = self { eh.handle_error(error).await; } - } - .boxed() + }) } } @@ -115,7 +114,7 @@ impl IgnoringErrorHandler { impl ErrorHandler for IgnoringErrorHandler { fn handle_error(self: Arc, _: E) -> BoxFuture<'static, ()> { - async {}.boxed() + Box::pin(async {}) } } @@ -161,7 +160,7 @@ impl IgnoringErrorHandlerSafe { #[allow(unreachable_code)] impl ErrorHandler for IgnoringErrorHandlerSafe { fn handle_error(self: Arc, _: Infallible) -> BoxFuture<'static, ()> { - async {}.boxed() + Box::pin(async {}) } } @@ -208,6 +207,6 @@ where { fn handle_error(self: Arc, error: E) -> BoxFuture<'static, ()> { log::error!("{text}: {:?}", error, text = self.text); - async {}.boxed() + Box::pin(async {}) } } From e6ceee752f119590ca89344f5f0a7efc607c99fc Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 1 Oct 2020 17:58:26 +0600 Subject: [PATCH 92/99] Update CODE_STYLE.md --- CODE_STYLE.md | 1 + src/dispatching/dialogue/dialogue_dispatcher_handler.rs | 2 +- src/dispatching/dialogue/storage/in_mem_storage.rs | 2 +- src/dispatching/dispatcher_handler.rs | 2 +- src/error_handlers.rs | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CODE_STYLE.md b/CODE_STYLE.md index 656a5c34..964aea8c 100644 --- a/CODE_STYLE.md +++ b/CODE_STYLE.md @@ -123,3 +123,4 @@ C: Into, { ... } ## Misc 1. Use `Into<...>` only where there exists at least one conversion **and** it will be logically to use. 2. Always mark a function as `#[must_use]` if its return value **must** be used. + 3. `Box::pin(async [move] { ... })` instead of `async [move] { ... }.boxed()`. diff --git a/src/dispatching/dialogue/dialogue_dispatcher_handler.rs b/src/dispatching/dialogue/dialogue_dispatcher_handler.rs index 04900baf..1a596bcc 100644 --- a/src/dispatching/dialogue/dialogue_dispatcher_handler.rs +++ b/src/dispatching/dialogue/dialogue_dispatcher_handler.rs @@ -1,5 +1,5 @@ use crate::prelude::{DialogueStage, DialogueWithCx}; -use futures::{future::BoxFuture, FutureExt}; +use futures::future::BoxFuture; use std::{future::Future, sync::Arc}; /// An asynchronous handler of an update used in [`DialogueDispatcher`]. diff --git a/src/dispatching/dialogue/storage/in_mem_storage.rs b/src/dispatching/dialogue/storage/in_mem_storage.rs index 14db6972..78fc842f 100644 --- a/src/dispatching/dialogue/storage/in_mem_storage.rs +++ b/src/dispatching/dialogue/storage/in_mem_storage.rs @@ -1,5 +1,5 @@ use super::Storage; -use futures::{future::BoxFuture, FutureExt}; +use futures::future::BoxFuture; use std::{collections::HashMap, sync::Arc}; use tokio::sync::Mutex; diff --git a/src/dispatching/dispatcher_handler.rs b/src/dispatching/dispatcher_handler.rs index 984c0d76..94ec6dbd 100644 --- a/src/dispatching/dispatcher_handler.rs +++ b/src/dispatching/dispatcher_handler.rs @@ -1,7 +1,7 @@ use std::future::Future; use crate::dispatching::{DispatcherHandlerRx, UpdateWithCx}; -use futures::{future::BoxFuture, FutureExt}; +use futures::future::BoxFuture; /// An asynchronous handler of a stream of updates used in [`Dispatcher`]. /// diff --git a/src/error_handlers.rs b/src/error_handlers.rs index 5d6a1e73..740ae427 100644 --- a/src/error_handlers.rs +++ b/src/error_handlers.rs @@ -1,6 +1,6 @@ //! Convenient error handling. -use futures::{future::BoxFuture, FutureExt}; +use futures::future::BoxFuture; use std::{convert::Infallible, fmt::Debug, future::Future, sync::Arc}; /// An asynchronous handler of an error. From b17728d76065fa4b71fd7fb0732f1e2455b840d6 Mon Sep 17 00:00:00 2001 From: Temirkhan Myrzamadi Date: Thu, 1 Oct 2020 18:19:52 +0600 Subject: [PATCH 93/99] Remove an unused import --- src/dispatching/dialogue/storage/redis_storage.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dispatching/dialogue/storage/redis_storage.rs b/src/dispatching/dialogue/storage/redis_storage.rs index 975c4a5d..a8514355 100644 --- a/src/dispatching/dialogue/storage/redis_storage.rs +++ b/src/dispatching/dialogue/storage/redis_storage.rs @@ -1,5 +1,5 @@ use super::{serializer::Serializer, Storage}; -use futures::{future::BoxFuture, FutureExt}; +use futures::future::BoxFuture; use redis::{AsyncCommands, FromRedisValue, IntoConnectionInfo}; use serde::{de::DeserializeOwned, Serialize}; use std::{ From eed1bbb0fc6692ac0fe237b296b577a504965e12 Mon Sep 17 00:00:00 2001 From: Jaslo Ziska Date: Fri, 2 Oct 2020 11:13:27 +0200 Subject: [PATCH 94/99] Conditionally add teloxide-macros crate and reexport macros This commit adds the feature "macros" which conditionally adds the teloxide-macros crate and reexports its macros. All (doc) tests using these macros are also conditionally enabled now. Also change examples accordingly. This commit solves https://github.com/teloxide/teloxide/issues/283 --- Cargo.toml | 4 +++- examples/admin_bot/Cargo.toml | 2 +- examples/simple_commands_bot/Cargo.toml | 2 +- src/dispatching/dialogue/mod.rs | 9 +++++++-- src/lib.rs | 6 ++++++ src/utils/command.rs | 15 +++++++++++++++ tests/command.rs | 12 ++++++++++++ 7 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 37991145..d92703f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,8 @@ bincode-serializer = ["bincode"] frunk- = ["frunk"] +macros = ["teloxide-macros"] + nightly = [] # currently used only for `README.md` tests [dependencies] @@ -57,7 +59,7 @@ serde_cbor = { version = "0.11.1", optional = true } bincode = { version = "1.3.1", optional = true } frunk = { version = "0.3.1", optional = true } -teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master" } +teloxide-macros = { git = "https://github.com/teloxide/teloxide-macros", branch = "master", optional = true } [dev-dependencies] smart-default = "0.6.0" diff --git a/examples/admin_bot/Cargo.toml b/examples/admin_bot/Cargo.toml index 3a4950a8..8f2031bc 100644 --- a/examples/admin_bot/Cargo.toml +++ b/examples/admin_bot/Cargo.toml @@ -10,7 +10,7 @@ edition = "2018" log = "0.4.8" pretty_env_logger = "0.4.0" tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } -teloxide = { path = "../../" } +teloxide = { path = "../../", features = ["macros"] } [profile.release] lto = true \ No newline at end of file diff --git a/examples/simple_commands_bot/Cargo.toml b/examples/simple_commands_bot/Cargo.toml index 7acc2030..dcf9aa20 100644 --- a/examples/simple_commands_bot/Cargo.toml +++ b/examples/simple_commands_bot/Cargo.toml @@ -10,4 +10,4 @@ edition = "2018" log = "0.4.8" pretty_env_logger = "0.4.0" tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } -teloxide = { path = "../../" } +teloxide = { path = "../../", features = ["macros"] } diff --git a/src/dispatching/dialogue/mod.rs b/src/dispatching/dialogue/mod.rs index 5030fd4b..00bdc6cf 100644 --- a/src/dispatching/dialogue/mod.rs +++ b/src/dispatching/dialogue/mod.rs @@ -30,10 +30,10 @@ //! skeleton should look like: //! //! ```no_run +//! # #[cfg(feature = "macros")] { //! use std::convert::Infallible; //! -//! use teloxide::prelude::*; -//! use teloxide_macros::{teloxide, Transition}; +//! use teloxide::{dispatching::dialogue::Transition, prelude::*, teloxide}; //! //! struct _1State; //! struct _2State; @@ -97,6 +97,7 @@ //! .dispatch() //! .await; //! } +//! # } //! ``` //! //! - `#[teloxide(subtransition)]` implements [`Subtransition`] for the first @@ -156,6 +157,10 @@ pub use transition::{ Subtransition, SubtransitionOutputType, Transition, TransitionIn, TransitionOut, }; +#[cfg(feature = "macros")] +#[cfg_attr(all(docsrs, feature = "nightly"), doc(cfg(feature = "macros")))] +pub use teloxide_macros::Transition; + #[cfg(feature = "redis-storage")] pub use storage::{RedisStorage, RedisStorageError}; diff --git a/src/lib.rs b/src/lib.rs index 7ffb1775..08ffe910 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,6 +41,7 @@ #![allow(clippy::match_bool)] #![forbid(unsafe_code)] #![cfg_attr(all(feature = "nightly", doctest), feature(external_doc))] +#![cfg_attr(all(docsrs, feature = "nightly"), feature(doc_cfg))] pub use bot::{Bot, BotBuilder}; pub use dispatching::repls::{ @@ -61,8 +62,13 @@ pub mod requests; pub mod types; pub mod utils; +#[cfg(feature = "macros")] extern crate teloxide_macros; +#[cfg(feature = "macros")] +#[cfg_attr(all(docsrs, feature = "nightly"), doc(cfg(feature = "macros")))] +pub use teloxide_macros::teloxide; + #[cfg(all(feature = "nightly", doctest))] #[doc(include = "../README.md")] enum ReadmeDocTests {} diff --git a/src/utils/command.rs b/src/utils/command.rs index ff5c9023..a2bd4c22 100644 --- a/src/utils/command.rs +++ b/src/utils/command.rs @@ -6,6 +6,7 @@ //! //! # Using BotCommand //! ``` +//! # #[cfg(feature = "macros")] { //! use teloxide::utils::command::BotCommand; //! //! type UnitOfTime = u8; @@ -19,6 +20,7 @@ //! //! let command = AdminCommand::parse("/ban 5 h", "bot_name").unwrap(); //! assert_eq!(command, AdminCommand::Ban(5, 'h')); +//! # } //! ``` //! //! # Using parse_command @@ -46,12 +48,16 @@ use serde::export::Formatter; use std::{error::Error, fmt::Display}; + +#[cfg(feature = "macros")] +#[cfg_attr(all(docsrs, feature = "nightly"), doc(cfg(feature = "macros")))] pub use teloxide_macros::BotCommand; /// An enumeration of bot's commands. /// /// # Example /// ``` +/// # #[cfg(feature = "macros")] { /// use teloxide::utils::command::BotCommand; /// /// type UnitOfTime = u8; @@ -65,6 +71,7 @@ pub use teloxide_macros::BotCommand; /// /// let command = AdminCommand::parse("/ban 5 h", "bot_name").unwrap(); /// assert_eq!(command, AdminCommand::Ban(5, 'h')); +/// # } /// ``` /// /// ## Enum attributes @@ -86,6 +93,7 @@ pub use teloxide_macros::BotCommand; /// /// ### Example /// ``` +/// # #[cfg(feature = "macros")] { /// use teloxide::utils::command::BotCommand; /// /// #[derive(BotCommand, PartialEq, Debug)] @@ -96,6 +104,7 @@ pub use teloxide_macros::BotCommand; /// /// let command = Command::parse("/text hello my dear friend!", "").unwrap(); /// assert_eq!(command, Command::Text("hello my dear friend!".to_string())); +/// # } /// ``` /// /// - `split` - separates a messsage by a given separator (the default is the @@ -104,6 +113,7 @@ pub use teloxide_macros::BotCommand; /// /// ### Example /// ``` +/// # #[cfg(feature = "macros")] { /// use teloxide::utils::command::BotCommand; /// /// #[derive(BotCommand, PartialEq, Debug)] @@ -114,6 +124,7 @@ pub use teloxide_macros::BotCommand; /// /// let command = Command::parse("/nums 1 32 -5", "").unwrap(); /// assert_eq!(command, Command::Nums(1, 32, -5)); +/// # } /// ``` /// /// 5. `#[command(separator = "sep")]` @@ -122,6 +133,7 @@ pub use teloxide_macros::BotCommand; /// /// ### Example /// ``` +/// # #[cfg(feature = "macros")] { /// use teloxide::utils::command::BotCommand; /// /// #[derive(BotCommand, PartialEq, Debug)] @@ -132,6 +144,7 @@ pub use teloxide_macros::BotCommand; /// /// let command = Command::parse("/nums 1|32|5", "").unwrap(); /// assert_eq!(command, Command::Nums(1, 32, 5)); +/// # } /// ``` /// /// ## Variant attributes @@ -149,6 +162,7 @@ pub use teloxide_macros::BotCommand; /// /// ### Example /// ``` +/// # #[cfg(feature = "macros")] { /// use teloxide::utils::command::{BotCommand, ParseError}; /// /// fn accept_two_digits(input: String) -> Result<(u8,), ParseError> { @@ -172,6 +186,7 @@ pub use teloxide_macros::BotCommand; /// assert_eq!(command, Command::Num(12)); /// let command = Command::parse("/num 333", ""); /// assert!(command.is_err()); +/// # } /// ``` /// /// 3. `#[command(prefix = "prefix")]` diff --git a/tests/command.rs b/tests/command.rs index d7badef0..4b059614 100644 --- a/tests/command.rs +++ b/tests/command.rs @@ -1,9 +1,11 @@ +#[cfg(feature = "macros")] use teloxide::utils::command::{BotCommand, ParseError}; // We put tests here because macro expand in unit tests in module // teloxide::utils::command was a failure #[test] +#[cfg(feature = "macros")] fn parse_command_with_args() { #[command(rename = "lowercase")] #[derive(BotCommand, Debug, PartialEq)] @@ -19,6 +21,7 @@ fn parse_command_with_args() { } #[test] +#[cfg(feature = "macros")] fn parse_command_with_non_string_arg() { #[command(rename = "lowercase")] #[derive(BotCommand, Debug, PartialEq)] @@ -34,6 +37,7 @@ fn parse_command_with_non_string_arg() { } #[test] +#[cfg(feature = "macros")] fn attribute_prefix() { #[command(rename = "lowercase")] #[derive(BotCommand, Debug, PartialEq)] @@ -50,6 +54,7 @@ fn attribute_prefix() { } #[test] +#[cfg(feature = "macros")] fn many_attributes() { #[command(rename = "lowercase")] #[derive(BotCommand, Debug, PartialEq)] @@ -64,6 +69,7 @@ fn many_attributes() { } #[test] +#[cfg(feature = "macros")] fn global_attributes() { #[command(prefix = "!", rename = "lowercase", description = "Bot commands")] #[derive(BotCommand, Debug, PartialEq)] @@ -79,6 +85,7 @@ fn global_attributes() { } #[test] +#[cfg(feature = "macros")] fn parse_command_with_bot_name() { #[command(rename = "lowercase")] #[derive(BotCommand, Debug, PartialEq)] @@ -95,6 +102,7 @@ fn parse_command_with_bot_name() { } #[test] +#[cfg(feature = "macros")] fn parse_with_split() { #[command(rename = "lowercase")] #[command(parse_with = "split")] @@ -111,6 +119,7 @@ fn parse_with_split() { } #[test] +#[cfg(feature = "macros")] fn parse_with_split2() { #[command(rename = "lowercase")] #[command(parse_with = "split", separator = "|")] @@ -127,6 +136,7 @@ fn parse_with_split2() { } #[test] +#[cfg(feature = "macros")] fn parse_custom_parser() { fn custom_parse_function(s: String) -> Result<(u8, String), ParseError> { let vec = s.split_whitespace().collect::>(); @@ -154,6 +164,7 @@ fn parse_custom_parser() { } #[test] +#[cfg(feature = "macros")] fn parse_named_fields() { #[command(rename = "lowercase")] #[command(parse_with = "split")] @@ -170,6 +181,7 @@ fn parse_named_fields() { } #[test] +#[cfg(feature = "macros")] fn descriptions_off() { #[command(rename = "lowercase")] #[derive(BotCommand, Debug, PartialEq)] From 03c21e4651c532431ca28f4db09c03ae639f597e Mon Sep 17 00:00:00 2001 From: Jaslo Ziska Date: Sat, 3 Oct 2020 17:23:40 +0200 Subject: [PATCH 95/99] Fix documentation for methods using InputFile This commit fixes https://github.com/teloxide/teloxide/issues/254 --- src/bot/api.rs | 176 ++++++++++++++-------- src/requests/all/send_animation.rs | 26 +++- src/requests/all/send_audio.rs | 30 ++-- src/requests/all/send_document.rs | 29 ++-- src/requests/all/send_photo.rs | 14 +- src/requests/all/send_sticker.rs | 16 +- src/requests/all/send_video.rs | 33 ++-- src/requests/all/send_video_note.rs | 32 ++-- src/requests/all/send_voice.rs | 15 +- src/requests/all/set_sticker_set_thumb.rs | 11 +- src/types/sticker_type.rs | 14 +- 11 files changed, 249 insertions(+), 147 deletions(-) diff --git a/src/bot/api.rs b/src/bot/api.rs index 8fe0fc80..10df2dd5 100644 --- a/src/bot/api.rs +++ b/src/bot/api.rs @@ -156,16 +156,17 @@ impl Bot { /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `photo`: Photo to send. + /// - `photo`: Pass [`InputFile::FileId`] to send a photo that exists on + /// the Telegram servers (recommended), pass an [`InputFile::Url`] for + /// Telegram to get a photo from the Internet (5MB max.), pass + /// [`InputFile::File`] to upload a picture from the file system or + /// [`InputFile::Memory`] to upload a photo from memory (10MB max. + /// each). [More info on Sending Files »]. /// - /// Pass [`InputFile::File`] to send a photo that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. - /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files /// @@ -184,11 +185,26 @@ impl Bot { ) } + /// Use this method to send audio files /// + /// [The official docs](https://core.telegram.org/bots/api#sendaudio). /// /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). + /// - `audio`: Pass [`InputFile::FileId`] to send an audio file that + /// exists on the Telegram servers (recommended), pass an + /// [`InputFile::Url`] for Telegram to get a file from the Internet + /// (20MB max.), pass [`InputFile::File`] to upload a file from the file + /// system or [`InputFile::Memory`] to upload a file from memory (50MB + /// max. each). [More info on Sending Files »]. + /// + /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files /// /// # Notes /// Uses [a default parse mode] if specified in [`BotBuilder`]. @@ -207,20 +223,22 @@ impl Bot { /// Use this method to send general files. /// - /// Bots can currently send files of any type of up to 50 MB in size, this - /// limit may be changed in the future. - /// /// [The official docs](https://core.telegram.org/bots/api#senddocument). /// /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `document`: File to send. + /// - `document`: Pass [`InputFile::FileId`] to send a file that exists on + /// the Telegram servers (recommended), pass an [`InputFile::Url`] for + /// Telegram to get a file from the Internet (20MB max.), pass + /// [`InputFile::File`] to upload a file from the file system or + /// [`InputFile::Memory`] to upload a file from memory (50MB max. each). + /// [More info on Sending Files »]. /// - /// Pass a file_id as String to send a file that exists on the - /// Telegram servers (recommended), pass an HTTP URL as a String for - /// Telegram to get a file from the Internet, or upload a new one using - /// `multipart/form-data`. [More info on Sending Files »]. + /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files /// @@ -242,24 +260,24 @@ impl Bot { /// Use this method to send video files, Telegram clients support mp4 videos /// (other formats may be sent as Document). /// - /// Bots can currently send video files of up to 50 MB in size, this - /// limit may be changed in the future. - /// /// [The official docs](https://core.telegram.org/bots/api#sendvideo). /// /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `video`: Video to sent. + /// - `video`: Pass [`InputFile::FileId`] to send a file that exists on + /// the Telegram servers (recommended), pass an [`InputFile::Url`] for + /// Telegram to get a file from the Internet (20MB max.), pass + /// [`InputFile::File`] to upload a file from the file system or + /// [`InputFile::Memory`] to upload a file from memory (50MB max. each). + /// [More info on Sending Files »]. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. - /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files /// /// # Notes /// Uses [a default parse mode] if specified in [`BotBuilder`]. @@ -279,15 +297,24 @@ impl Bot { /// Use this method to send animation files (GIF or H.264/MPEG-4 AVC video /// without sound). /// - /// Bots can currently send animation files of up to 50 MB in size, this - /// limit may be changed in the future. - /// /// [The official docs](https://core.telegram.org/bots/api#sendanimation). /// /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `animation`: Animation to send. + /// - `animation`: Pass [`InputFile::FileId`] to send a file that exists + /// on the Telegram servers (recommended), pass an [`InputFile::Url`] + /// for Telegram to get a file from the Internet (20MB max.), pass + /// [`InputFile::File`] to upload a file from the file system or + /// [`InputFile::Memory`] to upload a file from memory (50MB max. each). + /// [More info on Sending Files »]. + /// + /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files /// /// # Notes /// Uses [a default parse mode] if specified in [`BotBuilder`]. @@ -308,9 +335,7 @@ impl Bot { /// display the file as a playable voice message. /// /// For this to work, your audio must be in an .ogg file encoded with OPUS - /// (other formats may be sent as [`Audio`] or [`Document`]). Bots can - /// currently send voice messages of up to 50 MB in size, this limit may - /// be changed in the future. + /// (other formats may be sent as [`Audio`] or [`Document`]). /// /// [The official docs](https://core.telegram.org/bots/api#sendvoice). /// @@ -320,16 +345,18 @@ impl Bot { /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `voice`: Audio file to send. + /// - `voice`: Pass [`InputFile::FileId`] to send a file that exists on + /// the Telegram servers (recommended), pass an [`InputFile::Url`] for + /// Telegram to get a file from the Internet (20MB max.), pass + /// [`InputFile::File`] to upload a file from the file system or + /// [`InputFile::Memory`] to upload a file from memory (50MB max. each). + /// [More info on Sending Files »]. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. - /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files /// /// # Notes @@ -352,20 +379,23 @@ impl Bot { /// /// [The official docs](https://core.telegram.org/bots/api#sendvideonote). /// + /// [v.4.0]: https://telegram.org/blog/video-messages-and-telescope + /// /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `video_note`: Video note to send. + /// - `video_note`: Pass [`InputFile::FileId`] to send a file that exists + /// on the Telegram servers (recommended), pass an [`InputFile::Url`] + /// for Telegram to get a file from the Internet (20MB max.), pass + /// [`InputFile::File`] to upload a file from the file system or + /// [`InputFile::Memory`] to upload a file from memory (50MB max. each). + /// [More info on Sending Files »]. /// - /// Pass [`InputFile::File`] to send a file that exists on the Telegram - /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a - /// .webp file from the Internet, or upload a new one using - /// [`InputFile::FileId`]. [More info on Sending Files »]. - /// - /// [v.4.0]: https://telegram.org/blog/video-messages-and-telescope - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn send_video_note(&self, chat_id: C, video_note: InputFile) -> SendVideoNote @@ -382,8 +412,8 @@ impl Bot { /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `media`: A JSON-serialized array describing photos and videos to be - /// sent, must include 2–10 items. + /// - `media`: A vector of photos and videos as [`InputMedia`] to be sent, + /// must include 2–10 items. pub fn send_media_group(&self, chat_id: C, media: M) -> SendMediaGroup where C: Into, @@ -791,7 +821,14 @@ impl Bot { /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target supergroup or channel (in the format `@channelusername`). - /// - `photo`: New chat photo, uploaded using `multipart/form-data`. + /// - `photo`: New chat photo, pass [`InputFile::File`] to upload a file + /// from the file system or [`InputFile::Memory`] to upload a file from + /// memory (10MB max. each). [More info on Sending Files »]. + /// + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn set_chat_photo(&self, chat_id: C, photo: InputFile) -> SetChatPhoto where C: Into, @@ -1277,20 +1314,23 @@ impl Bot { /// /// [The official docs](https://core.telegram.org/bots/api#sendsticker). /// + /// [animated]: https://telegram.org/blog/animated-stickers + /// /// # Params /// - `chat_id`: Unique identifier for the target chat or username of the /// target channel (in the format `@channelusername`). - /// - `sticker`: Sticker to send. + /// - `sticker`: Pass [`InputFile::FileId`] to send a sticker that exists + /// on the Telegram servers (recommended), pass an [`InputFile::Url`] + /// for Telegram to get a sticker (.WEBP file) from the Internet, pass + /// [`InputFile::File`] to upload a sticker from the file system or + /// [`InputFile::Memory`] to upload a sticker from memory [More info on + /// Sending Files »]. /// - /// Pass [`InputFile::File`] to send a file that exists on the Telegram - /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a - /// .webp file from the Internet, or upload a new one using - /// [`InputFile::FileId`]. [More info on Sending Files »]. - /// - /// [animated]: https://telegram.org/blog/animated-stickers - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn send_sticker(&self, chat_id: C, sticker: InputFile) -> SendSticker where @@ -1322,12 +1362,14 @@ impl Bot { /// - `user_id`: User identifier of sticker file owner. /// - `png_sticker`: **Png** image with the sticker, must be up to 512 /// kilobytes in size, dimensions must not exceed 512px, and either - /// width or height must be exactly 512px. [More info on Sending Files - /// »]. + /// width or height must be exactly 512px. Pass [`InputFile::File`] to + /// upload a file from the file system or [`InputFile::Memory`] to + /// upload a file from memory. [More info on Sending Files »]. + /// + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files - /// [`Bot::create_new_sticker_set`]: crate::Bot::create_new_sticker_set - /// [`Bot::add_sticker_to_set`]: crate::Bot::add_sticker_to_set pub fn upload_sticker_file(&self, user_id: i32, png_sticker: InputFile) -> UploadStickerFile { UploadStickerFile::new(self.clone(), user_id, png_sticker) } diff --git a/src/requests/all/send_animation.rs b/src/requests/all/send_animation.rs index 287ebd93..df52f20c 100644 --- a/src/requests/all/send_animation.rs +++ b/src/requests/all/send_animation.rs @@ -90,6 +90,19 @@ impl SendAnimation { } /// Animation to send. + /// + /// Pass [`InputFile::FileId`] to send a file that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// file from the Internet (20MB max.), pass [`InputFile::File`] to upload + /// a file from the file system or [`InputFile::Memory`] to upload a file + /// from memory (50MB max. each). [More info on Sending Files »]. + /// + /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn animation(mut self, val: InputFile) -> Self { self.animation = val; self @@ -116,13 +129,18 @@ impl SendAnimation { /// Thumbnail of the file sent; can be ignored if thumbnail generation for /// the file is supported server-side. /// - /// The thumbnail should be in JPEG format and less than 200 kB in size. A + /// The thumbnail should be in JPEG format and less than 200kB in size. A /// thumbnail‘s width and height should not exceed 320. Ignored if the - /// file is not uploaded using [`InputFile::File`]. Thumbnails can’t be - /// reused and can be only uploaded as a new file, with - /// [`InputFile::File`]. + /// animation is not uploaded using [`InputFile::File`] or + /// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only + /// uploaded as a new file. Pass [`InputFile::File`] to upload a file from + /// the file system or [`InputFile::Memory`] to upload a file from memory. + /// [More info on Sending Files »]. /// /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn thumb(mut self, value: InputFile) -> Self { self.thumb = Some(value); self diff --git a/src/requests/all/send_audio.rs b/src/requests/all/send_audio.rs index f2ed209f..4d9d751a 100644 --- a/src/requests/all/send_audio.rs +++ b/src/requests/all/send_audio.rs @@ -95,14 +95,17 @@ impl SendAudio { /// Audio file to send. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send an audio file that exists on the + /// Telegram servers (recommended), pass an [`InputFile::Url`] for Telegram + /// to get a file from the Internet (20MB max.), pass [`InputFile::File`] + /// to upload a file from the file system or [`InputFile::Memory`] to + /// upload a file from memory (50MB max. each). + /// [More info on Sending Files »]. /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn audio(mut self, val: InputFile) -> Self { @@ -158,13 +161,16 @@ impl SendAudio { /// Thumbnail of the file sent; can be ignored if thumbnail generation for /// the file is supported server-side. /// - /// The thumbnail should be in JPEG format and less than 200 kB in size. A + /// The thumbnail should be in JPEG format and less than 200kB in size. A /// thumbnail‘s width and height should not exceed 320. Ignored if the - /// file is not uploaded using `multipart/form-data`. Thumbnails can’t - /// be reused and can be only uploaded as a new file, so you can pass - /// `attach://` if the thumbnail was uploaded using - /// `multipart/form-data` under ``. [More info on - /// Sending Files »]. + /// audio file is not uploaded using [`InputFile::File`] or + /// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only + /// uploaded as a new file. Pass [`InputFile::File`] to upload a file from + /// the file system or [`InputFile::Memory`] to upload a file from memory. + /// [More info on Sending Files »]. + /// + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn thumb(mut self, val: InputFile) -> Self { diff --git a/src/requests/all/send_document.rs b/src/requests/all/send_document.rs index a3b6ff6f..3bed2c65 100644 --- a/src/requests/all/send_document.rs +++ b/src/requests/all/send_document.rs @@ -81,10 +81,16 @@ impl SendDocument { /// File to send. /// - /// Pass a file_id as String to send a file that exists on the - /// Telegram servers (recommended), pass an HTTP URL as a String for - /// Telegram to get a file from the Internet, or upload a new one using - /// `multipart/form-data`. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send a file that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// file from the Internet (20MB max.), pass [`InputFile::File`] to upload + /// a file from the file system or [`InputFile::Memory`] to upload a file + /// from memory (50MB max. each). [More info on Sending Files »]. + /// + /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn document(mut self, val: InputFile) -> Self { @@ -95,13 +101,16 @@ impl SendDocument { /// Thumbnail of the file sent; can be ignored if thumbnail generation for /// the file is supported server-side. /// - /// The thumbnail should be in JPEG format and less than 200 kB in size. A + /// The thumbnail should be in JPEG format and less than 200kB in size. A /// thumbnail‘s width and height should not exceed 320. Ignored if the - /// file is not uploaded using `multipart/form-data`. Thumbnails can’t - /// be reused and can be only uploaded as a new file, so you can pass - /// “attach://” if the thumbnail was uploaded using - /// `multipart/form-data` under ``. [More info on - /// Sending Files »]. + /// document is not uploaded using [`InputFile::File`] or + /// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only + /// uploaded as a new file. Pass [`InputFile::File`] to upload a file from + /// the file system or [`InputFile::Memory`] to upload a file from memory. + /// [More info on Sending Files »]. + /// + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn thumb(mut self, val: InputFile) -> Self { diff --git a/src/requests/all/send_photo.rs b/src/requests/all/send_photo.rs index 4027f000..c66e6f02 100644 --- a/src/requests/all/send_photo.rs +++ b/src/requests/all/send_photo.rs @@ -73,14 +73,16 @@ impl SendPhoto { /// Photo to send. /// - /// Pass [`InputFile::File`] to send a photo that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send a photo that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// photo from the Internet (5MB max.), pass [`InputFile::File`] to upload + /// a picture from the file system or [`InputFile::Memory`] to upload a + /// photo from memory (10MB max. each). [More info on Sending Files »]. /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn photo(mut self, val: InputFile) -> Self { diff --git a/src/requests/all/send_sticker.rs b/src/requests/all/send_sticker.rs index 5e019e19..9c683a30 100644 --- a/src/requests/all/send_sticker.rs +++ b/src/requests/all/send_sticker.rs @@ -69,14 +69,18 @@ impl SendSticker { /// Sticker to send. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send a sticker that exists on the + /// Telegram servers (recommended), pass an [`InputFile::Url`] for Telegram + /// to get a sticker (.WEBP file) from the Internet, pass + /// [`InputFile::File`] to upload a sticker from the file system or + /// [`InputFile::Memory`] to upload a sticker from memory + /// [More info on Sending Files »]. /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn sticker(mut self, val: InputFile) -> Self { self.sticker = val; diff --git a/src/requests/all/send_video.rs b/src/requests/all/send_video.rs index 30ab6a45..395bf875 100644 --- a/src/requests/all/send_video.rs +++ b/src/requests/all/send_video.rs @@ -92,16 +92,20 @@ impl SendVideo { self } - /// Video to sent. + /// Video to send. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send a file that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// file from the Internet (20MB max.), pass [`InputFile::File`] to upload + /// a file from the file system or [`InputFile::Memory`] to upload a file + /// from memory (50MB max. each). [More info on Sending Files »]. /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn video(mut self, val: InputFile) -> Self { self.video = val; self @@ -128,13 +132,16 @@ impl SendVideo { /// Thumbnail of the file sent; can be ignored if thumbnail generation for /// the file is supported server-side. /// - /// The thumbnail should be in JPEG format and less than 200 kB in size. A + /// The thumbnail should be in JPEG format and less than 200kB in size. A /// thumbnail‘s width and height should not exceed 320. Ignored if the - /// file is not uploaded using `multipart/form-data`. Thumbnails can’t be - /// reused and can be only uploaded as a new file, so you can pass - /// `attach://` if the thumbnail was uploaded using - /// `multipart/form-data` under ``. [More info on Sending - /// Files »]. + /// video file is not uploaded using [`InputFile::File`] or + /// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only + /// uploaded as a new file. Pass [`InputFile::File`] to upload a file from + /// the file system or [`InputFile::Memory`] to upload a file from memory. + /// [More info on Sending Files »]. + /// + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn thumb(mut self, val: InputFile) -> Self { diff --git a/src/requests/all/send_video_note.rs b/src/requests/all/send_video_note.rs index 2ac653be..81638f68 100644 --- a/src/requests/all/send_video_note.rs +++ b/src/requests/all/send_video_note.rs @@ -81,14 +81,17 @@ impl SendVideoNote { /// Video note to send. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send a file that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// file from the Internet (20MB max.), pass [`InputFile::File`] to upload + /// a file from the file system or [`InputFile::Memory`] to upload a file + /// from memory (50MB max. each). [More info on Sending Files »]. /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn video_note(mut self, val: InputFile) -> Self { self.video_note = val; @@ -110,13 +113,18 @@ impl SendVideoNote { /// Thumbnail of the file sent; can be ignored if thumbnail generation for /// the file is supported server-side. /// - /// The thumbnail should be in JPEG format and less than 200 kB in size. A + /// The thumbnail should be in JPEG format and less than 200kB in size. A /// thumbnail‘s width and height should not exceed 320. Ignored if the - /// file is not uploaded using `multipart/form-data`. Thumbnails can’t - /// be reused and can be only uploaded as a new file, so you can pass - /// `attach://` if the thumbnail was uploaded using - /// `multipart/form-data` under ``. [More info on - /// Sending Files »]. + /// video note is not uploaded using [`InputFile::File`] or + /// [`InputFile::Memory`]. Thumbnails can’t be reused and can be only + /// uploaded as a new file. Pass [`InputFile::File`] to upload a file from + /// the file system or [`InputFile::Memory`] to upload a file from memory. + /// [More info on Sending Files »]. + /// + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// + /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn thumb(mut self, val: InputFile) -> Self { self.thumb = Some(val); self diff --git a/src/requests/all/send_voice.rs b/src/requests/all/send_voice.rs index 1e50bbed..29b7f6c1 100644 --- a/src/requests/all/send_voice.rs +++ b/src/requests/all/send_voice.rs @@ -85,14 +85,17 @@ impl SendVoice { /// Audio file to send. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send a file that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// file from the Internet (20MB max.), pass [`InputFile::File`] to upload + /// a file from the file system or [`InputFile::Memory`] to upload a file + /// from memory (50MB max. each). [More info on Sending Files »]. /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory + /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files pub fn voice(mut self, val: InputFile) -> Self { self.voice = val; diff --git a/src/requests/all/set_sticker_set_thumb.rs b/src/requests/all/set_sticker_set_thumb.rs index 1f84aacd..ecf153f4 100644 --- a/src/requests/all/set_sticker_set_thumb.rs +++ b/src/requests/all/set_sticker_set_thumb.rs @@ -58,11 +58,12 @@ impl SetStickerSetThumb { /// thumbnail up to 32 kilobytes in size; see https://core.telegram.org/animated_stickers#technical-requirements /// for animated sticker technical requirements. /// - /// Pass [`InputFile::FileId`] as a String to send a file that already - /// exists on the Telegram servers, pass [`InputFile::Url`] for Telegram - /// to get a file from the Internet, or upload a new one using - /// multipart/form-data. More info on Sending Files ». Animated sticker - /// set thumbnail can't be uploaded via HTTP URL. + /// Pass [`InputFile::FileId`] to send a file that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// file from the Internet (20MB max.), pass [`InputFile::File`] to upload + /// a file from the file system or [`InputFile::Memory`] to upload a file + /// from memory (50MB max. each). [More info on Sending Files »]. Animated + /// sticker set thumbnail can't be uploaded via HTTP URL. /// /// [`InputFile::FileId`]: crate::types::InputFile::FileId /// [`InputFile::Url]: crate::types::InputFile::Url diff --git a/src/types/sticker_type.rs b/src/types/sticker_type.rs index b80added..398ffb3a 100644 --- a/src/types/sticker_type.rs +++ b/src/types/sticker_type.rs @@ -7,14 +7,16 @@ pub enum StickerType { /// dimensions must not exceed 512px, and either width or height must be /// exactly 512px. /// - /// Pass [`InputFile::File`] to send a file that exists on - /// the Telegram servers (recommended), pass an [`InputFile::Url`] for - /// Telegram to get a .webp file from the Internet, or upload a new one - /// using [`InputFile::FileId`]. [More info on Sending Files »]. + /// Pass [`InputFile::FileId`] to send a sticker that exists on the Telegram + /// servers (recommended), pass an [`InputFile::Url`] for Telegram to get a + /// sticker (.WEBP file) from the Internet, pass [`InputFile::File`] to + /// upload a sticker from the file system or [`InputFile::Memory`] to upload + /// a sticker from memory [More info on Sending Files »]. /// - /// [`InputFile::File`]: crate::types::InputFile::File - /// [`InputFile::Url`]: crate::types::InputFile::Url /// [`InputFile::FileId`]: crate::types::InputFile::FileId + /// [`InputFile::Url`]: crate::types::InputFile::Url + /// [`InputFile::File`]: crate::types::InputFile::File + /// [`InputFile::Memory`]: crate::types::InputFile::Memory /// /// [More info on Sending Files »]: https://core.telegram.org/bots/api#sending-files Png(InputFile), From d88e2d0e930a3e0ab7f493577ba5255311fdd207 Mon Sep 17 00:00:00 2001 From: eupn <36292692+eupn@users.noreply.github.com> Date: Thu, 8 Oct 2020 11:46:30 +0800 Subject: [PATCH 96/99] Edit README.md a bit --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 653440eb..e28ed7a4 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ [functional reactive design]: https://en.wikipedia.org/wiki/Functional_reactive_programming [other adaptors]: https://docs.rs/futures/latest/futures/stream/trait.StreamExt.html - - **Dialogues management subsystem.** We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be independent of how/where dialogues are stored. For example, you can just replace one line to achieve [persistence]. Out-of-the-box storages include [Redis]. + - **Dialogues management subsystem.** We have designed our dialogues management subsystem to be easy-to-use, and, furthermore, to be 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]. [persistence]: https://en.wikipedia.org/wiki/Persistence_(computer_science) [Redis]: https://redis.io/ @@ -64,7 +64,7 @@ $ export TELOXIDE_TOKEN= # Windows $ set TELOXIDE_TOKEN= ``` - 4. Be sure that you are up to date: + 4. Make sure that your Rust compiler is up to date: ```bash # If you're using stable $ rustup update stable @@ -75,7 +75,7 @@ $ rustup update nightly $ rustup override set nightly ``` - 5. Execute `cargo new my_bot`, enter the directory and put these lines into your `Cargo.toml`: + 5. Run `cargo new my_bot`, enter the directory and put these lines into your `Cargo.toml`: ```toml [dependencies] teloxide = "0.3.1" @@ -90,7 +90,7 @@ tokio = { version = "0.2.11", features = ["rt-threaded", "macros"] } ## API overview ### The dices bot -This bot throws a dice on each incoming message: +This bot replies with a dice throw to each received message: ([Full](./examples/dices_bot/src/main.rs)) ```rust,no_run @@ -175,11 +175,11 @@ async fn main() {
### Dialogues management -A dialogue is described by an enumeration, where each variant is one of possible dialogue's states. There are also _subtransition functions_, which turn a dialogue from one state to another, thereby forming a [FSM]. +A dialogue is described by an enumeration where each variant is one of possible dialogue's states. There are also _transition functions_, which turn a dialogue from one state to another, thereby forming a [FSM]. [FSM]: https://en.wikipedia.org/wiki/Finite-state_machine -Below is a bot, which asks you three questions and then sends the answers back to you. First, let's start with an enumeration (a collection of our dialogue's states): +Below is a bot that asks you three questions and then sends the answers back to you. First, let's start with an enumeration (a collection of our dialogue's states): ([dialogue_bot/src/dialogue/mod.rs](./examples/dialogue_bot/src/dialogue/mod.rs)) ```rust,ignore @@ -200,7 +200,7 @@ impl Default for Dialogue { } ``` -When a user sends a message to our bot, and such a dialogue does not yet exist, `Dialogue::default()` is invoked, which is `Dialogue::Start`. Every time a message is received, an associated dialogue is extracted, and then passed to a corresponding subtransition function: +When a user sends a message to our bot and such a dialogue does not exist yet, a `Dialogue::default()` is invoked, which is a `Dialogue::Start` in this case. Every time a message is received, an associated dialogue is extracted and then passed to a corresponding transition function:
Dialogue::Start @@ -303,7 +303,7 @@ async fn receive_location(
-All these subtransitions accept a corresponding state (one of the many variants of `Dialogue`), a context, and a textual message. They return `TransitionOut`, e.g. a mapping from `` to `Dialogue`. +All these transition functions accept a corresponding state (one of the many variants of `Dialogue`), a context, and a textual message. They return `TransitionOut`, e.g. a mapping from `` to `Dialogue`. Finally, the `main` function looks like this: @@ -366,7 +366,7 @@ async fn handle_message(cx: UpdateWithCx, dialogue: Dialogue) -> Transi } ``` -The second one produces very strange compiler messages because of the `#[tokio::main]` macro. However, the examples in this README use the second variant for brevity. +The second one produces very strange compiler messages due to the `#[tokio::main]` macro. However, the examples in this README use the second variant for brevity. ## Cargo features @@ -397,15 +397,15 @@ A: No, only the bots API. Q: Why Rust? -A: Most programming languages have their own implementations of Telegram bots frameworks, so why not Rust? We think Rust provides enough good ecosystem and the language itself to be suitable for writing bots. +A: Most programming languages have their own implementations of Telegram bots frameworks, so why not Rust? We think Rust provides a good enough ecosystem and the language for it to be suitable for writing bots. -UPD: The current design spreads wide and deep trait bounds, thereby increasing cognitive complexity. It can be avoided using [mux-stream], but currently the stable Rust channel doesn't support necessary features to use [mux-stream] conveniently. What is even more interesting is that [mux-stream] could make a library from teloxide, not a framework, since the design could be defined by just combining streams of updates. +UPD: The current design relies on wide and deep trait bounds, thereby increasing cognitive complexity. It can be avoided using [mux-stream], but currently the stable Rust channel doesn't support necessary features to use [mux-stream] conveniently. Furthermore, the [mux-stream] could help to make a library out of teloxide, not a framework, since the design in this case could be defined by just combining streams of updates. [mux-stream]: https://github.com/Hirrolot/mux-stream Q: Can I use webhooks? -A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](./examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](./examples/heroku_ping_pong_bot/src/main.rs). +A: teloxide doesn't provide special API for working with webhooks due to their nature with lots of subtle settings. Instead, you should setup your webhook by yourself, as shown in [`examples/ngrok_ping_pong_bot`](./examples/ngrok_ping_pong_bot/src/main.rs) and [`examples/heroku_ping_pong_bot`](./examples/heroku_ping_pong_bot/src/main.rs). Associated links: - [Marvin's Marvellous Guide to All Things Webhook](https://core.telegram.org/bots/webhooks) From 970d33d477026c936fa6f5dfc453cb74afefee02 Mon Sep 17 00:00:00 2001 From: eupn <36292692+eupn@users.noreply.github.com> Date: Thu, 8 Oct 2020 20:01:39 +0700 Subject: [PATCH 97/99] Update README.md Co-authored-by: Temirkhan Myrzamadi --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e28ed7a4..c099957b 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ async fn main() { ### Dialogues management -A dialogue is described by an enumeration where each variant is one of possible dialogue's states. There are also _transition functions_, which turn a dialogue from one state to another, thereby forming a [FSM]. +A dialogue is described by an enumeration where each variant is one of possible dialogue's states. There are also _subtransition functions_, which turn a dialogue from one state to another, thereby forming a [FSM]. [FSM]: https://en.wikipedia.org/wiki/Finite-state_machine From bfe5ae43fb65262ca8068de52152f1672a77b17e Mon Sep 17 00:00:00 2001 From: eupn <36292692+eupn@users.noreply.github.com> Date: Thu, 8 Oct 2020 20:02:17 +0700 Subject: [PATCH 98/99] Update README.md Co-authored-by: Temirkhan Myrzamadi --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c099957b..ad7fc110 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ impl Default for Dialogue { } ``` -When a user sends a message to our bot and such a dialogue does not exist yet, a `Dialogue::default()` is invoked, which is a `Dialogue::Start` in this case. Every time a message is received, an associated dialogue is extracted and then passed to a corresponding transition function: +When a user sends a message to our bot and such a dialogue does not exist yet, a `Dialogue::default()` is invoked, which is a `Dialogue::Start` in this case. Every time a message is received, an associated dialogue is extracted and then passed to a corresponding subtransition function:
Dialogue::Start From ac99b39d67bd67f9704842fcf6c27dfe349fb493 Mon Sep 17 00:00:00 2001 From: eupn <36292692+eupn@users.noreply.github.com> Date: Thu, 8 Oct 2020 20:02:35 +0700 Subject: [PATCH 99/99] Update README.md Co-authored-by: Temirkhan Myrzamadi --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad7fc110..75f9ffcf 100644 --- a/README.md +++ b/README.md @@ -303,7 +303,7 @@ async fn receive_location(
-All these transition functions accept a corresponding state (one of the many variants of `Dialogue`), a context, and a textual message. They return `TransitionOut`, e.g. a mapping from `` to `Dialogue`. +All these subtransition functions accept a corresponding state (one of the many variants of `Dialogue`), a context, and a textual message. They return `TransitionOut`, e.g. a mapping from `` to `Dialogue`. Finally, the `main` function looks like this:

teloxide

- +
@@ -20,7 +20,7 @@ - + A full-featured framework that empowers you to easily build [Telegram bots](https://telegram.org/blog/bot-revolution) using the [`async`/`.await`](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) syntax in [Rust](https://www.rust-lang.org/). It handles all the difficult stuff so you can focus only on your business logic.