Rework Request trait

This commit is contained in:
Waffle 2019-09-03 12:03:38 +03:00
parent 6de592fa6b
commit 3f88c45d6b
4 changed files with 68 additions and 83 deletions

View file

@ -1,14 +1,16 @@
use apply::Apply;
use futures::compat::Future01CompatExt; use futures::compat::Future01CompatExt;
use reqwest::r#async::Client;
use reqwest::StatusCode;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde_json::Value; use serde_json::Value;
use reqwest::{
r#async::{Client, multipart::Form},
StatusCode,
};
use apply::Apply;
use super::requests::Request;
const TELEGRAM_API_URL: &str = "https://api.telegram.org"; const TELEGRAM_API_URL: &str = "https://api.telegram.org";
/// Create url for macking requests, see [telegram docs](https://core.telegram.org/bots/api#making-requests) /// Create url for macking requests, see [telegram docs](https://core.telegram.org/bots/api#making-requests)
fn method_url(base: &str, token: &str, method_name: &str) -> String { fn method_url(base: &str, token: &str, method_name: &str) -> String {
format!( format!(
@ -56,18 +58,16 @@ impl std::error::Error for RequestError {
pub type ResponseResult<T> = Result<T, RequestError>; pub type ResponseResult<T> = Result<T, RequestError>;
pub async fn request<T: DeserializeOwned, R: Request<ReturnValue = T>>( pub async fn request<T: DeserializeOwned>(
client: &Client, client: &Client,
request: R, token: &str,
method_name: &str,
params: Option<Form>,
) -> ResponseResult<T> { ) -> ResponseResult<T> {
let mut response = client let mut response = client
.post(&method_url( .post(&method_url(TELEGRAM_API_URL, token, method_name))
TELEGRAM_API_URL,
request.token(),
request.name(),
))
.apply(|request_builder| { .apply(|request_builder| {
if let Some(params) = request.params() { if let Some(params) = params {
request_builder.multipart(params) request_builder.multipart(params)
} else { } else {
request_builder request_builder

View file

@ -1,24 +1,25 @@
use reqwest::r#async::multipart::Form; use crate::core::{
types::User,
network::{
request, ResponseResult,
},
requests::{
Request, RequestInfo, RequestFuture,
}
};
use crate::core::types::User;
use super::Request; #[derive(Debug, Constructor)]
#[derive(Debug, Constructor, PartialEq, Eq)]
pub struct GetMe { pub struct GetMe {
token: String, info: RequestInfo
} }
impl Request for GetMe { impl Request for GetMe {
type ReturnValue = User; type ReturnValue = User;
fn name(&self) -> &str { fn send(self) -> RequestFuture<ResponseResult<Self::ReturnValue>> {
"getMe" Box::new(async {
} request(&self.info.client, &self.info.token, "getMe", None).await
fn params(self) -> Option<Form> { })
None
}
fn token(&self) -> &str {
&self.token
} }
} }

View file

@ -1,21 +1,30 @@
use reqwest::r#async::multipart::Form; use std::future::Future;
use crate::core::network::ResponseResult;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use reqwest::r#async::Client;
mod form_builder; mod form_builder;
/// Request that can be sended to telegram.
/// Request that can be sent to telegram.
/// `ReturnValue` - a type that will be returned from Telegram. /// `ReturnValue` - a type that will be returned from Telegram.
pub trait Request { pub trait Request {
type ReturnValue: DeserializeOwned; type ReturnValue: DeserializeOwned;
/// Get name of the request (e.g. "getMe" or "sendMessage") /// Send request to telegram
fn name(&self) -> &str; fn send(self) -> RequestFuture<ResponseResult<Self::ReturnValue>>;
}
/// Form with params pub type RequestFuture<T> = Box<dyn Future<Output = T>>;
fn params(self) -> Option<Form>;
/// Bot token // todo: better name?
fn token(&self) -> &str; #[derive(Debug)]
pub(crate) struct RequestInfo {
pub(crate) client: Client,
pub(crate) token: String,
} }
/// Unique identifier for the target chat or username of the target channel (in /// Unique identifier for the target chat or username of the target channel (in

View file

@ -1,19 +1,27 @@
use reqwest::r#async::multipart::Form; use crate::core::{
types::Message,
network::{
request, ResponseResult,
},
requests::{
form_builder::FormBuilder,
ChatId,
Request,
RequestInfo,
RequestFuture,
}
};
use crate::core::types::Message;
use super::form_builder::FormBuilder; #[derive(Debug, TypedBuilder)]
use super::{ChatId, Request};
#[derive(Debug, TypedBuilder, PartialEq, Eq)]
pub struct SendMessage { pub struct SendMessage {
token: String, info: RequestInfo,
chat_id: ChatId, chat_id: ChatId,
text: String, text: String,
#[builder(default)] #[builder(default)]
parse_mode: Option<String>, parse_mode: Option<String>, // TODO: ParseMode enum
// TODO: enum
#[builder(default)] #[builder(default)]
disable_web_page_preview: Option<bool>, disable_web_page_preview: Option<bool>,
#[builder(default)] #[builder(default)]
@ -27,12 +35,10 @@ pub struct SendMessage {
impl Request for SendMessage { impl Request for SendMessage {
type ReturnValue = Message; type ReturnValue = Message;
fn name(&self) -> &str {
"getMe" fn send(self) -> RequestFuture<ResponseResult<Self::ReturnValue>> {
} Box::new(async {
fn params(self) -> Option<Form> { let params = FormBuilder::new()
Some(
FormBuilder::new()
.add("chat_id", &self.chat_id) .add("chat_id", &self.chat_id)
.add("text", &self.text) .add("text", &self.text)
.add_if_some("parse_mode", self.parse_mode.as_ref()) .add_if_some("parse_mode", self.parse_mode.as_ref())
@ -42,40 +48,9 @@ impl Request for SendMessage {
) )
.add_if_some("disable_notification", self.disable_notification.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()) .add_if_some("reply_to_message_id", self.reply_to_message_id.as_ref())
.build(),
)
// TODO:
// .add_if_some("reply_markup",
// self.reply_markup.as_ref()))
}
fn token(&self) -> &str {
&self.token
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn default() {
let sm = SendMessage::builder()
.token("TOKEN")
.chat_id(123456.into())
.text("text")
.build(); .build();
let r = SendMessage {
token: String::from("TOKEN"),
chat_id: ChatId::Id(123456),
text: String::from("text"),
parse_mode: None,
disable_web_page_preview: None,
disable_notification: None,
reply_to_message_id: None,
reply_markup: None,
};
assert_eq!(sm, r); request(&self.info.client, &self.info.token, "sendMessage", Some(params)).await
})
} }
} }