Merge branch 'dev' into dispatching2

# Conflicts:
#	Cargo.toml
#	examples/dialogue_bot/Cargo.toml
#	examples/inline_bot/src/main.rs
#	src/dispatching/mod.rs
#	src/lib.rs
This commit is contained in:
p0lunin 2022-01-06 14:25:01 +02:00
commit a8098350fc
27 changed files with 263 additions and 75 deletions

View file

@ -15,7 +15,7 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
toolchain: nightly-2021-10-24
override: true
components: rustfmt
@ -34,7 +34,7 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
toolchain: nightly-2021-10-24
override: true
components: clippy

View file

@ -4,15 +4,31 @@ 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]
## unreleased
## [0.5.1] - 2021-08-05
### Changed
- Require that `AsUpdateStream::Stream` is `Send`
## 0.5.3 - 2021-10-25
### Fixed
- Compilation when the `ctrlc_handler` feature is disabled ([issue 462](https://github.com/teloxide/teloxide/issues/462))
## 0.5.2 - 2021-08-25
### Fixed
- Depend on a correct `futures` version (v0.3.15).
## 0.5.1 - 2021-08-05
### Changed
- Improved log messages when `^C` is received with `^C` handler set up
## [0.5.0] - 2021-07-08
## 0.5.0 - 2021-07-08
### Added
@ -58,7 +74,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Log errors from `Storage::{remove_dialogue, update_dialogue}` in `DialogueDispatcher` ([issue 302](https://github.com/teloxide/teloxide/issues/302)).
- Mark all the functions of `Storage` as `#[must_use]`.
## [0.4.0] - 2021-03-22
## 0.4.0 - 2021-03-22
### Added
- Integrate [teloxide-core].
@ -95,28 +111,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[issue 253]: https://github.com/teloxide/teloxide/issues/253
[pr 257]: https://github.com/teloxide/teloxide/pull/257
## [0.3.4] - 2020-01-13
## 0.3.4 - 2020-01-13
### Fixed
- Failing compilation with `serde::export` ([issue 328](https://github.com/teloxide/teloxide/issues/328)).
## [0.3.3] - 2020-10-30
## 0.3.3 - 2020-10-30
### Fixed
- The `dice` field from `MessageDice` is public now ([issue 306](https://github.com/teloxide/teloxide/issues/306))
## [0.3.2] - 2020-10-23
## 0.3.2 - 2020-10-23
### Added
- `LoginUrl::new` ([issue 298](https://github.com/teloxide/teloxide/issues/298))
## [0.3.1] - 2020-08-25
## 0.3.1 - 2020-08-25
### Added
- `Bot::builder` method ([PR 269](https://github.com/teloxide/teloxide/pull/269)).
## [0.3.0] - 2020-07-31
## 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`.
@ -153,7 +169,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Now methods which can send file to Telegram returns `tokio::io::Result<T>`. 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
## 0.2.0 - 2020-02-25
### Added
- The functionality to parse commands only with a correct bot's name (breaks backwards compatibility) ([Issue 168](https://github.com/teloxide/teloxide/issues/168)).
- This `CHANGELOG.md`.
@ -168,6 +184,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [either](https://crates.io/crates/either) from the dependencies in `Cargo.toml`.
- `teloxide-macros` migrated into [the separate repository](https://github.com/teloxide/teloxide-macros) to easier releases and testing.
## [0.1.0] - 2020-02-19
## 0.1.0 - 2020-02-19
### Added
- This project.

View file

@ -1,6 +1,6 @@
[package]
name = "teloxide"
version = "0.5.1"
version = "0.5.3"
edition = "2018"
description = "An elegant Telegram bots framework for Rust"
repository = "https://github.com/teloxide/teloxide"
@ -10,22 +10,9 @@ keywords = ["teloxide", "telegram", "telegram-bot", "telegram-bot-api"]
categories = ["web-programming", "api-bindings", "asynchronous"]
license = "MIT"
exclude = ["media"]
authors = [
"Hirrolot <hirrolot@gmail.com>",
"Waffle Lapkin <waffle.lapkin@gmail.com>",
"p0lunin <dmytro.polunin@gmail.com>",
"Mishko torop'izhko",
"Mr-Andersen",
"Sergey Levitin <selevit@gmail.com>",
"Rustem B. <bakirov.com@yandex.ru>",
"Alexey Fedechkin <aleksey-fedechkin@rambler.ru>"
]
[badges]
maintenance = { status = "actively-developed" }
[features]
default = ["native-tls", "ctrlc_handler", "teloxide-core/default", "new-dispatching"]
default = ["native-tls", "ctrlc_handler", "teloxide-core/default", "auto-send", "new-dispatching"]
old-dispatching = []
new-dispatching = ["dptree"]

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019-2020 teloxide
Copyright (c) 2019-2022 teloxide
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -51,8 +51,12 @@
# Unix-like
$ export TELOXIDE_TOKEN=<Your token here>
# Windows
# Windows command line
$ set TELOXIDE_TOKEN=<Your token here>
# Windows PowerShell
$ $env:TELOXIDE_TOKEN=<Your token here>
```
4. Make sure that your Rust compiler is up to date:
```bash
@ -68,10 +72,10 @@ $ rustup override set nightly
5. Run `cargo new my_bot`, enter the directory and put these lines into your `Cargo.toml`:
```toml
[dependencies]
teloxide = { version = "0.4", features = ["auto-send", "macros"] }
log = "0.4.8"
teloxide = { version = "0.5", features = ["macros", "auto-send"] }
log = "0.4"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3", features = ["rt-multi-thread", "macros"] }
tokio = { version = "1.8", features = ["rt-multi-thread", "macros"] }
```
## API overview
@ -387,21 +391,24 @@ A: Yes. You can setup any logger, for example, [fern], e.g. teloxide has no spec
Feel free to propose your own bot to our collection!
- [WaffleLapkin/crate_upd_bot](https://github.com/WaffleLapkin/crate_upd_bot) -- A bot that notifies about crate updates.
- [dracarys18/grpmr-rs](https://github.com/dracarys18/grpmr-rs) -- A telegram group manager bot with variety of extra features.
- [mxseev/logram](https://github.com/mxseev/logram) -- Utility that takes logs from anywhere and sends them to Telegram.
- [Hermitter/tepe](https://github.com/Hermitter/tepe) -- A CLI to command a bot to send messages and files over Telegram.
- [dracarys18/grpmr-rs](https://github.com/dracarys18/grpmr-rs) -- A Telegram group manager bot with variety of extra features.
- [steadylearner/subreddit_reader](https://github.com/steadylearner/Rust-Full-Stack/tree/master/commits/teloxide/subreddit_reader) -- A bot that shows the latest posts at Rust subreddit.
- [myblackbeard/basketball-betting-bot](https://github.com/myblackbeard/basketball-betting-bot) -- The bot lets you bet on NBA games against your buddies.
- [ArtHome12/vzmuinebot](https://github.com/ArtHome12/vzmuinebot) -- Telegram bot for food menu navigate.
- [ArtHome12/cognito_bot](https://github.com/ArtHome12/cognito_bot) -- The bot is designed to anonymize messages to a group.
- [Hermitter/tepe](https://github.com/Hermitter/tepe) -- A CLI to command a bot to send messages and files over Telegram.
- [pro-vim/tg-vimhelpbot](https://github.com/pro-vim/tg-vimhelpbot) -- Link `:help` for Vim in Telegram.
- [sschiz/janitor-bot](https://github.com/sschiz/janitor-bot) -- A bot that removes users trying to join to a chat that is designed for comments.
- [myblackbeard/basketball-betting-bot](https://github.com/myblackbeard/basketball-betting-bot) -- The bot lets you bet on NBA games against your buddies.
- [slondr/BeerHolderBot](https://gitlab.com/slondr/BeerHolderBot) -- A bot that holds your beer.
- [mxseev/logram](https://github.com/mxseev/logram) -- Utility that takes logs from anywhere and sends them to Telegram.
- [msfjarvis/walls-bot-rs](https://github.com/msfjarvis/walls-bot-rs) -- Telegram bot for my wallpapers collection, in Rust.
- [MustafaSalih1993/Miss-Vodka-Telegram-Bot](https://github.com/MustafaSalih1993/Miss-Vodka-Telegram-Bot) -- A telegram bot written in rust using "Teloxide" library.
- [MustafaSalih1993/Miss-Vodka-Telegram-Bot](https://github.com/MustafaSalih1993/Miss-Vodka-Telegram-Bot) -- A Telegram bot written in rust using "Teloxide" library.
- [x13a/tg-prompt](https://github.com/x13a/tg-prompt) -- Telegram prompt.
- [magnickolas/remindee-bot](https://github.com/magnickolas/remindee-bot) -- Telegram bot for managing reminders.
- [cyberknight777/knight-bot](https://gitlab.com/cyberknight777/knight-bot) -- A telegram bot with variety of fun features.
- [cyberknight777/knight-bot](https://gitlab.com/cyberknight777/knight-bot) -- A Telegram bot with variety of fun features.
- [wa7sa34cx/the-black-box-bot](https://github.com/wa7sa34cx/the-black-box-bot) -- This is the Black Box Telegram bot. You can hold any items in it.
- [crapstone/hsctt](https://codeberg.org/crapstones-bots/hsctt) -- A Telegram bot that searches for HTTP status codes in all messages and replies with the text form.
- [alenpaul2001/AurSearchBot](https://gitlab.com/alenpaul2001/aursearchbot) -- Telegram bot for searching AUR in inline mode.
## Contributing
See [CONRIBUTING.md](https://github.com/teloxide/teloxide/blob/master/CONTRIBUTING.md).

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["macros", "auto-send"] }
teloxide = { path = "../../", features = ["macros"] }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }

View file

@ -0,0 +1,12 @@
[package]
name = "buttons"
version = "0.1.0"
edition = "2018"
[dependencies]
teloxide = { path = "../../", features = ["macros"] }
tokio = { version = "1.3", features = ["rt-multi-thread", "macros"] }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio-stream = "0.1.6"

View file

@ -0,0 +1,147 @@
use std::error::Error;
use teloxide::{
payloads::SendMessageSetters,
prelude::*,
types::{
InlineKeyboardButton, InlineKeyboardMarkup, InlineQueryResultArticle, InputMessageContent,
InputMessageContentText,
},
utils::command::BotCommand,
};
use tokio_stream::wrappers::UnboundedReceiverStream;
#[derive(BotCommand)]
#[command(rename = "lowercase", description = "These commands are supported:")]
enum Command {
#[command(description = "Display this text")]
Help,
#[command(description = "Start")]
Start,
}
/// Creates a keyboard made by buttons in a big column.
fn make_keyboard() -> InlineKeyboardMarkup {
let mut keyboard: Vec<Vec<InlineKeyboardButton>> = vec![];
let debian_versions = [
"Buzz", "Rex", "Bo", "Hamm", "Slink", "Potato", "Woody", "Sarge", "Etch", "Lenny",
"Squeeze", "Wheezy", "Jessie", "Stretch", "Buster", "Bullseye",
];
for versions in debian_versions.chunks(3) {
let row = versions
.iter()
.map(|&version| InlineKeyboardButton::callback(version.to_owned(), version.to_owned()))
.collect();
keyboard.push(row);
}
InlineKeyboardMarkup::new(keyboard)
}
/// Parse the text wrote on Telegram and check if that text is a valid command
/// or not, then match the command. If the command is `/start` it writes a
/// markup with the `InlineKeyboardMarkup`.
async fn message_handler(
cx: UpdateWithCx<AutoSend<Bot>, Message>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
match cx.update.text() {
Some(text) => {
match BotCommand::parse(text, "buttons") {
Ok(Command::Help) => {
// Just send the description of all commands.
cx.answer(Command::descriptions()).await?;
}
Ok(Command::Start) => {
// Create a list of buttons and send them.
let keyboard = make_keyboard();
cx.answer("Debian versions:").reply_markup(keyboard).await?;
}
Err(_) => {
cx.reply_to("Command not found!").await?;
}
}
}
None => {}
}
Ok(())
}
async fn inline_query_handler(
cx: UpdateWithCx<AutoSend<Bot>, InlineQuery>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let UpdateWithCx { requester: bot, update: query } = cx;
let choose_debian_version = InlineQueryResultArticle::new(
"0",
"Chose debian version",
InputMessageContent::Text(InputMessageContentText::new("Debian versions:")),
)
.reply_markup(make_keyboard());
bot.answer_inline_query(query.id, vec![choose_debian_version.into()]).await?;
Ok(())
}
/// When it receives a callback from a button it edits the message with all
/// those buttons writing a text with the selected Debian version.
async fn callback_handler(
cx: UpdateWithCx<AutoSend<Bot>, CallbackQuery>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let UpdateWithCx { requester: bot, update: query } = cx;
if let Some(version) = query.data {
let text = format!("You chose: {}", version);
match query.message {
Some(Message { id, chat, .. }) => {
bot.edit_message_text(chat.id, id, text).await?;
}
None => {
if let Some(id) = query.inline_message_id {
bot.edit_message_text_inline(dbg!(id), text).await?;
}
}
}
log::info!("You chose: {}", version);
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
teloxide::enable_logging!();
log::info!("Starting bot...");
let bot = Bot::from_env().auto_send();
Dispatcher::new(bot)
.messages_handler(|rx: DispatcherHandlerRx<AutoSend<Bot>, Message>| {
UnboundedReceiverStream::new(rx).for_each_concurrent(None, |cx| async move {
message_handler(cx).await.log_on_error().await;
})
})
.callback_queries_handler(|rx: DispatcherHandlerRx<AutoSend<Bot>, CallbackQuery>| {
UnboundedReceiverStream::new(rx).for_each_concurrent(None, |cx| async move {
callback_handler(cx).await.log_on_error().await;
})
})
.inline_queries_handler(|rx: DispatcherHandlerRx<AutoSend<Bot>, InlineQuery>| {
UnboundedReceiverStream::new(rx).for_each_concurrent(None, |cx| async move {
inline_query_handler(cx).await.log_on_error().await;
})
})
.dispatch()
.await;
log::info!("Closing bot... Goodbye!");
Ok(())
}

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["frunk", "macros", "auto-send", "sqlite-storage"] }
teloxide = { path = "../../", features = ["frunk", "macros", "sqlite-storage"] }
anyhow = "1.0.52"
serde = "1"

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["auto-send"] }
teloxide = { path = "../../" }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["auto-send"] }
teloxide = { path = "../../" }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["macros", "auto-send"] }
teloxide = { path = "../../", features = ["macros"] }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }

View file

@ -33,7 +33,7 @@ async fn main() {
// While constructing them from the struct itself is possible, it is preferred
// to use the builder pattern if you wish to add more
// information to your result. Please refer to the documentation
// for more detailed information about each field. https://docs.rs/teloxide/0.5.1/teloxide/types/struct.InlineQueryResultArticle.html
// for more detailed information about each field. https://docs.rs/teloxide/latest/teloxide/types/struct.InlineQueryResultArticle.html
let ddg_search = InlineQueryResultArticle::new(
"02".to_string(),
"DuckDuckGo Search".to_string(),

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["auto-send"] }
teloxide = { path = "../../" }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }

View file

@ -6,7 +6,7 @@ edition = "2018"
[dependencies]
# You can also choose "cbor-serializer" or built-in JSON serializer
teloxide = { path = "../../", features = ["redis-storage", "bincode-serializer", "macros", "auto-send"] }
teloxide = { path = "../../", features = ["redis-storage", "bincode-serializer", "macros"] }
log = "0.4.8"
pretty_env_logger = "0.4.0"

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["auto-send"] }
teloxide = { path = "../../" }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }

View file

@ -7,7 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { path = "../../", features = ["macros", "auto-send"] }
teloxide = { path = "../../", features = ["macros"] }
log = "0.4.8"
pretty_env_logger = "0.4.0"
tokio = { version = "1.3.0", features = ["rt-multi-thread", "macros"] }

View file

@ -6,7 +6,7 @@ edition = "2018"
[dependencies]
# You can also choose "cbor-serializer" or built-in JSON serializer
teloxide = { path = "../../", features = ["sqlite-storage", "bincode-serializer", "redis-storage", "macros", "auto-send"] }
teloxide = { path = "../../", features = ["sqlite-storage", "bincode-serializer", "redis-storage", "macros"] }
log = "0.4.8"
pretty_env_logger = "0.4.0"

View file

@ -156,15 +156,17 @@ where
match this.senders.pin().get(&chat_id) {
// An old dialogue
Some(tx) => {
if tx.send(cx).is_err() {
panic!("We are not dropping a receiver or call .close() on it",);
}
assert!(
tx.send(cx).is_ok(),
"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",);
}
assert!(
tx.send(cx).is_ok(),
"We are not dropping a receiver or call .close() on it"
);
this.senders.pin().insert(chat_id, tx);
}
}
@ -271,9 +273,7 @@ mod tests {
let tx = tx.clone();
async move {
if tx.send(update).is_err() {
panic!("tx.send(update) failed");
}
assert!(tx.send(update).is_ok(), "tx.send(update) failed");
}
})
.await;

View file

@ -106,7 +106,7 @@ where
///
/// [`shutdown`]: ShutdownToken::shutdown
#[cfg(feature = "ctrlc_handler")]
#[cfg_attr(docsrs, doc(cfg(feature = "ctrlc_handler")))]
#[cfg_attr(all(docsrs, feature = "nightly"), doc(cfg(feature = "ctrlc_handler")))]
pub fn setup_ctrlc_handler(self) -> Self {
let state = Arc::clone(&self.state);
tokio::spawn(async move {

View file

@ -22,7 +22,6 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
///
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
/// [`Dispatcher`]: crate::dispatching::Dispatcher
#[cfg(feature = "ctrlc_handler")]
pub async fn commands_repl<R, Cmd, H, Fut, HandlerE, N>(requester: R, bot_name: N, handler: H)
where
Cmd: BotCommand + Send + 'static,
@ -57,7 +56,6 @@ where
/// [`Dispatcher`]: crate::dispatching::Dispatcher
/// [`commands_repl`]: crate::dispatching::repls::commands_repl()
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
#[cfg(feature = "ctrlc_handler")]
pub async fn commands_repl_with_listener<'a, R, Cmd, H, Fut, L, ListenerE, HandlerE, N>(
requester: R,
bot_name: N,

View file

@ -23,7 +23,6 @@ use teloxide_core::{requests::Requester, types::Message};
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
/// [`Dispatcher`]: crate::dispatching::Dispatcher
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
#[cfg(feature = "ctrlc_handler")]
pub async fn dialogues_repl<'a, R, H, D, Fut>(requester: R, handler: H)
where
H: Fn(UpdateWithCx<R, Message>, D) -> Fut + Send + Sync + 'static,
@ -56,7 +55,6 @@ where
/// [`dialogues_repl`]: crate::dispatching::repls::dialogues_repl()
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
/// [`InMemStorage`]: crate::dispatching::dialogue::InMemStorage
#[cfg(feature = "ctrlc_handler")]
pub async fn dialogues_repl_with_listener<'a, R, H, D, Fut, L, ListenerE>(
requester: R,
handler: H,

View file

@ -21,7 +21,6 @@ use tokio_stream::wrappers::UnboundedReceiverStream;
///
/// [REPL]: https://en.wikipedia.org/wiki/Read-eval-print_loop
/// [`Dispatcher`]: crate::dispatching::Dispatcher
#[cfg(feature = "ctrlc_handler")]
pub async fn repl<R, H, Fut, E>(requester: R, handler: H)
where
H: Fn(UpdateWithCx<R, Message>) -> Fut + Send + Sync + 'static,
@ -52,7 +51,6 @@ where
/// [`Dispatcher`]: crate::dispatching::Dispatcher
/// [`repl`]: crate::dispatching::repls::repl()
/// [`UpdateListener`]: crate::dispatching::update_listeners::UpdateListener
#[cfg(feature = "ctrlc_handler")]
pub async fn repl_with_listener<'a, R, H, Fut, E, L, ListenerE>(
requester: R,
handler: H,

View file

@ -188,7 +188,14 @@ pub trait UpdateListener<E>: for<'a> AsUpdateStream<'a, E> {
/// This trait is a workaround to not require GAT.
pub trait AsUpdateStream<'a, E> {
/// The stream of updates from Telegram.
type Stream: Stream<Item = Result<Update, E>> + 'a;
// HACK: There is currently no way to write something like
// `-> impl for<'a> AsUpdateStream<'a, E, Stream: Send>`. Since we return
// `impl UpdateListener<E>` from `polling`, we need to have `Send` bound here,
// to make the stream `Send`.
//
// Without this it's, for example, impossible to spawn a tokio task with
// teloxide polling.
type Stream: Stream<Item = Result<Update, E>> + Send + 'a;
/// Creates the update [`Stream`].
///

View file

@ -24,7 +24,7 @@ use crate::{
/// This function will automatically delete a webhook if it was set up.
pub async fn polling_default<R>(requester: R) -> impl UpdateListener<R::Err>
where
R: Requester + 'static,
R: Requester + Send + 'static,
<R as Requester>::GetUpdatesFaultTolerant: Send,
{
delete_webhook_if_setup(&requester).await;
@ -50,7 +50,7 @@ pub fn polling<R>(
allowed_updates: Option<Vec<AllowedUpdate>>,
) -> impl UpdateListener<R::Err>
where
R: Requester + 'static,
R: Requester + Send + 'static,
<R as Requester>::GetUpdatesFaultTolerant: Send,
{
struct State<B: Requester> {
@ -63,9 +63,10 @@ where
token: AsyncStopToken,
}
fn stream<B>(st: &mut State<B>) -> impl Stream<Item = Result<Update, B::Err>> + '_
fn stream<B>(st: &mut State<B>) -> impl Stream<Item = Result<Update, B::Err>> + Send + '_
where
B: Requester,
B: Requester + Send,
<B as Requester>::GetUpdatesFaultTolerant: Send,
{
stream::unfold(st, move |state| async move {
let State { timeout, limit, allowed_updates, bot, offset, flag, .. } = &mut *state;
@ -177,3 +178,16 @@ where
}
}
}
#[test]
fn polling_is_send() {
use crate::dispatching::update_listeners::AsUpdateStream;
let bot = crate::Bot::new("TOKEN");
let mut polling = polling(bot, None, None, None);
assert_send(&polling);
assert_send(&polling.as_stream());
fn assert_send(_: &impl Send) {}
}

View file

@ -79,7 +79,7 @@ impl<S, E>
Thfn<S>,
>
where
S: Stream<Item = Result<Update, E>> + Unpin + 'static,
S: Stream<Item = Result<Update, E>> + Unpin + Send + 'static,
{
/// Creates a new update listener from a stream of updates which ignores
/// stop signals.
@ -109,6 +109,7 @@ impl<'a, St, Assf, Sf, Hauf, Thf, Strm, E> AsUpdateStream<'a, E>
for StatefulListener<St, Assf, Hauf, Sf, Thf>
where
(St, Strm): 'a,
Strm: Send,
Assf: FnMut(&'a mut St) -> Strm,
Strm: Stream<Item = Result<Update, E>>,
{

View file

@ -10,8 +10,11 @@
| `native-tls` | Enables the [`native-tls`] TLS implementation (enabled by default). |
| `rustls` | Enables the [`rustls`] TLS implementation. |
| `ctrlc_handler` | Enables the [`Dispatcher::setup_ctrlc_handler`](dispatching::Dispatcher::setup_ctrlc_handler) function. |
| `auto-send` | Enables the `AutoSend` bot adaptor. |
| `cache-me` | Enables the `CacheMe` bot adaptor. |
| `auto-send` | Enables the [`AutoSend`](adaptors::AutoSend) bot adaptor. |
| `throttle` | Enables the [`Throttle`](adaptors::Throttle) bot adaptor. |
| `cache-me` | Enables the [`CacheMe`](adaptors::CacheMe) bot adaptor. |
| `trace-adaptor` | Enables the [`Trace`](adaptors::Trace) bot adaptor. |
| `erased` | Enables the [`ErasedRequester`](adaptors::ErasedRequester) bot adaptor. |
| `frunk` | Enables [`teloxide::utils::UpState`]. |
| `full` | Enables all the features except `nightly`. |
| `nightly` | Enables nightly-only features (see the [teloxide-core features]). |