diff --git a/README.md b/README.md index e6ad7315..0e01f9b1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,30 @@ +
+ +
+ # teloxide-core [![CI status](https://github.com/teloxide/teloxide-core/workflows/Continuous%20integration/badge.svg)](https://github.com/teloxide/teloxide-core/actions) +[![documentation](https://docs.rs/teloxide_core/badge.svg)](https://docs.rs/teloxide_core/) [![documentation (master)](https://img.shields.io/badge/docs-master-blue)](https://teloxide-core.netlify.com) [![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Api Cov](https://img.shields.io/badge/API%20coverage-Up%20to%200.4.9%20(inclusively)-green.svg)](https://core.telegram.org/bots/api) +[![crates.io](https://img.shields.io/crates/v/teloxide_core.svg)](https://crates.io/crates/teloxide_core) +[![Official Chat](https://img.shields.io/badge/official%20chat-t.me%2Fteloxide-blueviolet)](https://t.me/teloxide) -Core part of `teloxide` library. + + +Core part of the [`teloxide`] library. + +This library provides tools for making requests to the [Telegram Bot API] +(Currently, version `4.9` is supported) with ease. The library is fully +asynchronouns and built using [`tokio`]. + +```toml +teloxide_core = "0.1" +``` +_Compiler support: requires rustc 1.49+_ + +[`teloxide`]: https://docs.rs/teloxide +[Telegram Bot API]: https://core.telegram.org/bots/api +[`tokio`]: https://tokio.rs \ No newline at end of file diff --git a/src/adaptors.rs b/src/adaptors.rs index 1a308c57..8692d43c 100644 --- a/src/adaptors.rs +++ b/src/adaptors.rs @@ -8,12 +8,27 @@ //! //! [`Requester`]: crate::requests::Requester +/// [`AutoSend`] bot adaptor which allows sending a request without calling +/// [`send`]. +/// +/// [`AutoSend`]: auto_send::AutoSend +/// [`send`]: crate::requests::Request::send #[cfg(feature = "auto_send")] #[cfg_attr(all(docsrs, feature = "nightly"), doc(cfg(feature = "auto_send")))] pub mod auto_send; + +/// [`CacheMe`] bot adaptor which caches [`GetMe`] requests. +/// +/// [`CacheMe`]: cache_me::CacheMe +/// [`GetMe`]: crate::payloads::GetMe #[cfg(feature = "cache_me")] #[cfg_attr(all(docsrs, feature = "nightly"), doc(cfg(feature = "cache_me")))] pub mod cache_me; + +/// [`Throttle`] bot adaptor which allows automatically throttle when hitting +/// API limits. +/// +/// [`Throttle`]: throttle::Throttle #[cfg(feature = "throttle")] #[cfg_attr(all(docsrs, feature = "nightly"), doc(cfg(feature = "throttle")))] pub mod throttle; diff --git a/src/adaptors/auto_send.rs b/src/adaptors/auto_send.rs index 890979ac..77ce8e25 100644 --- a/src/adaptors/auto_send.rs +++ b/src/adaptors/auto_send.rs @@ -20,8 +20,8 @@ use crate::{ /// Notes: /// 1. This wrapper should be the most outer i.e.: `AutoSend>` /// will automatically send requests, while `CacheMe>` - won't. -/// 2. After first call to `poll` on a request you will unable to access payload -/// nor could you use [`send_ref`](Request::send_ref). +/// 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). /// /// ## Examples /// @@ -74,7 +74,10 @@ macro_rules! fty { }; } -impl Requester for AutoSend { +impl Requester for AutoSend +where + B: Requester, +{ type Err = B::Err; requester_forward! { @@ -112,7 +115,10 @@ download_forward! { #[pin_project::pin_project] pub struct AutoRequest(#[pin] Inner); -impl AutoRequest { +impl AutoRequest +where + R: Request, +{ pub fn new(inner: R) -> Self { Self(Inner::Request(inner)) } @@ -133,7 +139,10 @@ enum Inner { Done, } -impl Request for AutoRequest { +impl Request for AutoRequest +where + R: Request, +{ type Err = R::Err; type Send = R::Send; type SendRef = R::SendRef; diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 07c78829..06f6cea6 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -22,9 +22,41 @@ pub(crate) const TELOXIDE_PROXY: &str = "TELOXIDE_PROXY"; /// A requests sender. /// -/// No need to put it into [`Arc`], because it's already in. +/// This is the main type of the library, it allows to send requests to the +/// [Telegram Bot API] and download files. +/// +/// ## TBA methods +/// +/// All TBA methods are located in the [`Requester`] [`impl for Bot`]. This +/// allows for opt-in behaviours using requester [adaptors]. +/// +/// ``` +/// # async { +/// use teloxide_core::prelude::*; +/// +/// let bot = Bot::new("TOKEN"); +/// dbg!(bot.get_me().send().await?); +/// # Ok::<_, teloxide_core::RequestError>(()) }; +/// ``` +/// +/// [`Requester`]: crate::requests::Requester +/// [`impl for Bot`]: Bot#impl-Requester +/// [adaptors]: crate::adaptors +/// +/// ## File download +/// +/// In the similar way as with TBA methods, file downloading methods are located +/// in a trait — [`Download<'_>`]. See its documentation for more. +/// +/// [`Download<'_>`]: crate::net::Download +/// +/// ## Clone cost +/// +/// `Bot::clone` is relatively cheap, so if you need to share `Bot`, it's +/// recommended to clone it, instead of wrapping it in [`Arc<_>`]. /// /// [`Arc`]: std::sync::Arc +/// [Telegram Bot API]: https://core.telegram.org/bots/api #[derive(Debug, Clone)] pub struct Bot { token: Arc, @@ -32,6 +64,7 @@ pub struct Bot { client: Client, } +/// Constructors impl Bot { /// Creates a new `Bot` with the specified token and the default /// [http-client](reqwest::Client). @@ -81,7 +114,7 @@ impl Bot { /// [`reqwest::Client`]: https://docs.rs/reqwest/0.10.1/reqwest/struct.Client.html /// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all pub fn from_env() -> Self { - Self::from_env_with_client(crate::client_from_env()) + Self::from_env_with_client(crate::net::client_from_env()) } /// Creates a new `Bot` with the `TELOXIDE_TOKEN` environmental variable (a @@ -122,11 +155,31 @@ impl Bot { /// bot.get_me().send().await /// # }; /// ``` + /// + /// ## Multi-instance behaviour + /// + /// This method only sets the url for one bot instace, older clones are + /// unaffected. + /// + /// ``` + /// use teloxide_core::Bot; + /// + /// let bot = Bot::new("TOKEN"); + /// let bot2 = bot.clone(); + /// let bot = bot.set_api_url(reqwest::Url::parse("https://example.com/").unwrap()); + /// + /// assert_eq!(bot.api_url().as_str(), "https://example.com/"); + /// assert_eq!(bot.clone().api_url().as_str(), "https://example.com/"); + /// assert_ne!(bot2.api_url().as_str(), "https://example.com/"); + /// ``` pub fn set_api_url(mut self, url: reqwest::Url) -> Self { self.api_url = ApiUrl::Custom(Arc::new(url)); self } +} +/// Getters +impl Bot { /// Returns currently used token. pub fn token(&self) -> &str { &self.token diff --git a/src/errors.rs b/src/errors.rs index 3476ceed..4efcae04 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -53,7 +53,7 @@ pub enum RequestError { #[error("An error while parsing JSON: {0}")] InvalidJson(#[source] serde_json::Error), - // Occurs when trying to send a file to Telegram. + /// Occurs when trying to send a file to Telegram. #[error("An I/O error: {0}")] Io(#[source] io::Error), } diff --git a/src/lib.rs b/src/lib.rs index 79f43df4..797c36a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,69 @@ -//! Core part of `teloxide` library. -// TODO: expand docs +//! Core part of the [`teloxide`] library. +//! +//! This library provides tools for making requests to the [Telegram Bot API] +//! (Currently, version `4.9` is supported) with ease. The library is fully +//! asynchronouns and built using [`tokio`]. +//! +//!```toml +//! teloxide_core = "0.1" +//! ``` +//! _Compiler support: requires rustc 1.49+_ +//! +//! ``` +//! # #[cfg(feature = "auto_send")] +//! # async { +//! # let chat_id = 0; +//! use teloxide_core::{ +//! prelude::*, +//! types::{DiceEmoji, ParseMode}, +//! }; +//! +//! let bot = Bot::from_env() +//! .parse_mode(ParseMode::MarkdownV2) +//! .auto_send(); +//! +//! let me = bot.get_me().await?; +//! +//! bot.send_dice(chat_id, DiceEmoji::Dice).await?; +//! bot.send_message(chat_id, format!("Hi, my name is **{}** 👋", me.first_name)) +//! .await?; +//! # Ok::<_, Box>(()) }; +//! ``` +//! +//!
+//! +//!
+//! +//! [`teloxide`]: https://docs.rs/teloxide +//! [Telegram Bot API]: https://core.telegram.org/bots/api +//! [`tokio`]: https://tokio.rs +//! +//! ## Cargo features +//! +//! - `auto_send` — enables [`AutoSend`] bot adaptor +//! - `throttle` — enables [`Throttle`] bot adaptor +//! - `cache_me` — enables [`CacheMe`] bot adaptor +//! - `full` — enables all features except `nigthly` +//! - `nightly` — enables nigthly-only features, currently: +//! - Removes some future boxing using `#![feature(type_alias_impl_trait)]` +//! - Used to built docs (`#![feature(doc_cfg, doc_spotlight)]`) +//! +//! [`AutoSend`]: adaptors::AutoSend +//! [`Throttle`]: adaptors::Throttle +//! [`CacheMe`]: adaptors::CacheMe +#![doc( + // FIXME(waffle): use github + html_logo_url = "https://cdn.discordapp.com/attachments/224881373326999553/798598120760934410/logo.png", + html_favicon_url = "https://cdn.discordapp.com/attachments/224881373326999553/798598120760934410/logo.png" +)] +#![forbid(unsafe_code)] // we pass "--cfg docsrs" when building docs to add `This is supported on feature="..." only.` // // To properly build docs of this crate run // ```console // $ RUSTDOCFLAGS="--cfg docsrs -Znormalize-docs" cargo doc --open --all-features // ``` -#![forbid(unsafe_code)] #![cfg_attr(all(docsrs, feature = "nightly"), feature(doc_cfg, doc_spotlight))] #![cfg_attr(feature = "nightly", feature(type_alias_impl_trait))] #![cfg_attr(feature = "full", deny(broken_intra_doc_links))] diff --git a/src/local_macros.rs b/src/local_macros.rs index 25cffd7f..91f5623a 100644 --- a/src/local_macros.rs +++ b/src/local_macros.rs @@ -188,6 +188,8 @@ macro_rules! impl_payload { #[allow(clippy::too_many_arguments)] // It's just easier for macros to generate such code. #[allow(clippy::redundant_field_names)] + // It's obvious what this method does. (If you think it's not, feel free to open a PR) + #[allow(missing_docs)] $vi fn new($($($fields : impl_payload!(@convert? $FTy $([$conv])?)),*)?) -> Self { Self { $( diff --git a/src/payloads/mod.rs b/src/payloads/mod.rs index abfebc1b..cf31ea9d 100644 --- a/src/payloads/mod.rs +++ b/src/payloads/mod.rs @@ -1,7 +1,8 @@ //! Request data sent to Telegram. -/// This module re-exports all the setters traits as `_`. When used with a glob -/// import: +/// This module re-exports all the setters traits as `_`. +/// +/// When used with a glob import: /// /// ``` /// use teloxide_core::payloads::setters::*; diff --git a/src/prelude.rs b/src/prelude.rs index 3ea2b60c..ed53d1d7 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,3 +1,7 @@ //! Commonly used items. -pub use crate::requests::Requester; +pub use crate::{ + payloads::setters::*, + requests::{Request, Requester, RequesterExt}, + Bot, +}; diff --git a/src/requests/request.rs b/src/requests/request.rs index b719abf5..8517daa2 100644 --- a/src/requests/request.rs +++ b/src/requests/request.rs @@ -13,7 +13,7 @@ use crate::requests::{HasPayload, Output}; /// /// This is crucial for request wrappers which may want to cancel and/or never /// send the underlying request. E.g.: [`Throttle`]'s `send_ref` calls -/// `B::send_ref` while _not_ meaning to really send the request right now. +/// `B::send_ref` while _not_ meaning to really send the request at the moment. /// /// [`Throttle`]: crate::adaptors::Throttle #[cfg_attr(all(docsrs, feature = "nightly"), doc(spotlight))] @@ -32,8 +32,8 @@ pub trait Request: HasPayload { /// A type of the future returned by the [`send_ref`](Request::send_ref) /// method. - // Note: it intentionally forbids borrowing from `self` though anyway we - // couldn't allow borrowing without GATs. + // Note: it intentionally forbids borrowing from `self` though we couldn't allow + // borrowing without GATs anyway. type SendRef: Future, Self::Err>> + Send; /// Send this request. @@ -49,6 +49,8 @@ pub trait Request: HasPayload { /// }; /// /// let bot = Bot::new("TOKEN"); + /// + /// // Note: it's recommended to `Requester` instead of creating requests directly /// let method = GetMe::new(); /// let request = JsonRequest::new(bot, method); /// let _: User = request.send().await.unwrap(); diff --git a/src/requests/requester.rs b/src/requests/requester.rs index 09ff0641..7e30be76 100644 --- a/src/requests/requester.rs +++ b/src/requests/requester.rs @@ -15,9 +15,42 @@ use crate::{ /// /// This trait is implemented by all bots & bot adaptors. /// -/// _This trait is included in the crate's [`prelude`](crate::prelude)_. +/// ## Examples +/// +/// Calling TBA methods: +/// +/// ``` +/// # async { +/// use teloxide_core::{prelude::*, types::ParseMode}; +/// +/// // Bot implements `Requester` +/// let bot = Bot::new("TOKEN"); +/// +/// // Required parameters are supplied to the `Requester` methods: +/// bot.send_message(0, "Text") +/// // 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() +/// .await?; +/// # Ok::<_, teloxide_core::RequestError>(()) }; +/// ``` +/// +/// Using `Requester` in a generic context: +/// +/// ``` +/// use teloxide_core::{prelude::*, types::Message}; +/// +/// async fn send_hi(bot: R, chat: i64) -> Message +/// where +/// R: Requester, +/// { +/// bot.send_message(chat, "hi").send().await.expect("error") +/// } +/// ``` #[cfg_attr(all(docsrs, feature = "nightly"), doc(spotlight))] pub trait Requester { + /// Error type returned by all requests. type Err: std::error::Error + Send; // This block is auto generated by `cg` (de3765b).