+
# 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/examples/self_info.rs b/examples/self_info.rs
new file mode 100644
index 00000000..78678e9f
--- /dev/null
+++ b/examples/self_info.rs
@@ -0,0 +1,23 @@
+use teloxide_core::{
+ prelude::*,
+ types::{DiceEmoji, ParseMode},
+};
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let chat_id = std::env::var("CHAT_ID")
+ .expect("Expected CHAT_ID env var")
+ .parse::()?;
+
+ 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(())
+}
diff --git a/media/example.gif b/media/example.gif
new file mode 100644
index 00000000..a0605aa6
Binary files /dev/null and b/media/example.gif differ
diff --git a/media/logo.png b/media/logo.png
new file mode 100644
index 00000000..2155dd30
Binary files /dev/null and b/media/logo.png differ
diff --git a/media/logo.svg b/media/logo.svg
new file mode 100644
index 00000000..08a5a668
--- /dev/null
+++ b/media/logo.svg
@@ -0,0 +1,1907 @@
+
+
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 d1105eaf..cca00141 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).emoji(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))]
@@ -35,29 +91,3 @@ mod errors;
// implementation details
mod serde_multipart;
-
-/// Constructs a client from the `TELOXIDE_PROXY` environmental variable.
-///
-/// This function passes the value of `TELOXIDE_PROXY` into
-/// [`reqwest::Proxy::all`], if it exists, otherwise returns the default
-/// client.
-///
-/// # Note
-/// The created client will have safe settings, meaning that it will be able to
-/// work in long time durations, see the [issue 223].
-///
-/// [`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 crate::bot::{sound_bot, TELOXIDE_PROXY};
- use reqwest::Proxy;
-
- 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")
-}
diff --git a/src/local_macros.rs b/src/local_macros.rs
index 271d7cad..fb528f5d 100644
--- a/src/local_macros.rs
+++ b/src/local_macros.rs
@@ -47,7 +47,15 @@ macro_rules! req_future {
$(where $($wh:tt)*)?
) => {
#[pin_project::pin_project]
- $v struct $i<$T>
+ pub
+ // FIXME(waffle):
+ // The `pub` above should ideally be `$v`, but we currently can't do
+ // this due to compiler bug, see:
+ // - pin_project bug report
+ // - related rustc issue
+ // - original fix (closed)
+ // - second iteration of the fix
+ struct $i<$T>
$(where $($wh)*)?
{
#[pin]
@@ -188,6 +196,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/net/mod.rs b/src/net/mod.rs
index 944e1538..6c9665dc 100644
--- a/src/net/mod.rs
+++ b/src/net/mod.rs
@@ -14,6 +14,38 @@ mod telegram_response;
/// The default Telegram API URL.
pub const TELEGRAM_API_URL: &str = "https://api.telegram.org";
+/// Constructs a network client from the `TELOXIDE_PROXY` environmental
+/// variable.
+///
+/// This function passes the value of `TELOXIDE_PROXY` into
+/// [`reqwest::Proxy::all`], if it exists, otherwise returns the default
+/// client.
+///
+/// ## Note
+///
+/// The created client will have safe settings, meaning that it will be able to
+/// work in long time durations, see the [issue 223].
+///
+/// [`reqwest::Proxy::all`]: https://docs.rs/reqwest/latest/reqwest/struct.Proxy.html#method.all
+/// [issue 223]: https://github.com/teloxide/teloxide/issues/223
+///
+/// ## Panics
+///
+/// If `TELOXIDE_PROXY` exists, but isn't correct url.
+pub fn client_from_env() -> reqwest::Client {
+ use crate::bot::{sound_bot, TELOXIDE_PROXY};
+ use reqwest::Proxy;
+
+ 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")
+}
+
/// Creates URL for making HTTPS requests. See the [Telegram documentation].
///
/// [Telegram documentation]: https://core.telegram.org/bots/api#making-requests
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