mirror of
https://github.com/teloxide/teloxide.git
synced 2024-12-22 14:35:36 +01:00
Merge branch 'master' into fix_set_webhook_again
This commit is contained in:
commit
3d1cb9c665
24 changed files with 267 additions and 271 deletions
43
.github/workflows/ci.yml
vendored
43
.github/workflows/ci.yml
vendored
|
@ -17,17 +17,12 @@ env:
|
|||
CARGO_NET_RETRY: 10
|
||||
RUSTUP_MAX_RETRIES: 10
|
||||
|
||||
rust_nightly: nightly-2022-01-17
|
||||
rust_nightly: nightly-2022-09-23
|
||||
# When updating this, also update:
|
||||
# - README.md
|
||||
# - src/lib.rs
|
||||
# - down below in a matrix
|
||||
rust_msrv: 1.58.0
|
||||
# When updating this, also update:
|
||||
# - down below in a matrix
|
||||
#
|
||||
# This is needed because some of our tests can't run on MSRV.
|
||||
rust_msrv_dev: 1.59.0
|
||||
rust_msrv: 1.64.0
|
||||
|
||||
CI: 1
|
||||
|
||||
|
@ -43,7 +38,6 @@ jobs:
|
|||
- check-examples
|
||||
- clippy
|
||||
- doc
|
||||
- msrv
|
||||
|
||||
steps:
|
||||
- run: exit 0
|
||||
|
@ -82,7 +76,7 @@ jobs:
|
|||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
- msrv_dev
|
||||
- msrv
|
||||
|
||||
include:
|
||||
- rust: stable
|
||||
|
@ -92,10 +86,10 @@ jobs:
|
|||
toolchain: beta
|
||||
features: "--features full"
|
||||
- rust: nightly
|
||||
toolchain: nightly-2022-01-17
|
||||
toolchain: nightly-2022-09-23
|
||||
features: "--all-features"
|
||||
- rust: msrv_dev
|
||||
toolchain: 1.59.0
|
||||
- rust: msrv
|
||||
toolchain: 1.64.0
|
||||
features: "--features full"
|
||||
|
||||
steps:
|
||||
|
@ -108,6 +102,7 @@ jobs:
|
|||
profile: minimal
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
override: true
|
||||
components: rustfmt # required by codegen
|
||||
|
||||
- name: Cache Dependencies
|
||||
uses: Swatinem/rust-cache@v1
|
||||
|
@ -194,27 +189,3 @@ jobs:
|
|||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: docs # from .cargo/config.toml
|
||||
|
||||
msrv:
|
||||
name: minimal supported rust version
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Rust ${{ env.rust_msrv }}
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ env.rust_msrv }}
|
||||
override: true
|
||||
|
||||
- name: Cache Dependencies
|
||||
uses: Swatinem/rust-cache@v1
|
||||
|
||||
- name: Check
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
args: --verbose --features full
|
||||
|
|
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## unreleased
|
||||
|
||||
### Changed
|
||||
|
||||
- **You can now `.await` any `Request`!** ([#249][pr249])
|
||||
- `Request` now requires `Self: IntoFuture`
|
||||
- There is no need for `AutoSend` anymore
|
||||
- MSRV (Minimal Supported Rust Version) was bumped from `1.58.0` to `1.64.0`
|
||||
|
||||
### Removed
|
||||
|
||||
- Methods for creating `InlineQuery` ([#246][pr244])
|
||||
|
@ -19,6 +26,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
[pr250]: https://github.com/teloxide/teloxide-core/pull/250
|
||||
|
||||
### Deprecated
|
||||
|
||||
- `AutoSend` adaptor ([#249][pr249])
|
||||
|
||||
[pr249]: https://github.com/teloxide/teloxide-core/pull/249
|
||||
|
||||
## 0.7.1 - 2022-08-19
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -24,7 +24,7 @@ exclude = [
|
|||
futures = "0.3.5"
|
||||
tokio = { version = "1.12.0", features = ["fs"] }
|
||||
tokio-util = { version = "0.7.0", features = ["codec"] }
|
||||
pin-project = "1.0.3"
|
||||
pin-project = "1.0.12"
|
||||
bytes = "1.0.0"
|
||||
reqwest = { version = "0.11.10", features = ["json", "stream", "multipart"], default-features = false }
|
||||
url = { version = "2", features = ["serde"] }
|
||||
|
@ -99,8 +99,8 @@ cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"]
|
|||
|
||||
[[example]]
|
||||
name = "self_info"
|
||||
required-features = ["tokio/macros", "tokio/rt-multi-thread", "auto_send"]
|
||||
required-features = ["tokio/macros", "tokio/rt-multi-thread"]
|
||||
|
||||
[[example]]
|
||||
name = "erased"
|
||||
required-features = ["tokio/macros", "tokio/rt-multi-thread", "auto_send", "erased"]
|
||||
required-features = ["tokio/macros", "tokio/rt-multi-thread", "erased", "trace_adaptor"]
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
```toml
|
||||
teloxide-core = "0.7"
|
||||
```
|
||||
_Compiler support: requires rustc 1.58+_.
|
||||
_Compiler support: requires rustc 1.64+_.
|
||||
|
||||
[`teloxide`]: https://docs.rs/teloxide
|
||||
[Telegram Bot API]: https://core.telegram.org/bots/api
|
||||
|
|
|
@ -32,9 +32,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
log::info!("Trace settings: {:?}", trace_settings);
|
||||
|
||||
let bot = if trace_settings.is_empty() {
|
||||
Bot::from_env().erase().auto_send()
|
||||
Bot::from_env().erase()
|
||||
} else {
|
||||
Bot::from_env().trace(trace_settings).erase().auto_send()
|
||||
Bot::from_env().trace(trace_settings).erase()
|
||||
};
|
||||
|
||||
bot.send_chat_action(chat_id, ChatAction::Typing).await?;
|
||||
|
|
|
@ -13,9 +13,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.parse::<i64>()?,
|
||||
);
|
||||
|
||||
let bot = Bot::from_env()
|
||||
.parse_mode(ParseMode::MarkdownV2)
|
||||
.auto_send();
|
||||
let bot = Bot::from_env().parse_mode(ParseMode::MarkdownV2);
|
||||
|
||||
let Me { user: me, .. } = bot.get_me().await?;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2022-01-17"
|
||||
channel = "nightly-2022-09-23"
|
||||
components = ["rustfmt", "clippy"]
|
||||
profile = "minimal"
|
||||
|
|
|
@ -3,17 +3,18 @@
|
|||
//! Bot adaptors are very similar to the [`Iterator`] adaptors: they are bots
|
||||
//! wrapping other bots to alter existing or add new functionality.
|
||||
//!
|
||||
//! E.g. [`AutoSend`] allows `await`ing requests directly, no need to use
|
||||
//! `.send()`.
|
||||
//!
|
||||
//! [`Requester`]: crate::requests::Requester
|
||||
|
||||
/// [`AutoSend`] bot adaptor which allows sending a request without calling
|
||||
/// [`send`].
|
||||
/// [`AutoSend`] bot adaptor which used to allow sending a request without
|
||||
/// calling [`send`].
|
||||
///
|
||||
/// [`AutoSend`]: auto_send::AutoSend
|
||||
/// [`send`]: crate::requests::Request::send
|
||||
#[cfg(feature = "auto_send")]
|
||||
#[deprecated(
|
||||
since = "0.8.0",
|
||||
note = "`AutoSend` is no longer required to `.await` requests and is now noop"
|
||||
)]
|
||||
pub mod auto_send;
|
||||
|
||||
/// [`CacheMe`] bot adaptor which caches [`GetMe`] requests.
|
||||
|
@ -47,6 +48,7 @@ pub mod throttle;
|
|||
mod parse_mode;
|
||||
|
||||
#[cfg(feature = "auto_send")]
|
||||
#[allow(deprecated)]
|
||||
pub use auto_send::AutoSend;
|
||||
#[cfg(feature = "cache_me")]
|
||||
pub use cache_me::CacheMe;
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
use std::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use std::future::IntoFuture;
|
||||
|
||||
use futures::future::FusedFuture;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
|
@ -12,32 +7,16 @@ use crate::{
|
|||
types::*,
|
||||
};
|
||||
|
||||
/// Send requests automatically.
|
||||
/// Previously was used to send requests automatically.
|
||||
///
|
||||
/// Requests returned by `<AutoSend<_> as `[`Requester`]`>` are [`Future`]s
|
||||
/// which means that you can simply `.await` them instead of using
|
||||
/// `.send().await`.
|
||||
/// Before addition of [`IntoFuture`] you could only `.await` [`Future`]s.
|
||||
/// This adaptor turned requests into futures, allowing to `.await` them,
|
||||
/// without calling `.send()`.
|
||||
///
|
||||
/// Notes:
|
||||
/// 1. This wrapper should be the most outer i.e.: `AutoSend<CacheMe<Bot>>`
|
||||
/// will automatically send requests, while `CacheMe<AutoSend<Bot>>` - won't.
|
||||
/// 2. After first call to `poll` on a request you will be unable to access
|
||||
/// payload nor could you use [`send_ref`](Request::send_ref).
|
||||
/// Now, however, all requests are required to implement `IntoFuture`, allowing
|
||||
/// you to `.await` them directly. This adaptor is noop, and shouldn't be used.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use teloxide_core::{
|
||||
/// requests::{Requester, RequesterExt},
|
||||
/// types::Me,
|
||||
/// Bot,
|
||||
/// };
|
||||
///
|
||||
/// # async {
|
||||
/// let bot = Bot::new("TOKEN").auto_send();
|
||||
/// let myself: Me = bot.get_me().await?; // No .send()!
|
||||
/// # Ok::<_, teloxide_core::RequestError>(()) };
|
||||
/// ```
|
||||
/// [`Future`]: std::future::Future
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AutoSend<B> {
|
||||
bot: B,
|
||||
|
@ -192,33 +171,17 @@ download_forward! {
|
|||
}
|
||||
|
||||
#[must_use = "Futures are lazy and do nothing unless polled or awaited"]
|
||||
#[pin_project::pin_project]
|
||||
pub struct AutoRequest<R: Request>(#[pin] Inner<R>);
|
||||
pub struct AutoRequest<R>(R);
|
||||
|
||||
impl<R> AutoRequest<R>
|
||||
where
|
||||
R: Request,
|
||||
{
|
||||
pub fn new(inner: R) -> Self {
|
||||
Self(Inner::Request(inner))
|
||||
Self(inner)
|
||||
}
|
||||
}
|
||||
|
||||
/// Data of the `AutoRequest` used to not expose variants (I wish there were
|
||||
/// private enum variants).
|
||||
#[pin_project::pin_project(project = InnerProj, project_replace = InnerRepl)]
|
||||
enum Inner<R: Request> {
|
||||
/// An unsent modifiable request.
|
||||
Request(R),
|
||||
/// A sent request.
|
||||
Future(#[pin] R::Send),
|
||||
/// Done state. Set after `R::Send::poll` returned `Ready(_)`.
|
||||
///
|
||||
/// Also used as a temporary replacement to turn pinned `Request(req)`
|
||||
/// into `Future(req.send())` in `AutoRequest::poll`.
|
||||
Done,
|
||||
}
|
||||
|
||||
impl<R> Request for AutoRequest<R>
|
||||
where
|
||||
R: Request,
|
||||
|
@ -228,19 +191,20 @@ where
|
|||
type SendRef = R::SendRef;
|
||||
|
||||
fn send(self) -> Self::Send {
|
||||
match self.0 {
|
||||
Inner::Request(req) => req.send(),
|
||||
Inner::Future(fut) => fut,
|
||||
Inner::Done => done_unreachable(),
|
||||
}
|
||||
self.0.send()
|
||||
}
|
||||
|
||||
fn send_ref(&self) -> Self::SendRef {
|
||||
match &self.0 {
|
||||
Inner::Request(req) => req.send_ref(),
|
||||
Inner::Future(_) => already_polled(),
|
||||
Inner::Done => done_unreachable(),
|
||||
}
|
||||
self.0.send_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Request> IntoFuture for AutoRequest<R> {
|
||||
type Output = Result<Output<Self>, <Self as Request>::Err>;
|
||||
type IntoFuture = <Self as Request>::Send;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.send()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,75 +212,10 @@ impl<R: Request> HasPayload for AutoRequest<R> {
|
|||
type Payload = R::Payload;
|
||||
|
||||
fn payload_mut(&mut self) -> &mut Self::Payload {
|
||||
match &mut self.0 {
|
||||
Inner::Request(req) => req.payload_mut(),
|
||||
Inner::Future(_) => already_polled(),
|
||||
Inner::Done => done_unreachable(),
|
||||
}
|
||||
self.0.payload_mut()
|
||||
}
|
||||
|
||||
fn payload_ref(&self) -> &Self::Payload {
|
||||
match &self.0 {
|
||||
Inner::Request(req) => req.payload_ref(),
|
||||
Inner::Future(_) => already_polled(),
|
||||
Inner::Done => done_unreachable(),
|
||||
}
|
||||
self.0.payload_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Request> Future for AutoRequest<R> {
|
||||
type Output = Result<Output<R>, R::Err>;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let mut this: Pin<&mut Inner<_>> = self.as_mut().project().0;
|
||||
|
||||
match this.as_mut().project() {
|
||||
// Poll the underling future.
|
||||
InnerProj::Future(fut) => {
|
||||
let res = futures::ready!(fut.poll(cx));
|
||||
// We've got the result, so we set the state to done.
|
||||
this.set(Inner::Done);
|
||||
Poll::Ready(res)
|
||||
}
|
||||
|
||||
// This future is fused.
|
||||
InnerProj::Done => Poll::Pending,
|
||||
// The `AutoRequest` future was polled for the first time after
|
||||
// creation. We need to transform it into sent form by calling
|
||||
// `R::send` and doing some magic around Pin.
|
||||
InnerProj::Request(_) => {
|
||||
// Replace `Request(_)` by `Done(_)` to obtain ownership over
|
||||
// the former.
|
||||
let inner = this.as_mut().project_replace(Inner::Done);
|
||||
// Map Request(req) to `Future(req.send())`.
|
||||
let inner = match inner {
|
||||
InnerRepl::Request(req) => Inner::Future(req.send()),
|
||||
// Practically this is unreachable, because we've just checked for
|
||||
// both `Future(_)` and `Done` variants.
|
||||
InnerRepl::Future(_) | InnerRepl::Done => done_unreachable(),
|
||||
};
|
||||
// Set the resulting `Future(_)` back to pin.
|
||||
this.set(inner);
|
||||
|
||||
// Poll `self`. This time another brunch will be executed, returning `Poll`.
|
||||
self.poll(cx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Request> FusedFuture for AutoRequest<R> {
|
||||
fn is_terminated(&self) -> bool {
|
||||
matches!(&self.0, Inner::Done)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn done_unreachable() -> ! {
|
||||
unreachable!("future is completed and as such doesn't provide any functionality")
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn already_polled() -> ! {
|
||||
panic!("AutoRequest was already polled once")
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{pin::Pin, sync::Arc};
|
||||
use std::{future::IntoFuture, pin::Pin, sync::Arc};
|
||||
|
||||
use futures::{
|
||||
future,
|
||||
|
@ -244,6 +244,15 @@ impl<R: Request<Payload = GetMe>> HasPayload for CachedMeRequest<R> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<R: Request<Payload = GetMe>> IntoFuture for CachedMeRequest<R> {
|
||||
type Output = Result<Me, R::Err>;
|
||||
type IntoFuture = Send<R>;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.send()
|
||||
}
|
||||
}
|
||||
|
||||
type ReadyMe<Err> = Ready<Result<Me, Err>>;
|
||||
|
||||
#[pin_project::pin_project]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Arc;
|
||||
use std::{future::IntoFuture, sync::Arc};
|
||||
|
||||
use futures::{future::BoxFuture, FutureExt};
|
||||
use reqwest::Url;
|
||||
|
@ -51,7 +51,8 @@ pub struct ErasedRequest<'a, T, E> {
|
|||
inner: Box<dyn ErasableRequest<'a, Payload = T, Err = E> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a, T, E> ErasedRequest<'a, T, E> {
|
||||
// `T: Payload` required b/c of <https://github.com/rust-lang/rust/issues/102185>
|
||||
impl<'a, T: Payload, E> ErasedRequest<'a, T, E> {
|
||||
pub(crate) fn erase(request: impl Request<Payload = T, Err = E> + 'a) -> Self {
|
||||
Self {
|
||||
inner: Box::new(request),
|
||||
|
@ -94,6 +95,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T, E> IntoFuture for ErasedRequest<'a, T, E>
|
||||
where
|
||||
T: Payload,
|
||||
E: std::error::Error + Send,
|
||||
{
|
||||
type Output = Result<Output<Self>, <Self as Request>::Err>;
|
||||
type IntoFuture = <Self as Request>::Send;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.send()
|
||||
}
|
||||
}
|
||||
|
||||
/// Object safe version of [`Request`].
|
||||
///
|
||||
/// TODO(waffle): make [`Request`] object safe and remove this trait (this is a
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::{future::Future, pin::Pin, sync::Arc, time::Instant};
|
||||
use std::{
|
||||
future::{Future, IntoFuture},
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use futures::{
|
||||
future::BoxFuture,
|
||||
|
@ -74,6 +79,20 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> IntoFuture for ThrottlingRequest<R>
|
||||
where
|
||||
R: Request + Clone + Send + Sync + 'static,
|
||||
R::Err: AsResponseParameters + Send,
|
||||
Output<R>: Send,
|
||||
{
|
||||
type Output = Result<Output<Self>, <Self as Request>::Err>;
|
||||
type IntoFuture = <Self as Request>::Send;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.send()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Request> Future for ThrottlingSend<R>
|
||||
where
|
||||
R::Err: AsResponseParameters,
|
||||
|
@ -159,7 +178,7 @@ where
|
|||
|
||||
let res = match &mut request {
|
||||
ShareableRequest::Shared(shared) => shared.send_ref().await,
|
||||
ShareableRequest::Owned(owned) => owned.take().unwrap().send().await,
|
||||
ShareableRequest::Owned(owned) => owned.take().unwrap().await,
|
||||
};
|
||||
|
||||
return res;
|
||||
|
@ -178,7 +197,7 @@ where
|
|||
request.send_ref().await
|
||||
}
|
||||
(false, ShareableRequest::Shared(shared)) => shared.send_ref().await,
|
||||
(false, ShareableRequest::Owned(owned)) => owned.take().unwrap().send().await,
|
||||
(false, ShareableRequest::Owned(owned)) => owned.take().unwrap().await,
|
||||
};
|
||||
|
||||
let retry_after = res.as_ref().err().and_then(<_>::retry_after);
|
||||
|
|
|
@ -9,7 +9,7 @@ use vecrem::VecExt;
|
|||
use crate::{
|
||||
adaptors::throttle::{request_lock::RequestLock, ChatIdHash, Limits, Settings},
|
||||
errors::AsResponseParameters,
|
||||
requests::{Request, Requester},
|
||||
requests::Requester,
|
||||
};
|
||||
|
||||
const MINUTE: Duration = Duration::from_secs(60);
|
||||
|
@ -321,7 +321,7 @@ async fn freeze(
|
|||
// TODO: maybe not call `get_chat` every time?
|
||||
|
||||
// At this point there isn't much we can do with the error besides ignoring
|
||||
if let Ok(chat) = bot.get_chat(id).send().await {
|
||||
if let Ok(chat) = bot.get_chat(id).await {
|
||||
match chat.slow_mode_delay() {
|
||||
Some(delay) => {
|
||||
let now = Instant::now();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
future::{Future, IntoFuture},
|
||||
pin::Pin,
|
||||
task::{self, Poll},
|
||||
};
|
||||
|
@ -309,6 +309,21 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<R> IntoFuture for TraceRequest<R>
|
||||
where
|
||||
R: Request,
|
||||
Output<R>: Debug,
|
||||
R::Err: Debug,
|
||||
R::Payload: Debug,
|
||||
{
|
||||
type Output = Result<Output<Self>, <Self as Request>::Err>;
|
||||
type IntoFuture = <Self as Request>::Send;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.send()
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project::pin_project]
|
||||
pub struct Send<F>
|
||||
where
|
||||
|
|
|
@ -29,7 +29,7 @@ const TELOXIDE_TOKEN: &str = "TELOXIDE_TOKEN";
|
|||
/// use teloxide_core::prelude::*;
|
||||
///
|
||||
/// let bot = Bot::new("TOKEN");
|
||||
/// dbg!(bot.get_me().send().await?);
|
||||
/// dbg!(bot.get_me().await?);
|
||||
/// # Ok::<_, teloxide_core::RequestError>(()) };
|
||||
/// ```
|
||||
///
|
||||
|
@ -158,7 +158,7 @@ impl Bot {
|
|||
/// let url = reqwest::Url::parse("https://localhost/tbas").unwrap();
|
||||
/// let bot = Bot::new("TOKEN").set_api_url(url);
|
||||
/// // From now all methods will use "https://localhost/tbas" as an API URL.
|
||||
/// bot.get_me().send().await
|
||||
/// bot.get_me().await
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
|
|
|
@ -23,7 +23,7 @@ use xshell::{cmd, Shell};
|
|||
|
||||
fn ensure_rustfmt(sh: &Shell) {
|
||||
// FIXME(waffle): find a better way to set toolchain
|
||||
let toolchain = "nightly-2022-01-17";
|
||||
let toolchain = "nightly-2022-09-23";
|
||||
|
||||
let version = cmd!(sh, "rustup run {toolchain} rustfmt --version")
|
||||
.read()
|
||||
|
@ -38,7 +38,7 @@ fn ensure_rustfmt(sh: &Shell) {
|
|||
}
|
||||
|
||||
pub fn reformat(text: String) -> String {
|
||||
let toolchain = "nightly-2022-01-17";
|
||||
let toolchain = "nightly-2022-09-23";
|
||||
|
||||
let sh = Shell::new().unwrap();
|
||||
ensure_rustfmt(&sh);
|
||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -7,10 +7,9 @@
|
|||
//!```toml
|
||||
//! teloxide_core = "0.7"
|
||||
//! ```
|
||||
//! _Compiler support: requires rustc 1.58+_.
|
||||
//! _Compiler support: requires rustc 1.64+_.
|
||||
//!
|
||||
//! ```
|
||||
//! # #[cfg(feature = "auto_send")]
|
||||
//! # async {
|
||||
//! # let chat_id = teloxide_core::types::ChatId(-1);
|
||||
//! use teloxide_core::{
|
||||
|
@ -18,9 +17,7 @@
|
|||
//! types::{DiceEmoji, ParseMode},
|
||||
//! };
|
||||
//!
|
||||
//! let bot = Bot::from_env()
|
||||
//! .parse_mode(ParseMode::MarkdownV2)
|
||||
//! .auto_send();
|
||||
//! let bot = Bot::from_env().parse_mode(ParseMode::MarkdownV2);
|
||||
//!
|
||||
//! let me = bot.get_me().await?;
|
||||
//!
|
||||
|
@ -46,7 +43,6 @@
|
|||
//! - `native-tls` = use [`native-tls`] tls implementation (**enabled by
|
||||
//! default**)
|
||||
//! - `rustls` — use [`rustls`] tls implementation
|
||||
//! - `auto_send` — enables [`AutoSend`] bot adaptor
|
||||
//! - `trace_adaptor` — enables [`Trace`] bot adaptor
|
||||
//! - `erased` — enables [`ErasedRequester`] bot adaptor
|
||||
//! - `throttle` — enables [`Throttle`] bot adaptor
|
||||
|
@ -55,6 +51,7 @@
|
|||
//! - `nightly` — enables nightly-only features, currently:
|
||||
//! - Removes some future boxing using `#![feature(type_alias_impl_trait)]`
|
||||
//! - Used to built docs (`#![feature(doc_cfg, doc_notable_trait)]`)
|
||||
//! - `auto_send` — enables [`AutoSend`] bot adaptor (deprecated)
|
||||
//!
|
||||
//! [`AutoSend`]: adaptors::AutoSend
|
||||
//! [`Trace`]: adaptors::Trace
|
||||
|
@ -93,6 +90,13 @@
|
|||
#![allow(clippy::return_self_not_must_use)]
|
||||
// Workaround for CI
|
||||
#![allow(rustdoc::bare_urls)]
|
||||
// FIXME: deal with these lints
|
||||
#![allow(
|
||||
clippy::collapsible_str_replace,
|
||||
clippy::borrow_deref_ref,
|
||||
clippy::unnecessary_lazy_evaluations,
|
||||
clippy::derive_partial_eq_without_eq
|
||||
)]
|
||||
|
||||
// The internal helper macros.
|
||||
#[macro_use]
|
||||
|
|
|
@ -42,7 +42,7 @@ pub trait Download<'w>
|
|||
/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let bot = Bot::new("TOKEN");
|
||||
///
|
||||
/// let TgFile { file_path, .. } = bot.get_file("*file_id*").send().await?;
|
||||
/// let TgFile { file_path, .. } = bot.get_file("*file_id*").await?;
|
||||
/// let mut file = File::create("/tmp/test.png").await?;
|
||||
/// bot.download_file(&file_path, &mut file).await?;
|
||||
/// # Ok(()) }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::future::IntoFuture;
|
||||
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
use crate::{
|
||||
|
@ -49,6 +51,20 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<P> IntoFuture for JsonRequest<P>
|
||||
where
|
||||
P: 'static,
|
||||
P: Payload + Serialize,
|
||||
P::Output: DeserializeOwned,
|
||||
{
|
||||
type Output = Result<P::Output, RequestError>;
|
||||
type IntoFuture = <Self as Request>::Send;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.send()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> HasPayload for JsonRequest<P>
|
||||
where
|
||||
P: Payload,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::future::IntoFuture;
|
||||
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
use crate::{
|
||||
|
@ -50,6 +52,20 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<P> IntoFuture for MultipartRequest<P>
|
||||
where
|
||||
P: 'static,
|
||||
P: Payload + MultipartPayload + Serialize,
|
||||
P::Output: DeserializeOwned,
|
||||
{
|
||||
type Output = Result<P::Output, RequestError>;
|
||||
type IntoFuture = <Self as Request>::Send;
|
||||
|
||||
fn into_future(self) -> Self::IntoFuture {
|
||||
self.send()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> HasPayload for MultipartRequest<P>
|
||||
where
|
||||
P: Payload,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::future::Future;
|
||||
use std::future::{Future, IntoFuture};
|
||||
|
||||
use either::Either;
|
||||
use futures::future;
|
||||
// use either::Either;
|
||||
// use futures::future;
|
||||
|
||||
use crate::requests::{HasPayload, Output};
|
||||
|
||||
|
@ -20,12 +20,11 @@ use crate::requests::{HasPayload, Output};
|
|||
///
|
||||
/// [`Throttle<B>`]: crate::adaptors::Throttle
|
||||
#[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))]
|
||||
pub trait Request: HasPayload {
|
||||
/*
|
||||
* Could be mostly `core::future::IntoFuture` though there is no reason to
|
||||
* use it before it's integrated in async/await
|
||||
*/
|
||||
|
||||
pub trait Request
|
||||
where
|
||||
Self: HasPayload,
|
||||
Self: IntoFuture<Output = Result<Output<Self>, Self::Err>, IntoFuture = Self::Send>,
|
||||
{
|
||||
/// The type of an error that may happen while sending a request to
|
||||
/// Telegram.
|
||||
type Err: std::error::Error + Send;
|
||||
|
@ -42,6 +41,7 @@ pub trait Request: HasPayload {
|
|||
/// Send this request.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```
|
||||
/// # async {
|
||||
/// use teloxide_core::{
|
||||
|
@ -56,7 +56,11 @@ pub trait Request: HasPayload {
|
|||
/// // Note: it's recommended to `Requester` instead of creating requests directly
|
||||
/// let method = GetMe::new();
|
||||
/// let request = JsonRequest::new(bot, method);
|
||||
/// let request_clone = request.clone();
|
||||
/// let _: Me = request.send().await.unwrap();
|
||||
///
|
||||
/// // You can also just await requests, without calling `send`:
|
||||
/// let _: Me = request_clone.await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
#[must_use = "Futures are lazy and do nothing unless polled or awaited"]
|
||||
|
@ -73,6 +77,7 @@ pub trait Request: HasPayload {
|
|||
/// and then serializing it, this method should just serialize the data.)
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```
|
||||
/// # async {
|
||||
/// use teloxide_core::{prelude::*, requests::Request, types::ChatId, Bot};
|
||||
|
@ -99,27 +104,30 @@ pub trait Request: HasPayload {
|
|||
}
|
||||
}
|
||||
|
||||
impl<L, R> Request for Either<L, R>
|
||||
where
|
||||
L: Request,
|
||||
R: Request<Payload = L::Payload, Err = L::Err>,
|
||||
{
|
||||
type Err = L::Err;
|
||||
// FIXME: re-introduce `Either` impls once `Either: IntoFuture` (or make out own
|
||||
// `Either`) (same for `Requester`)
|
||||
|
||||
type Send = future::Either<L::Send, R::Send>;
|
||||
// impl<L, R> Request for Either<L, R>
|
||||
// where
|
||||
// L: Request,
|
||||
// R: Request<Payload = L::Payload, Err = L::Err>,
|
||||
// {
|
||||
// type Err = L::Err;
|
||||
|
||||
type SendRef = future::Either<L::SendRef, R::SendRef>;
|
||||
// type Send = future::Either<L::Send, R::Send>;
|
||||
|
||||
fn send(self) -> Self::Send {
|
||||
self.map_left(<_>::send)
|
||||
.map_right(<_>::send)
|
||||
.either(future::Either::Left, future::Either::Right)
|
||||
}
|
||||
// type SendRef = future::Either<L::SendRef, R::SendRef>;
|
||||
|
||||
fn send_ref(&self) -> Self::SendRef {
|
||||
self.as_ref()
|
||||
.map_left(<_>::send_ref)
|
||||
.map_right(<_>::send_ref)
|
||||
.either(future::Either::Left, future::Either::Right)
|
||||
}
|
||||
}
|
||||
// fn send(self) -> Self::Send {
|
||||
// self.map_left(<_>::send)
|
||||
// .map_right(<_>::send)
|
||||
// .either(future::Either::Left, future::Either::Right)
|
||||
// }
|
||||
|
||||
// fn send_ref(&self) -> Self::SendRef {
|
||||
// self.as_ref()
|
||||
// .map_left(<_>::send_ref)
|
||||
// .map_right(<_>::send_ref)
|
||||
// .either(future::Either::Left, future::Either::Right)
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -32,8 +32,7 @@ use crate::{
|
|||
/// bot.send_message(chat_id, "<b>Text</b>")
|
||||
/// // Optional parameters can be supplied by calling setters
|
||||
/// .parse_mode(ParseMode::Html)
|
||||
/// // To send request to telegram you need to call `.send()` and await the resulting future
|
||||
/// .send()
|
||||
/// // To send request to telegram you need to `.await` the request
|
||||
/// .await?;
|
||||
/// # Ok::<_, teloxide_core::RequestError>(())
|
||||
/// # };
|
||||
|
@ -51,7 +50,7 @@ use crate::{
|
|||
/// where
|
||||
/// R: Requester,
|
||||
/// {
|
||||
/// bot.send_message(chat, "hi").send().await.expect("error")
|
||||
/// bot.send_message(chat, "hi").await.expect("error")
|
||||
/// }
|
||||
/// ```
|
||||
#[cfg_attr(all(any(docsrs, dep_docsrs), feature = "nightly"), doc(notable_trait))]
|
||||
|
@ -1090,30 +1089,30 @@ where
|
|||
forward_all! {}
|
||||
}
|
||||
|
||||
macro_rules! fty_either {
|
||||
($T:ident) => {
|
||||
either::Either<LR::$T, RR::$T>
|
||||
};
|
||||
}
|
||||
// macro_rules! fty_either {
|
||||
// ($T:ident) => {
|
||||
// either::Either<LR::$T, RR::$T>
|
||||
// };
|
||||
// }
|
||||
|
||||
macro_rules! fwd_either {
|
||||
($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
|
||||
match ($this) {
|
||||
either::Either::Left(l) => either::Either::Left(l.$m($($arg),*)),
|
||||
either::Either::Right(r) => either::Either::Right(r.$m($($arg),*)),
|
||||
}
|
||||
};
|
||||
}
|
||||
// macro_rules! fwd_either {
|
||||
// ($m:ident $this:ident ($($arg:ident : $T:ty),*)) => {
|
||||
// match ($this) {
|
||||
// either::Either::Left(l) => either::Either::Left(l.$m($($arg),*)),
|
||||
// either::Either::Right(r) =>
|
||||
// either::Either::Right(r.$m($($arg),*)), }
|
||||
// };
|
||||
// }
|
||||
|
||||
impl<LR, RR> Requester for either::Either<LR, RR>
|
||||
where
|
||||
LR: Requester,
|
||||
RR: Requester<Err = LR::Err>,
|
||||
{
|
||||
type Err = LR::Err;
|
||||
// impl<LR, RR> Requester for either::Either<LR, RR>
|
||||
// where
|
||||
// LR: Requester,
|
||||
// RR: Requester<Err = LR::Err>,
|
||||
// {
|
||||
// type Err = LR::Err;
|
||||
|
||||
forward_all! { fwd_either, fty_either }
|
||||
}
|
||||
// forward_all! { fwd_either, fty_either }
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn codegen_requester_methods() {
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::{adaptors::DefaultParseMode, requests::Requester, types::ParseMode};
|
|||
use crate::adaptors::CacheMe;
|
||||
|
||||
#[cfg(feature = "auto_send")]
|
||||
#[allow(deprecated)]
|
||||
use crate::adaptors::AutoSend;
|
||||
|
||||
#[cfg(feature = "erased")]
|
||||
|
@ -28,6 +29,11 @@ pub trait RequesterExt: Requester {
|
|||
|
||||
/// Send requests automatically, see [`AutoSend`] for more.
|
||||
#[cfg(feature = "auto_send")]
|
||||
#[deprecated(
|
||||
since = "0.8.0",
|
||||
note = "`AutoSend` is no longer required to `.await` requests and is now noop"
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
fn auto_send(self) -> AutoSend<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
|
|
|
@ -17,26 +17,8 @@ pub struct KeyboardButton {
|
|||
|
||||
/// Request something from user. This is available in private chats only.
|
||||
///
|
||||
/// - If `Some(Contact)`, the user's phone number will be sent as a contact
|
||||
/// when the button is pressed.
|
||||
/// - If `Some(Location)`, the user's current location will be sent when the
|
||||
/// button is pressed.
|
||||
/// - If `Some(Poll(_))`, the user will be asked to create a poll and send
|
||||
/// it to the bot when the button is pressed.
|
||||
/// - If `Some(WebApp(_))`, the described Web App will be launched when the
|
||||
/// button is pressed. The Web App will be able to send a “web_app_data”
|
||||
/// service message.
|
||||
///
|
||||
/// **Note:** `Contact` and `Location` options will only work in Telegram
|
||||
/// versions released after 9 April, 2016. Older clients will display
|
||||
/// unsupported message.
|
||||
///
|
||||
/// **Note:** `Poll(_)` option will only work in Telegram versions released
|
||||
/// after 23 January, 2020. Older clients will display unsupported message.
|
||||
///
|
||||
/// **Note:** `WebApp(_)` option will only work in Telegram versions
|
||||
/// released after 16 April, 2022. Older clients will display unsupported
|
||||
/// message.
|
||||
/// See [`ButtonRequest`] documentation for options on what can be
|
||||
/// requested.
|
||||
#[serde(flatten)]
|
||||
pub request: Option<ButtonRequest>,
|
||||
}
|
||||
|
@ -61,13 +43,38 @@ impl KeyboardButton {
|
|||
}
|
||||
}
|
||||
|
||||
// Serialize + Deserialize are implemented by hand
|
||||
// FIXME: add documentation
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
/// Request something from user, when a button is pressed.
|
||||
///
|
||||
/// See individual variants documentation for more info.
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq /*, Serialize, Deserialize */)]
|
||||
pub enum ButtonRequest {
|
||||
/// If this variant is used, the user's current location will be sent when
|
||||
/// the button is pressed.
|
||||
///
|
||||
/// **Note:** this option will only work in Telegram versions released after
|
||||
/// 9 April, 2016. Older clients will display unsupported message.
|
||||
Location,
|
||||
|
||||
/// If this variant is used, the user's phone number will be sent as a
|
||||
/// contact when the button is pressed.
|
||||
///
|
||||
/// **Note:** this option will only work in Telegram versions released after
|
||||
/// 9 April, 2016. Older clients will display unsupported message.
|
||||
Contact,
|
||||
|
||||
/// If this variant is used, the user will be asked to create a poll and
|
||||
/// send it to the bot when the button is pressed.
|
||||
///
|
||||
/// **Note:** this option will only work in Telegram versions released after
|
||||
/// 23 January, 2020. Older clients will display unsupported message.
|
||||
Poll(KeyboardButtonPollType),
|
||||
|
||||
/// If this variant is used, the described Web App will be launched when the
|
||||
/// button is pressed. The Web App will be able to send a “web_app_data”
|
||||
/// service message.
|
||||
///
|
||||
/// **Note:** this option will only work in Telegram versions released after
|
||||
/// 16 April, 2022. Older clients will display unsupported message.
|
||||
WebApp(WebAppInfo),
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue