diff --git a/Cargo.toml b/Cargo.toml
index e40bdb28..85ab027a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,16 +6,20 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "ba7b2a754eab0d79817ea8551d0803806ae8af7d" }
-serde_json = "1.0.39"
-serde = {version = "1.0.92", features = ["derive"] }
-lazy_static = "1.3"
+reqwest = { version = "0.10.0-alpha.1", features = ["json", "unstable-stream"] }
+serde_json = "1.0.41"
+serde = { version = "1.0.101", features = ["derive"] }
apply = "0.2.2"
derive_more = "0.15.0"
-tokio = "0.2.0-alpha.4"
+tokio = "0.2.0-alpha.6"
bytes = "0.4.12"
log = "0.4.8"
-futures-preview = "0.3.0-alpha.18"
pin-project = "0.4.0-alpha.7"
+futures-preview = "0.3.0-alpha.19"
async-trait = "0.1.13"
-libc = "0.2.62"
+thiserror = "1.0.2"
+
+[features]
+default = []
+
+unstable-stream = [] # add streams to public API
\ No newline at end of file
diff --git a/ICON.jpg b/ICON.jpg
new file mode 100644
index 00000000..64d69180
Binary files /dev/null and b/ICON.jpg differ
diff --git a/README.md b/README.md
index 6e0c581c..384dc706 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,30 @@
async-telegram-bot
+
+
+
+
-
-
-## Dependency graph
-
-
+
+
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet consectetur adipiscing elit nibh cubilia, nostra ultricies class torquent integer scelerisque netus euismod vehicula, metus aliquam morbi leo risus cursus massa potenti.
+
+
diff --git a/graph.png b/graph.png
deleted file mode 100644
index 8c66df6f..00000000
Binary files a/graph.png and /dev/null differ
diff --git a/src/bot/api.rs b/src/bot/api.rs
index 0472d84d..a75328c1 100644
--- a/src/bot/api.rs
+++ b/src/bot/api.rs
@@ -1,11 +1,14 @@
use crate::{
bot::Bot,
requests::{
- ChatId, EditMessageLiveLocation, ForwardMessage, GetFile, GetMe,
- SendAudio, SendLocation, SendMediaGroup, SendMessage, SendPhoto,
- StopMessageLiveLocation, GetUpdates
+ AnswerPreCheckoutQuery, AnswerShippingQuery, EditMessageLiveLocation,
+ ForwardMessage, GetFile, GetMe, KickChatMember, PinChatMessage,
+ PromoteChatMember, RestrictChatMember, SendAudio, SendChatAction,
+ SendContact, SendLocation, SendMediaGroup, SendMessage, SendPhoto,
+ SendPoll, SendVenue, SendVideoNote, SendVoice, StopMessageLiveLocation,
+ UnbanChatMember, UnpinChatMessage, GetUpdates
},
- types::{InputFile, InputMedia},
+ types::{ChatAction, ChatId, ChatPermissions, InputFile, InputMedia},
};
/// Telegram functions
@@ -23,7 +26,7 @@ impl Bot {
C: Into,
T: Into,
{
- SendMessage::new(self.ctx(), chat_id.into(), text.into())
+ SendMessage::new(self.ctx(), chat_id, text)
}
pub fn edit_message_live_location(
@@ -35,11 +38,7 @@ impl Bot {
Lt: Into,
Lg: Into,
{
- EditMessageLiveLocation::new(
- self.ctx(),
- latitude.into(),
- longitude.into(),
- )
+ EditMessageLiveLocation::new(self.ctx(), latitude, longitude)
}
pub fn forward_message(
@@ -53,12 +52,7 @@ impl Bot {
F: Into,
M: Into,
{
- ForwardMessage::new(
- self.ctx(),
- chat_id.into(),
- from_chat_id.into(),
- message_id.into(),
- )
+ ForwardMessage::new(self.ctx(), chat_id, from_chat_id, message_id)
}
pub fn send_audio(&self, chat_id: C, audio: A) -> SendAudio
@@ -66,7 +60,7 @@ impl Bot {
C: Into,
A: Into,
{
- SendAudio::new(self.ctx(), chat_id.into(), audio.into())
+ SendAudio::new(self.ctx(), chat_id, audio)
}
pub fn send_location(
@@ -80,12 +74,7 @@ impl Bot {
Lt: Into,
Lg: Into,
{
- SendLocation::new(
- self.ctx(),
- chat_id.into(),
- latitude.into(),
- longitude.into(),
- )
+ SendLocation::new(self.ctx(), chat_id, latitude, longitude)
}
pub fn send_media_group(&self, chat_id: C, media: M) -> SendMediaGroup
@@ -93,7 +82,7 @@ impl Bot {
C: Into,
M: Into>,
{
- SendMediaGroup::new(self.ctx(), chat_id.into(), media.into())
+ SendMediaGroup::new(self.ctx(), chat_id, media)
}
pub fn send_photo(&self, chat_id: C, photo: P) -> SendPhoto
@@ -101,7 +90,7 @@ impl Bot {
C: Into,
P: Into,
{
- SendPhoto::new(self.ctx(), chat_id.into(), photo.into())
+ SendPhoto::new(self.ctx(), chat_id, photo)
}
pub fn stop_message_live_location(&self) -> StopMessageLiveLocation {
@@ -112,6 +101,177 @@ impl Bot {
where
F: Into,
{
- GetFile::new(self.ctx(), file_id.into())
+ GetFile::new(self.ctx(), file_id)
+ }
+
+ pub fn answer_pre_checkout_query(
+ &self,
+ pre_checkout_query_id: I,
+ ok: O,
+ ) -> AnswerPreCheckoutQuery
+ where
+ I: Into,
+ O: Into,
+ {
+ AnswerPreCheckoutQuery::new(self.ctx(), pre_checkout_query_id, ok)
+ }
+
+ pub fn answer_shipping_query(
+ &self,
+ shipping_query_id: I,
+ ok: O,
+ ) -> AnswerShippingQuery
+ where
+ I: Into,
+ O: Into,
+ {
+ AnswerShippingQuery::new(self.ctx(), shipping_query_id, ok)
+ }
+
+ pub fn kick_chat_member(
+ &self,
+ chat_id: C,
+ user_id: U,
+ ) -> KickChatMember
+ where
+ C: Into,
+ U: Into,
+ {
+ KickChatMember::new(self.ctx(), chat_id, user_id)
+ }
+
+ pub fn pin_chat_message(
+ &self,
+ chat_id: C,
+ message_id: M,
+ ) -> PinChatMessage
+ where
+ C: Into,
+ M: Into,
+ {
+ PinChatMessage::new(self.ctx(), chat_id, message_id)
+ }
+
+ pub fn promote_chat_member(
+ &self,
+ chat_id: C,
+ user_id: U,
+ ) -> PromoteChatMember
+ where
+ C: Into,
+ U: Into,
+ {
+ PromoteChatMember::new(self.ctx(), chat_id, user_id)
+ }
+
+ pub fn restrict_chat_member(
+ &self,
+ chat_id: C,
+ user_id: U,
+ permissions: P,
+ ) -> RestrictChatMember
+ where
+ C: Into,
+ U: Into,
+ P: Into,
+ {
+ RestrictChatMember::new(self.ctx(), chat_id, user_id, permissions)
+ }
+
+ pub fn send_chat_action(
+ &self,
+ chat_id: C,
+ action: A,
+ ) -> SendChatAction
+ where
+ C: Into,
+ A: Into,
+ {
+ SendChatAction::new(self.ctx(), chat_id, action)
+ }
+
+ pub fn send_contact(
+ &self,
+ chat_id: C,
+ phone_number: P,
+ first_name: F,
+ ) -> SendContact
+ where
+ C: Into,
+ P: Into,
+ F: Into,
+ {
+ SendContact::new(self.ctx(), chat_id, phone_number, first_name)
+ }
+
+ pub fn send_poll(
+ &self,
+ chat_id: C,
+ question: Q,
+ options: O,
+ ) -> SendPoll
+ where
+ C: Into,
+ Q: Into,
+ O: Into>,
+ {
+ SendPoll::new(self.ctx(), chat_id, question, options)
+ }
+
+ pub fn send_venue(
+ &self,
+ chat_id: C,
+ latitude: Lt,
+ longitude: Lg,
+ title: T,
+ address: A,
+ ) -> SendVenue
+ where
+ C: Into,
+ Lt: Into,
+ Lg: Into,
+ T: Into,
+ A: Into,
+ {
+ SendVenue::new(self.ctx(), chat_id, latitude, longitude, title, address)
+ }
+
+ pub fn send_video_note(
+ &self,
+ chat_id: C,
+ video_note: V,
+ ) -> SendVideoNote
+ where
+ C: Into,
+ V: Into, // TODO: InputFile
+ {
+ SendVideoNote::new(self.ctx(), chat_id, video_note)
+ }
+
+ pub fn send_voice(&self, chat_id: C, voice: V) -> SendVoice
+ where
+ C: Into,
+ V: Into, // TODO: InputFile
+ {
+ SendVoice::new(self.ctx(), chat_id, voice)
+ }
+
+ pub fn unban_chat_member(
+ &self,
+ chat_id: C,
+ user_id: U,
+ ) -> UnbanChatMember
+ where
+ C: Into,
+ U: Into,
+ {
+ UnbanChatMember::new(self.ctx(), chat_id, user_id)
+ }
+
+ pub fn unpin_chat_message(&self, chat_id: C) -> UnpinChatMessage
+ where
+ C: Into,
+ {
+ UnpinChatMessage::new(self.ctx(), chat_id)
}
}
diff --git a/src/bot/download.rs b/src/bot/download.rs
index d3c6ff69..d711f151 100644
--- a/src/bot/download.rs
+++ b/src/bot/download.rs
@@ -1,11 +1,11 @@
-use reqwest::r#async::Chunk;
-use tokio::{io::AsyncWrite, stream::Stream};
+use tokio::io::AsyncWrite;
-use crate::{
- bot::Bot,
- network::{download_file, download_file_stream},
- DownloadError,
-};
+#[cfg(feature = "unstable-stream")]
+use ::{bytes::Bytes, tokio::stream::Stream};
+
+#[cfg(feature = "unstable-stream")]
+use crate::network::download_file_stream;
+use crate::{bot::Bot, network::download_file, DownloadError};
impl Bot {
/// Download file from telegram into `destination`.
@@ -26,8 +26,7 @@ impl Bot {
/// let bot = Bot::new("TOKEN");
/// let mut file = File::create("/home/waffle/Pictures/test.png").await?;
///
- /// let TgFile { file_path, .. } =
- /// bot.get_file("*file_id*").send_boxed().await?;
+ /// let TgFile { file_path, .. } = bot.get_file("*file_id*").send().await?;
/// bot.download_file(&file_path, &mut file).await?;
/// # Ok(()) }
/// ```
@@ -56,10 +55,11 @@ impl Bot {
/// [`AsyncWrite`]: tokio::io::AsyncWrite
/// [`tokio::fs::File`]: tokio::fs::File
/// [`download_file`]: crate::bot::Bot::download_file
+ #[cfg(feature = "unstable-stream")]
pub async fn download_file_stream(
&self,
path: &str,
- ) -> Result>, reqwest::Error>
+ ) -> Result>, reqwest::Error>
{
download_file_stream(&self.client, &self.token, path).await
}
diff --git a/src/bot/mod.rs b/src/bot/mod.rs
index eacf2e3a..4f370663 100644
--- a/src/bot/mod.rs
+++ b/src/bot/mod.rs
@@ -1,4 +1,4 @@
-use reqwest::r#async::Client;
+use reqwest::Client;
use crate::requests::RequestContext;
diff --git a/src/errors.rs b/src/errors.rs
index 6482793d..e8c1ae21 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,29 +1,21 @@
use reqwest::StatusCode;
//
-#[derive(Debug, Display, From)]
+#[derive(Debug, Error, From)]
pub enum DownloadError {
- #[display(fmt = "Network error: {err}", err = _0)]
- NetworkError(reqwest::Error),
+ #[error("A network error: {0}")]
+ NetworkError(#[source] reqwest::Error),
- #[display(fmt = "IO Error: {err}", err = _0)]
- Io(std::io::Error),
+ #[error("An I/O error: {0}")]
+ Io(#[source] std::io::Error),
}
-impl std::error::Error for DownloadError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match self {
- DownloadError::NetworkError(err) => Some(err),
- DownloadError::Io(err) => Some(err),
- }
- }
-}
//
//
-#[derive(Debug, Display)]
+#[derive(Debug, Error)]
pub enum RequestError {
- #[display(fmt = "Telegram error #{}: {}", status_code, description)]
+ #[error("A Telegram's error #{status_code}: {description}")]
ApiError {
status_code: StatusCode,
description: String,
@@ -31,30 +23,19 @@ pub enum RequestError {
/// The group has been migrated to a supergroup with the specified
/// identifier.
- #[display(fmt = "The group has been migrated to a supergroup with id {id}", id = _0)]
+ #[error("The group has been migrated to a supergroup with ID #{0}")]
MigrateToChatId(i64),
/// In case of exceeding flood control, the number of seconds left to wait
/// before the request can be repeated
- #[display(fmt = "Retry after {secs} seconds", secs = _0)]
+ #[error("Retry after {0} seconds")]
RetryAfter(i32),
- #[display(fmt = "Network error: {err}", err = _0)]
- NetworkError(reqwest::Error),
+ #[error("A network error: {0}")]
+ NetworkError(#[source] reqwest::Error),
- #[display(fmt = "InvalidJson error caused by: {err}", err = _0)]
- InvalidJson(serde_json::Error),
+ #[error("An error while parsing JSON: {0}")]
+ InvalidJson(#[source] serde_json::Error),
}
-impl std::error::Error for RequestError {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match self {
- RequestError::ApiError { .. } => None,
- RequestError::MigrateToChatId(_) => None,
- RequestError::RetryAfter(_) => None,
- RequestError::NetworkError(err) => Some(err),
- RequestError::InvalidJson(err) => Some(err),
- }
- }
-}
//
diff --git a/src/lib.rs b/src/lib.rs
index 28221d58..8d244ff6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,9 +1,9 @@
-#![feature(termination_trait_lib)]
-
#[macro_use]
extern crate derive_more;
#[macro_use]
extern crate serde;
+#[macro_use]
+extern crate thiserror;
pub use errors::{DownloadError, RequestError};
diff --git a/src/network/download.rs b/src/network/download.rs
index 82ff18ea..47061b6f 100644
--- a/src/network/download.rs
+++ b/src/network/download.rs
@@ -1,10 +1,8 @@
-use bytes::Buf;
-use futures::StreamExt;
-use reqwest::r#async::{Chunk, Client};
-use tokio::{
- io::{AsyncWrite, AsyncWriteExt},
- stream::Stream,
-};
+use reqwest::Client;
+use tokio::io::{AsyncWrite, AsyncWriteExt};
+
+#[cfg(feature = "unstable-stream")]
+use ::{bytes::Bytes, tokio::stream::Stream};
use crate::DownloadError;
@@ -19,25 +17,38 @@ pub async fn download_file(
where
D: AsyncWrite + Unpin,
{
- let mut stream = download_file_stream(client, token, path).await?;
+ let mut res = client
+ .get(&super::file_url(TELEGRAM_API_URL, token, path))
+ .send()
+ .await?
+ .error_for_status()?;
- while let Some(chunk) = stream.next().await {
- let chunk = chunk?;
- destination.write_all(chunk.bytes()).await?;
+ while let Some(chunk) = res.chunk().await? {
+ destination.write_all(&chunk).await?;
}
Ok(())
}
+#[cfg(feature = "unstable-stream")]
pub async fn download_file_stream(
client: &Client,
token: &str,
path: &str,
-) -> Result>, reqwest::Error> {
- Ok(client
+) -> Result>, reqwest::Error> {
+ let res = client
.get(&super::file_url(TELEGRAM_API_URL, token, path))
.send()
.await?
- .error_for_status()?
- .into_body())
+ .error_for_status()?;
+
+ Ok(futures::stream::unfold(res, |mut res| {
+ async {
+ match res.chunk().await {
+ Err(err) => Some((Err(err), res)),
+ Ok(Some(c)) => Some((Ok(c), res)),
+ Ok(None) => None,
+ }
+ }
+ }))
}
diff --git a/src/network/mod.rs b/src/network/mod.rs
index 625b28e3..1461304f 100644
--- a/src/network/mod.rs
+++ b/src/network/mod.rs
@@ -1,6 +1,11 @@
-pub use download::{download_file, download_file_stream};
-pub use request::{request_json, request_multipart};
-pub use telegram_response::TelegramResponse;
+#[cfg(feature = "unstable-stream")]
+pub use download::download_file_stream;
+
+pub use self::{
+ download::download_file,
+ request::{request_json, request_multipart},
+ telegram_response::TelegramResponse,
+};
mod download;
mod request;
@@ -22,7 +27,7 @@ fn method_url(base: &str, token: &str, method_name: &str) -> String {
/// Creates URL for downloading a file. See the [Telegram documentation].
///
-/// [Telegram documentation] (https://core.telegram.org/bots/api#file)
+/// [Telegram documentation]: https://core.telegram.org/bots/api#file
fn file_url(base: &str, token: &str, file_path: &str) -> String {
format!(
"{url}/file/bot{token}/{file}",
diff --git a/src/network/request.rs b/src/network/request.rs
index 139b6f74..ac97c612 100644
--- a/src/network/request.rs
+++ b/src/network/request.rs
@@ -1,5 +1,5 @@
use apply::Apply;
-use reqwest::r#async::{multipart::Form, Client, Response};
+use reqwest::{multipart::Form, Client, Response};
use serde::{de::DeserializeOwned, Serialize};
use crate::{requests::ResponseResult, RequestError};
@@ -29,12 +29,16 @@ where
.await
}
-pub async fn request_json(
+pub async fn request_json(
client: &Client,
token: &str,
method_name: &str,
params: &P,
-) -> ResponseResult {
+) -> ResponseResult
+where
+ T: DeserializeOwned,
+ P: Serialize,
+{
process_response(
client
.post(&super::method_url(TELEGRAM_API_URL, token, method_name))
@@ -46,9 +50,10 @@ pub async fn request_json(
.await
}
-async fn process_response(
- mut response: Response,
-) -> ResponseResult {
+async fn process_response(response: Response) -> ResponseResult
+where
+ T: DeserializeOwned,
+{
serde_json::from_str::>(
&response.text().await.map_err(RequestError::NetworkError)?,
)
diff --git a/src/requests/answer_pre_checkout_query.rs b/src/requests/answer_pre_checkout_query.rs
index 9caee1e9..df5940e7 100644
--- a/src/requests/answer_pre_checkout_query.rs
+++ b/src/requests/answer_pre_checkout_query.rs
@@ -12,6 +12,8 @@ use crate::{
/// pre_checkout_query. Use this method to respond to such pre-checkout queries.
/// On success, True is returned. Note: The Bot API must receive an answer
/// within 10 seconds after the pre-checkout query was sent.
+///
+/// [`Update`]: crate::types::Update
pub struct AnswerPreCheckoutQuery<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
@@ -56,40 +58,44 @@ impl AnswerPreCheckoutQuery<'_> {
}
impl<'a> AnswerPreCheckoutQuery<'a> {
- pub(crate) fn new(
+ pub(crate) fn new(
ctx: RequestContext<'a>,
- pre_checkout_query_id: String,
- ok: bool,
- ) -> Self {
+ pre_checkout_query_id: S,
+ ok: B,
+ ) -> Self
+ where
+ S: Into,
+ B: Into,
+ {
Self {
ctx,
- pre_checkout_query_id,
- ok,
+ pre_checkout_query_id: pre_checkout_query_id.into(),
+ ok: ok.into(),
error_message: None,
}
}
- pub fn pre_checkout_query_id(mut self, pre_checkout_query_id: T) -> Self
+ pub fn pre_checkout_query_id(mut self, value: T) -> Self
where
T: Into,
{
- self.pre_checkout_query_id = pre_checkout_query_id.into();
+ self.pre_checkout_query_id = value.into();
self
}
- pub fn ok(mut self, ok: T) -> Self
+ pub fn ok(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.ok = ok.into();
+ self.ok = value.into();
self
}
- pub fn error_message(mut self, error_message: T) -> Self
+ pub fn error_message(mut self, value: S) -> Self
where
- T: Into,
+ S: Into,
{
- self.error_message = Some(error_message.into());
+ self.error_message = Some(value.into());
self
}
}
diff --git a/src/requests/answer_shipping_query.rs b/src/requests/answer_shipping_query.rs
index 6961f5dc..cb58135c 100644
--- a/src/requests/answer_shipping_query.rs
+++ b/src/requests/answer_shipping_query.rs
@@ -11,6 +11,8 @@ use crate::{
/// is_flexible was specified, the Bot API will send an [`Update`] with a
/// shipping_query field to the bot. Use this method to reply to shipping
/// queries. On success, True is returned.
+///
+/// [`Update`]: crate::types::Update
pub struct AnswerShippingQuery<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
@@ -57,49 +59,53 @@ impl AnswerShippingQuery<'_> {
}
impl<'a> AnswerShippingQuery<'a> {
- pub(crate) fn new(
+ pub(crate) fn new(
ctx: RequestContext<'a>,
- shipping_query_id: String,
- ok: bool,
- ) -> Self {
+ shipping_query_id: S,
+ ok: B,
+ ) -> Self
+ where
+ S: Into,
+ B: Into,
+ {
Self {
ctx,
- shipping_query_id,
- ok,
+ shipping_query_id: shipping_query_id.into(),
+ ok: ok.into(),
shipping_options: None,
error_message: None,
}
}
- pub fn shipping_query_id(mut self, shipping_query_id: T) -> Self
+ pub fn shipping_query_id(mut self, value: S) -> Self
where
- T: Into,
+ S: Into,
{
- self.shipping_query_id = shipping_query_id.into();
+ self.shipping_query_id = value.into();
self
}
- pub fn ok(mut self, ok: T) -> Self
+ pub fn ok(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.ok = ok.into();
+ self.ok = value.into();
self
}
- pub fn shipping_options(mut self, shipping_options: T) -> Self
+ pub fn shipping_options(mut self, value: T) -> Self
where
T: Into>,
{
- self.shipping_options = Some(shipping_options.into());
+ self.shipping_options = Some(value.into());
self
}
- pub fn error_message(mut self, error_message: T) -> Self
+ pub fn error_message(mut self, value: S) -> Self
where
- T: Into,
+ S: Into,
{
- self.error_message = Some(error_message.into());
+ self.error_message = Some(value.into());
self
}
}
diff --git a/src/requests/edit_message_live_location.rs b/src/requests/edit_message_live_location.rs
index 192a1e2a..db584c28 100644
--- a/src/requests/edit_message_live_location.rs
+++ b/src/requests/edit_message_live_location.rs
@@ -2,16 +2,19 @@ use async_trait::async_trait;
use crate::{
network,
- requests::{ChatId, Request, RequestContext, ResponseResult},
- types::{Message, ReplyMarkup},
+ requests::{Request, RequestContext, ResponseResult},
+ types::{ChatId, Message, ReplyMarkup},
};
#[derive(Debug, Clone, Serialize)]
/// 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
+/// call to [`StopMessageLiveLocation`]. On success, if the edited message
/// was sent by the bot, the edited [`Message`] is returned, otherwise True
/// is returned.
+///
+/// [`StopMessageLiveLocation`]: crate::requests::StopMessageLiveLocation
+/// [`Message`]: crate::types::Message
pub struct EditMessageLiveLocation<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>,
@@ -60,47 +63,63 @@ impl EditMessageLiveLocation<'_> {
}
impl<'a> EditMessageLiveLocation<'a> {
- pub(crate) fn new(
+ pub(crate) fn new(
ctx: RequestContext<'a>,
- latitude: f64,
- longitude: f64,
- ) -> Self {
+ latitude: Lt,
+ longitude: Lg,
+ ) -> Self
+ where
+ Lt: Into,
+ Lg: Into,
+ {
Self {
ctx,
chat_id: None,
message_id: None,
inline_message_id: None,
- latitude,
- longitude,
+ latitude: latitude.into(),
+ longitude: longitude.into(),
reply_markup: None,
}
}
- pub fn chat_id>(mut self, chat_id: T) -> Self {
- self.chat_id = Some(chat_id.into());
- self
- }
-
- pub fn message_id>(mut self, message_id: T) -> Self {
- self.message_id = Some(message_id.into());
- self
- }
-
- pub fn inline_message_id(mut self, inline_message_id: T) -> Self
+ pub fn chat_id(mut self, value: T) -> Self
where
- T: Into,
+ T: Into,
{
- self.inline_message_id = Some(inline_message_id.into());
+ self.chat_id = Some(value.into());
self
}
- pub fn latitude>(mut self, latitude: T) -> Self {
- self.latitude = latitude.into();
+ pub fn message_id(mut self, value: T) -> Self
+ where
+ T: Into,
+ {
+ self.message_id = Some(value.into());
self
}
- pub fn longitude>(mut self, longitude: T) -> Self {
- self.longitude = longitude.into();
+ pub fn inline_message_id(mut self, value: S) -> Self
+ where
+ S: Into,
+ {
+ self.inline_message_id = Some(value.into());
+ self
+ }
+
+ pub fn latitude(mut self, value: Lt) -> Self
+ where
+ Lt: Into,
+ {
+ self.latitude = value.into();
+ self
+ }
+
+ pub fn longitude(mut self, value: Lg) -> Self
+ where
+ Lg: Into,
+ {
+ self.longitude = value.into();
self
}
}
diff --git a/src/requests/form_builder.rs b/src/requests/form_builder.rs
index d5ee4169..72a013e7 100644
--- a/src/requests/form_builder.rs
+++ b/src/requests/form_builder.rs
@@ -1,13 +1,13 @@
use std::path::PathBuf;
-use reqwest::r#async::multipart::Form;
+use reqwest::multipart::Form;
use crate::{
- requests::{utils, ChatId},
- types::{InputMedia, ParseMode},
+ requests::utils,
+ types::{ChatId, InputMedia, ParseMode},
};
-/// This is a convenient struct that builds `reqwest::r#async::multipart::Form`
+/// This is a convenient struct that builds `reqwest::multipart::Form`
/// from scratch.
pub struct FormBuilder {
form: Form,
diff --git a/src/requests/forward_message.rs b/src/requests/forward_message.rs
index 90dd5765..6681faf0 100644
--- a/src/requests/forward_message.rs
+++ b/src/requests/forward_message.rs
@@ -2,8 +2,8 @@ use async_trait::async_trait;
use crate::{
network,
- requests::{ChatId, Request, RequestContext, ResponseResult},
- types::Message,
+ requests::{Request, RequestContext, ResponseResult},
+ types::{ChatId, Message},
};
#[derive(Debug, Clone, Serialize)]
@@ -50,38 +50,56 @@ impl ForwardMessage<'_> {
}
impl<'a> ForwardMessage<'a> {
- pub(crate) fn new(
+ pub(crate) fn new(
ctx: RequestContext<'a>,
- chat_id: ChatId,
- from_chat_id: ChatId,
- message_id: i32,
- ) -> Self {
+ chat_id: C,
+ from_chat_id: Fc,
+ message_id: M,
+ ) -> Self
+ where
+ C: Into,
+ Fc: Into,
+ M: Into,
+ {
Self {
ctx,
- chat_id,
- from_chat_id,
- message_id,
+ chat_id: chat_id.into(),
+ from_chat_id: from_chat_id.into(),
+ message_id: message_id.into(),
disable_notification: None,
}
}
- pub fn chat_id>(mut self, val: T) -> Self {
- self.chat_id = val.into();
+ pub fn chat_id(mut self, value: C) -> Self
+ where
+ C: Into,
+ {
+ self.chat_id = value.into();
self
}
- pub fn from_chat_id>(mut self, val: T) -> Self {
- self.from_chat_id = val.into();
+ #[allow(clippy::wrong_self_convention)]
+ pub fn from_chat_id(mut self, value: C) -> Self
+ where
+ C: Into,
+ {
+ self.from_chat_id = value.into();
self
}
- pub fn message_id>(mut self, val: T) -> Self {
- self.message_id = val.into();
+ pub fn message_id(mut self, value: M) -> Self
+ where
+ M: Into,
+ {
+ self.message_id = value.into();
self
}
- pub fn disable_notification>(mut self, val: T) -> Self {
- self.disable_notification = Some(val.into());
+ pub fn disable_notification(mut self, value: B) -> Self
+ where
+ B: Into,
+ {
+ self.disable_notification = Some(value.into());
self
}
}
diff --git a/src/requests/get_chat.rs b/src/requests/get_chat.rs
index 4a71a107..9de16585 100644
--- a/src/requests/get_chat.rs
+++ b/src/requests/get_chat.rs
@@ -2,8 +2,8 @@ use async_trait::async_trait;
use crate::{
network,
- requests::{ChatId, Request, RequestContext, ResponseResult},
- types::Chat,
+ requests::{Request, RequestContext, ResponseResult},
+ types::{Chat, ChatId},
};
/// Use this method to get up to date information about the chat
@@ -41,11 +41,11 @@ impl GetChat<'_> {
}
impl<'a> GetChat<'a> {
- pub fn chat_id(mut self, chat_id: T) -> Self
+ pub fn chat_id(mut self, value: C) -> Self
where
- T: Into,
+ C: Into,
{
- self.chat_id = chat_id.into();
+ self.chat_id = value.into();
self
}
}
diff --git a/src/requests/get_file.rs b/src/requests/get_file.rs
index abfc8cd5..bb303e92 100644
--- a/src/requests/get_file.rs
+++ b/src/requests/get_file.rs
@@ -43,15 +43,21 @@ impl GetFile<'_> {
}
impl<'a> GetFile<'a> {
- pub(crate) fn new(ctx: RequestContext<'a>, file_id: String) -> Self {
- Self { ctx, file_id }
+ pub(crate) fn new(ctx: RequestContext<'a>, value: F) -> Self
+ where
+ F: Into,
+ {
+ Self {
+ ctx,
+ file_id: value.into(),
+ }
}
- pub fn file_id(mut self, file_id: T) -> Self
+ pub fn file_id(mut self, value: F) -> Self
where
- T: Into,
+ F: Into,
{
- self.file_id = file_id.into();
+ self.file_id = value.into();
self
}
}
diff --git a/src/requests/get_updates.rs b/src/requests/get_updates.rs
index 596eaac1..5925c114 100644
--- a/src/requests/get_updates.rs
+++ b/src/requests/get_updates.rs
@@ -61,35 +61,35 @@ impl<'a> GetUpdates<'a> {
}
}
- pub fn offset(mut self, offset: T) -> Self
+ pub fn offset(mut self, value: T) -> Self
where
T: Into,
{
- self.offset = Some(offset.into());
+ self.offset = Some(value.into());
self
}
- pub fn limit(mut self, limit: T) -> Self
+ pub fn limit(mut self, value: T) -> Self
where
T: Into,
{
- self.limit = Some(limit.into());
+ self.limit = Some(value.into());
self
}
- pub fn timeout(mut self, timeout: T) -> Self
+ pub fn timeout(mut self, value: T) -> Self
where
T: Into,
{
- self.timeout = Some(timeout.into());
+ self.timeout = Some(value.into());
self
}
- pub fn allowed_updates(mut self, allowed_updates: T) -> Self
+ pub fn allowed_updates(mut self, value: T) -> Self
where
T: Into>,
{
- self.allowed_updates = Some(allowed_updates.into());
+ self.allowed_updates = Some(value.into());
self
}
}
diff --git a/src/requests/get_user_profile_photos.rs b/src/requests/get_user_profile_photos.rs
index 28e6b4be..37246478 100644
--- a/src/requests/get_user_profile_photos.rs
+++ b/src/requests/get_user_profile_photos.rs
@@ -46,36 +46,39 @@ impl GetUserProfilePhotos<'_> {
}
impl<'a> GetUserProfilePhotos<'a> {
- pub fn new(ctx: RequestContext<'a>, user_id: i32) -> Self {
+ pub fn new(ctx: RequestContext<'a>, user_id: U) -> Self
+ where
+ U: Into,
+ {
Self {
ctx,
- user_id,
+ user_id: user_id.into(),
offset: None,
limit: None,
}
}
- pub fn user_id(mut self, user_id: T) -> Self
+ pub fn user_id(mut self, value: T) -> Self
where
T: Into,
{
- self.user_id = user_id.into();
+ self.user_id = value.into();
self
}
- pub fn offset(mut self, offset: T) -> Self
+ pub fn offset(mut self, value: T) -> Self
where
T: Into,
{
- self.offset = Some(offset.into());
+ self.offset = Some(value.into());
self
}
- pub fn limit(mut self, limit: T) -> Self
+ pub fn limit(mut self, value: T) -> Self
where
T: Into,
{
- self.limit = Some(limit.into());
+ self.limit = Some(value.into());
self
}
}
diff --git a/src/requests/kick_chat_member.rs b/src/requests/kick_chat_member.rs
index e30716d3..08956d2a 100644
--- a/src/requests/kick_chat_member.rs
+++ b/src/requests/kick_chat_member.rs
@@ -2,8 +2,8 @@ use async_trait::async_trait;
use crate::{
network,
- requests::{ChatId, Request, RequestContext, ResponseResult},
- types::True,
+ requests::{Request, RequestContext, ResponseResult},
+ types::{ChatId, True},
};
/// Use this method to kick a user from a group, a supergroup or a channel. In
@@ -28,7 +28,7 @@ pub struct KickChatMember<'a> {
}
#[async_trait]
-impl<'a> Request for KickChatMember<'a> {
+impl Request for KickChatMember<'_> {
type ReturnValue = True;
async fn send_boxed(self) -> ResponseResult {
@@ -49,31 +49,44 @@ impl KickChatMember<'_> {
}
impl<'a> KickChatMember<'a> {
- pub(crate) fn new(
+ pub(crate) fn new(
ctx: RequestContext<'a>,
- chat_id: ChatId,
- user_id: i32,
- ) -> Self {
+ chat_id: C,
+ user_id: U,
+ ) -> Self
+ where
+ C: Into,
+ U: Into,
+ {
Self {
ctx,
- chat_id,
- user_id,
+ chat_id: chat_id.into(),
+ user_id: user_id.into(),
until_date: None,
}
}
- pub fn chat_id>(mut self, chat_id: T) -> Self {
- self.chat_id = chat_id.into();
+ pub fn chat_id(mut self, value: C) -> Self
+ where
+ C: Into,
+ {
+ self.chat_id = value.into();
self
}
- pub fn user_id>(mut self, user_id: T) -> Self {
- self.user_id = user_id.into();
+ pub fn user_id(mut self, value: U) -> Self
+ where
+ U: Into,
+ {
+ self.user_id = value.into();
self
}
- pub fn until_date>(mut self, until_date: T) -> Self {
- self.until_date = Some(until_date.into());
+ pub fn until_date(mut self, value: T) -> Self
+ where
+ T: Into,
+ {
+ self.until_date = Some(value.into());
self
}
}
diff --git a/src/requests/mod.rs b/src/requests/mod.rs
index afd9c47d..f6708ca1 100644
--- a/src/requests/mod.rs
+++ b/src/requests/mod.rs
@@ -1,7 +1,8 @@
-use async_trait::async_trait;
-use reqwest::r#async::Client;
+use reqwest::Client;
use serde::de::DeserializeOwned;
+use async_trait::async_trait;
+
use crate::RequestError;
pub use self::{
@@ -27,61 +28,6 @@ pub use self::{
mod form_builder;
mod utils;
-pub type ResponseResult = Result;
-
-/// Request that can be sent to telegram.
-/// `ReturnValue` - a type that will be returned from Telegram.
-#[async_trait]
-pub trait Request {
- type ReturnValue: DeserializeOwned;
-
- /// Send request to telegram
- async fn send_boxed(self) -> ResponseResult;
-}
-
-#[derive(Debug, Clone)]
-pub struct RequestContext<'a> {
- pub client: &'a Client,
- pub token: &'a str,
-}
-
-/// Unique identifier for the target chat or username of the target channel (in
-/// the format @channelusername)
-#[derive(Debug, Display, Serialize, From, PartialEq, Eq, Clone)]
-#[serde(untagged)]
-pub enum ChatId {
- /// chat identifier
- #[display(fmt = "{}", _0)]
- Id(i64),
- /// _channel_ username (in the format @channelusername)
- #[display(fmt = "{}", _0)]
- ChannelUsername(String),
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn chat_id_id_serialization() {
- let expected_json = String::from(r#"123456"#);
- let actual_json = serde_json::to_string(&ChatId::Id(123456)).unwrap();
-
- assert_eq!(expected_json, actual_json)
- }
-
- #[test]
- fn chat_id_channel_username_serialization() {
- let expected_json = String::from(r#""@username""#);
- let actual_json = serde_json::to_string(&ChatId::ChannelUsername(
- String::from("@username"),
- ))
- .unwrap();
-
- assert_eq!(expected_json, actual_json)
- }
-}
-
mod answer_pre_checkout_query;
mod answer_shipping_query;
mod edit_message_live_location;
@@ -112,3 +58,21 @@ mod send_voice;
mod stop_message_live_location;
mod unban_chat_member;
mod unpin_chat_message;
+
+pub type ResponseResult = Result;
+
+/// A request that can be sent to Telegram.
+#[async_trait]
+pub trait Request {
+ /// A type of response.
+ type ReturnValue: DeserializeOwned;
+
+ /// Send this request.
+ async fn send_boxed(self) -> ResponseResult;
+}
+
+#[derive(Debug, Clone)]
+pub struct RequestContext<'a> {
+ pub client: &'a Client,
+ pub token: &'a str,
+}
diff --git a/src/requests/pin_chat_message.rs b/src/requests/pin_chat_message.rs
index d8129b59..4f71d4a6 100644
--- a/src/requests/pin_chat_message.rs
+++ b/src/requests/pin_chat_message.rs
@@ -2,8 +2,8 @@ use async_trait::async_trait;
use crate::{
network,
- requests::{ChatId, Request, RequestContext, ResponseResult},
- types::True,
+ requests::{Request, RequestContext, ResponseResult},
+ types::{ChatId, True},
};
/// Use this method to get up to date information about the chat
@@ -22,30 +22,34 @@ pub struct PinChatMessage<'a> {
}
impl<'a> PinChatMessage<'a> {
- pub(crate) fn new(
+ pub(crate) fn new(
ctx: RequestContext<'a>,
- chat_id: ChatId,
- message_id: i32,
- ) -> Self {
+ chat_id: C,
+ message_id: M,
+ ) -> Self
+ where
+ C: Into,
+ M: Into,
+ {
Self {
ctx,
- chat_id,
- message_id,
+ chat_id: chat_id.into(),
+ message_id: message_id.into(),
disable_notification: None,
}
}
- pub fn disable_notification(mut self, val: T) -> Self
+ pub fn disable_notification(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.disable_notification = Some(val.into());
+ self.disable_notification = Some(value.into());
self
}
}
#[async_trait]
-impl<'a> Request for PinChatMessage<'a> {
+impl Request for PinChatMessage<'_> {
type ReturnValue = True;
async fn send_boxed(self) -> ResponseResult {
self.send().await
diff --git a/src/requests/promote_chat_member.rs b/src/requests/promote_chat_member.rs
index 9685adc9..596d56c6 100644
--- a/src/requests/promote_chat_member.rs
+++ b/src/requests/promote_chat_member.rs
@@ -1,9 +1,11 @@
-use crate::network;
-use crate::requests::{ChatId, Request, RequestContext, ResponseResult};
-use crate::types::True;
-
use async_trait::async_trait;
+use crate::{
+ network,
+ requests::{Request, RequestContext, ResponseResult},
+ types::{ChatId, True},
+};
+
///Use this method to promote or demote a user in a supergroup or a channel.
/// The bot must be an administrator in the chat for this to work and must have
/// the appropriate admin rights. Pass False for all boolean parameters to
@@ -47,6 +49,7 @@ pub struct PromoteChatMember<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub can_promote_members: Option,
}
+
#[async_trait]
impl Request for PromoteChatMember<'_> {
type ReturnValue = True;
@@ -67,16 +70,21 @@ impl PromoteChatMember<'_> {
.await
}
}
+
impl<'a> PromoteChatMember<'a> {
- pub(crate) fn new(
+ pub(crate) fn new(
ctx: RequestContext<'a>,
- chat_id: ChatId,
- user_id: i32,
- ) -> Self {
+ chat_id: C,
+ user_id: U,
+ ) -> Self
+ where
+ C: Into,
+ U: Into,
+ {
Self {
ctx,
- chat_id,
- user_id,
+ chat_id: chat_id.into(),
+ user_id: user_id.into(),
can_change_info: None,
can_post_messages: None,
can_edit_messages: None,
@@ -88,83 +96,83 @@ impl<'a> PromoteChatMember<'a> {
}
}
- pub fn chat_id(mut self, chat_id: T) -> Self
+ pub fn chat_id(mut self, value: C) -> Self
where
- T: Into,
+ C: Into,
{
- self.chat_id = chat_id.into();
+ self.chat_id = value.into();
self
}
- pub fn user_id(mut self, user_id: T) -> Self
+ pub fn user_id(mut self, value: U) -> Self
where
- T: Into,
+ U: Into,
{
- self.user_id = user_id.into();
+ self.user_id = value.into();
self
}
- pub fn can_change_info(mut self, can_change_info: T) -> Self
+ pub fn can_change_info(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.can_change_info = Some(can_change_info.into());
+ self.can_change_info = Some(value.into());
self
}
- pub fn can_post_messages(mut self, can_post_messages: T) -> Self
+ pub fn can_post_messages(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.can_post_messages = Some(can_post_messages.into());
+ self.can_post_messages = Some(value.into());
self
}
- pub fn can_edit_messages(mut self, can_edit_messages: T) -> Self
+ pub fn can_edit_messages(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.can_edit_messages = Some(can_edit_messages.into());
+ self.can_edit_messages = Some(value.into());
self
}
- pub fn can_delete_messages(mut self, can_delete_messages: T) -> Self
+ pub fn can_delete_messages(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.can_delete_messages = Some(can_delete_messages.into());
+ self.can_delete_messages = Some(value.into());
self
}
- pub fn can_invite_users(mut self, can_invite_users: T) -> Self
+ pub fn can_invite_users(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.can_invite_users = Some(can_invite_users.into());
+ self.can_invite_users = Some(value.into());
self
}
- pub fn can_restrict_members(mut self, can_restrict_members: T) -> Self
+ pub fn can_restrict_members(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.can_restrict_members = Some(can_restrict_members.into());
+ self.can_restrict_members = Some(value.into());
self
}
- pub fn can_pin_messages(mut self, can_pin_messages: T) -> Self
+ pub fn can_pin_messages(mut self, value: B) -> Self
where
- T: Into,
+ B: Into,
{
- self.can_pin_messages = Some(can_pin_messages.into());
+ self.can_pin_messages = Some(value.into());
self
}
- pub fn can_promote_members(mut self, can_promote_members: T) -> Self
+ pub fn can_promote_members(mut self, value: B) -> Self
where
- T: Into,
+ B: Into