Refine network/mod.rs

This commit is contained in:
Temirkhan Myrzamadi 2019-09-02 16:21:10 +06:00
parent ce87928a90
commit cad60fa2fb
6 changed files with 123 additions and 85 deletions

View file

@ -1,59 +1,63 @@
use reqwest::StatusCode;
use reqwest::r#async::Client;
use serde_json::Value;
use futures::compat::Future01CompatExt;
use apply::Apply;
use serde::de::DeserializeOwned;
use super::requests::Request;
use apply::Apply;
use futures::compat::Future01CompatExt;
use reqwest::r#async::Client;
use reqwest::StatusCode;
use serde::de::DeserializeOwned;
use serde_json::Value;
const TELEGRAM_URL_START: &str = "https://api.telegram.org/bot";
const TELEGRAM_API_URL: &str = "https://api.telegram.org";
#[derive(Debug)]
pub enum Error {
Api {
pub enum RequestError {
ApiError {
status_code: StatusCode,
description: Option<String>,
description: String,
},
Send(reqwest::Error),
InvalidJson(reqwest::Error),
NetworkError(reqwest::Error),
InvalidJson(serde_json::Error),
}
pub type Response<T> = Result<T, Error>;
pub type ResponseResult<T> = Result<T, RequestError>;
pub async fn request<R: DeserializeOwned, Req: Request<R>>(
pub async fn request<T: DeserializeOwned, R: Request<T>>(
client: &Client,
request: Req,
) -> Response<T> {
request: R,
) -> ResponseResult<T> {
let mut response = client
.post(&format!(
"{}{token}/{method}",
TELEGRAM_URL_START,
"{url}/bot{token}/{method}",
url = TELEGRAM_API_URL,
token = request.token(),
method = request.name(),
))
.apply(|req| if let Some(params) = request.params() {
req.multipart(params)
} else { req })
.apply(|request_builder| {
if let Some(params) = request.params() {
request_builder.multipart(params)
} else {
request_builder
}
})
.send()
.compat()
.await
.map_err(Error::Send)?;
.map_err(RequestError::NetworkError)?;
let response_json = response
.json::<Value>()
let response_json = serde_json::from_str::<Value>(
&response
.text()
.compat()
.await
.map_err(Error::InvalidJson)?;
.map_err(RequestError::NetworkError)?,
)
.map_err(RequestError::InvalidJson)?;
if response_json["ok"] == "false" {
return Err(Error::Api {
Err(RequestError::ApiError {
status_code: response.status(),
description: match response_json.get("description") {
None => None,
Some(description) => Some(description.to_string()),
},
});
}
description: response_json["description"].to_string(),
})
} else {
Ok(serde_json::from_value(response_json["result"].clone()).unwrap())
}
}

View file

@ -1,5 +1,5 @@
use crate::core::payments::{Invoice, SuccessfulPayment};
use serde::Deserialize;
use crate::core::payments::{SuccessfulPayment, Invoice};
#[derive(Debug, Deserialize)]
pub struct User {

View file

@ -1,8 +1,5 @@
use serde::Deserialize;
use crate::core::other::User;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct SendInvoice {
@ -76,7 +73,7 @@ pub struct OrderInfo {
name: String,
phone_number: String,
email: String,
shipping_address: ShippingAddress
shipping_address: ShippingAddress,
}
#[derive(Debug, Deserialize)]
@ -113,5 +110,5 @@ pub struct PreCheckoutQuery {
total_amount: i64,
invoice_payload: String,
shipping_option_id: Option<String>,
order_info: Option<OrderInfo>
order_info: Option<OrderInfo>,
}

View file

@ -1,16 +1,21 @@
use crate::core::other::User;
use super::Request;
use crate::core::other::User;
use reqwest::r#async::multipart::Form;
#[derive(Debug, Constructor, PartialEq, Eq)]
pub struct GetMe {
token: String,
}
impl Request<User> for GetMe {
fn name(&self) -> &str { "getMe" }
fn params(self) -> Option<Form> { None }
fn token(&self) -> &str { &self.token }
fn name(&self) -> &str {
"getMe"
}
fn params(self) -> Option<Form> {
None
}
fn token(&self) -> &str {
&self.token
}
}

View file

@ -1,6 +1,5 @@
use reqwest::r#async::multipart::Form;
/// Request that can be sended to telegram.
/// `R` - return type.
pub trait Request<R: serde::de::DeserializeOwned> {

View file

@ -1,9 +1,8 @@
use crate::core::other::Message;
use super::{ChatId, Request};
use crate::core::other::Message;
use reqwest::r#async::multipart::Form;
#[derive(Debug, TypedBuilder, PartialEq, Eq)]
pub struct SendMessage {
token: String,
@ -23,7 +22,9 @@ pub struct SendMessage {
}
impl Request<Message> for SendMessage {
fn name(&self) -> &str { "getMe" }
fn name(&self) -> &str {
"getMe"
}
fn params(self) -> Option<Form> {
use apply::Apply;
@ -31,31 +32,59 @@ impl Request<Message> for SendMessage {
let params = Form::new()
.text("chat_id", format!("{:?}", self.chat_id))
.text("text", self.text)
.apply(|f| if let Some(parse_mode) = self.parse_mode {
.apply(|f| {
if let Some(parse_mode) = self.parse_mode {
f.text("parse_mode", parse_mode);
f
} else { f })
.apply(|f| if let Some(disable_web_page_preview) = self.disable_web_page_preview {
f.text("disable_web_page_preview", format!("{:?}", disable_web_page_preview));
} else {
f
} else { f })
.apply(|f| if let Some(disable_notification) = self.disable_notification {
f.text("disable_notification", format!("{:?}", disable_notification));
}
})
.apply(|f| {
if let Some(disable_web_page_preview) = self.disable_web_page_preview {
f.text(
"disable_web_page_preview",
format!("{:?}", disable_web_page_preview),
);
f
} else { f })
.apply(|f| if let Some(reply_to_message_id) = self.reply_to_message_id {
} else {
f
}
})
.apply(|f| {
if let Some(disable_notification) = self.disable_notification {
f.text(
"disable_notification",
format!("{:?}", disable_notification),
);
f
} else {
f
}
})
.apply(|f| {
if let Some(reply_to_message_id) = self.reply_to_message_id {
f.text("reply_to_message_id", format!("{:?}", reply_to_message_id));
f
} else { f })
.apply(|f| if let Some(reply_markup) = self.reply_markup {
} else {
f
}
})
.apply(|f| {
if let Some(reply_markup) = self.reply_markup {
unimplemented!();
//f.text("reply_markup", );
f
} else { f });
} else {
f
}
});
Some(params)
}
fn token(&self) -> &str { &self.token }
fn token(&self) -> &str {
&self.token
}
}
#[cfg(test)]
@ -64,7 +93,11 @@ mod test {
#[test]
fn default() {
let sm = SendMessage::builder().token("TOKEN").chat_id(123456.into()).text("text").build();
let sm = SendMessage::builder()
.token("TOKEN")
.chat_id(123456.into())
.text("text")
.build();
let r = SendMessage {
token: String::from("TOKEN"),
chat_id: ChatId::Id(123456),
@ -73,7 +106,7 @@ mod test {
disable_web_page_preview: None,
disable_notification: None,
reply_to_message_id: None,
reply_markup: None
reply_markup: None,
};
assert_eq!(sm, r);