Add option to send requests with json instead of multipart/form-data

This commit is contained in:
Waffle 2019-09-07 22:15:26 +03:00
parent 19f7ce1435
commit 27debb0c77
5 changed files with 56 additions and 41 deletions

View file

@ -5,6 +5,7 @@ use serde::de::DeserializeOwned;
use serde_json::Value; use serde_json::Value;
use crate::core::requests::{RequestError, ResponseResult}; use crate::core::requests::{RequestError, ResponseResult};
use serde::Serialize;
const TELEGRAM_API_URL: &str = "https://api.telegram.org"; const TELEGRAM_API_URL: &str = "https://api.telegram.org";
@ -32,7 +33,7 @@ fn file_url(base: &str, token: &str, file_path: &str) -> String {
) )
} }
pub async fn request<T: DeserializeOwned>( pub async fn request_multipart<T: DeserializeOwned>(
client: &Client, client: &Client,
token: &str, token: &str,
method_name: &str, method_name: &str,
@ -68,6 +69,39 @@ pub async fn request<T: DeserializeOwned>(
} }
} }
pub async fn request_json<T: DeserializeOwned, P: Serialize>(
client: &Client,
token: &str,
method_name: &str,
params: &P,
) -> ResponseResult<T> {
let mut response = client
.post(&method_url(TELEGRAM_API_URL, token, method_name))
.json(params)
.send()
.compat()
.await
.map_err(RequestError::NetworkError)?;
let response_json = serde_json::from_str::<Value>(
&response
.text()
.compat()
.await
.map_err(RequestError::NetworkError)?,
)
.map_err(RequestError::InvalidJson)?;
if response_json["ok"] == "false" {
Err(RequestError::ApiError {
status_code: response.status(),
description: response_json["description"].to_string(),
})
} else {
Ok(serde_json::from_value(response_json["result"].clone()).unwrap())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -3,10 +3,11 @@ use crate::core::requests::{ChatId, RequestContext, Request, RequestFuture, Resp
use crate::core::types::Message; use crate::core::types::Message;
use crate::core::network; use crate::core::network;
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize)]
/// Use this method to forward messages of any kind. On success, the sent /// Use this method to forward messages of any kind. On success, the sent
/// [`Message`] is returned. /// [`Message`] is returned.
pub struct ForwardMessage<'a> { pub struct ForwardMessage<'a> {
#[serde(skip_serializing)]
ctx: RequestContext<'a>, ctx: RequestContext<'a>,
/// Unique identifier for the target chat or username of the target channel /// Unique identifier for the target chat or username of the target channel
@ -19,6 +20,7 @@ pub struct ForwardMessage<'a> {
pub message_id: i64, pub message_id: i64,
/// Sends the message silently. Users will receive a notification with no sound. /// Sends the message silently. Users will receive a notification with no sound.
#[serde(skip_serializing_if="Option::is_none")]
pub disable_notification: Option<bool>, pub disable_notification: Option<bool>,
} }
@ -27,21 +29,11 @@ impl<'a> Request<'a> for ForwardMessage<'a> {
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> { fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
Box::pin(async move { Box::pin(async move {
let params = FormBuilder::new() network::request_json(
.add("chat_id", &self.chat_id)
.add("from_chat_id", &self.from_chat_id)
.add("message_id", &self.message_id)
.add_if_some(
"disable_notification",
self.disable_notification.as_ref()
)
.build();
network::request(
&self.ctx.client, &self.ctx.client,
&self.ctx.token, &self.ctx.token,
"forwardMessage", "forwardMessage",
Some(params), &self,
).await ).await
}) })
} }

View file

@ -16,7 +16,7 @@ impl<'a> Request<'a> for GetMe<'a> {
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> { fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
Box::pin(async move { Box::pin(async move {
network::request(self.info.client, self.info.token, "getMe", None) network::request_multipart(self.info.client, self.info.token, "getMe", None)
.await .await
}) })
} }

View file

@ -4,10 +4,12 @@ use crate::core::requests::{
}; };
use crate::core::{network, types::Message, types::ParseMode}; use crate::core::{network, types::Message, types::ParseMode};
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize)]
/// Use this method to send text messages. On success, the sent [`Message`] is returned. /// Use this method to send text messages. On success, the sent [`Message`] is returned.
pub struct SendMessage<'a> { pub struct SendMessage<'a> {
info: RequestContext<'a>, #[serde(skip_serializing)]
ctx: RequestContext<'a>,
/// Unique identifier for the target chat or username of the target channel /// Unique identifier for the target chat or username of the target channel
/// (in the format @channelusername) /// (in the format @channelusername)
@ -23,13 +25,18 @@ pub struct SendMessage<'a> {
/// [Html]: crate::core::types::ParseMode::Html /// [Html]: crate::core::types::ParseMode::Html
/// [bold, italic, fixed-width text or inline URLs]: /// [bold, italic, fixed-width text or inline URLs]:
/// crate::core::types::ParseMode /// crate::core::types::ParseMode
#[serde(skip_serializing_if="Option::is_none")]
pub parse_mode: Option<ParseMode>, pub parse_mode: Option<ParseMode>,
/// Disables link previews for links in this message /// Disables link previews for links in this message
#[serde(skip_serializing_if="Option::is_none")]
pub disable_web_page_preview: Option<bool>, pub disable_web_page_preview: Option<bool>,
/// Sends the message silently. Users will receive a notification with no sound. /// Sends the message silently. Users will receive a notification with no sound.
#[serde(skip_serializing_if="Option::is_none")]
pub disable_notification: Option<bool>, pub disable_notification: Option<bool>,
/// If the message is a reply, ID of the original message /// If the message is a reply, ID of the original message
#[serde(skip_serializing_if="Option::is_none")]
pub reply_to_message_id: Option<i64>, pub reply_to_message_id: Option<i64>,
#[serde(skip_serializing_if="Option::is_none")]
pub reply_markup: Option<()>, // TODO: ReplyMarkup enum pub reply_markup: Option<()>, // TODO: ReplyMarkup enum
} }
@ -38,29 +45,11 @@ impl<'a> Request<'a> for SendMessage<'a> {
fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> { fn send(self) -> RequestFuture<'a, ResponseResult<Self::ReturnValue>> {
Box::pin(async move { Box::pin(async move {
let params = FormBuilder::new() network::request_json(
.add("chat_id", &self.chat_id) &self.ctx.client,
.add::<str>("text", &self.text) &self.ctx.token,
.add_if_some("parse_mode", self.parse_mode.as_ref())
.add_if_some(
"disable_web_page_preview",
self.disable_web_page_preview.as_ref(),
)
.add_if_some(
"disable_notification",
self.disable_notification.as_ref(),
)
.add_if_some(
"reply_to_message_id",
self.reply_to_message_id.as_ref(),
)
.build();
network::request(
&self.info.client,
&self.info.token,
"sendMessage", "sendMessage",
Some(params), &self,
) )
.await .await
}) })
@ -74,7 +63,7 @@ impl<'a> SendMessage<'a> {
text: String, text: String,
) -> Self { ) -> Self {
SendMessage { SendMessage {
info, ctx: info,
chat_id, chat_id,
text, text,
parse_mode: None, parse_mode: None,

View file

@ -64,7 +64,7 @@ impl<'a> Request<'a> for SendPhoto<'a> {
}; };
let params = params.build(); let params = params.build();
network::request( network::request_multipart(
&self.ctx.client, &self.ctx.client,
&self.ctx.token, &self.ctx.token,
"sendPhoto", "sendPhoto",