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 reqwest::r#async::Client;
use reqwest::StatusCode;
use serde::de::DeserializeOwned;
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";
/// 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 {
format!(
@ -56,18 +58,16 @@ impl std::error::Error for 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,
request: R,
token: &str,
method_name: &str,
params: Option<Form>,
) -> ResponseResult<T> {
let mut response = client
.post(&method_url(
TELEGRAM_API_URL,
request.token(),
request.name(),
))
.post(&method_url(TELEGRAM_API_URL, token, method_name))
.apply(|request_builder| {
if let Some(params) = request.params() {
if let Some(params) = params {
request_builder.multipart(params)
} else {
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, PartialEq, Eq)]
#[derive(Debug, Constructor)]
pub struct GetMe {
token: String,
info: RequestInfo
}
impl Request for GetMe {
type ReturnValue = User;
fn name(&self) -> &str {
"getMe"
}
fn params(self) -> Option<Form> {
None
}
fn token(&self) -> &str {
&self.token
fn send(self) -> RequestFuture<ResponseResult<Self::ReturnValue>> {
Box::new(async {
request(&self.info.client, &self.info.token, "getMe", None).await
})
}
}

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 reqwest::r#async::Client;
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.
pub trait Request {
type ReturnValue: DeserializeOwned;
/// Get name of the request (e.g. "getMe" or "sendMessage")
fn name(&self) -> &str;
/// Send request to telegram
fn send(self) -> RequestFuture<ResponseResult<Self::ReturnValue>>;
}
/// Form with params
fn params(self) -> Option<Form>;
pub type RequestFuture<T> = Box<dyn Future<Output = T>>;
/// Bot token
fn token(&self) -> &str;
// todo: better name?
#[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

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;
use super::{ChatId, Request};
#[derive(Debug, TypedBuilder, PartialEq, Eq)]
#[derive(Debug, TypedBuilder)]
pub struct SendMessage {
token: String,
info: RequestInfo,
chat_id: ChatId,
text: String,
#[builder(default)]
parse_mode: Option<String>,
// TODO: enum
parse_mode: Option<String>, // TODO: ParseMode enum
#[builder(default)]
disable_web_page_preview: Option<bool>,
#[builder(default)]
@ -27,12 +35,10 @@ pub struct SendMessage {
impl Request for SendMessage {
type ReturnValue = Message;
fn name(&self) -> &str {
"getMe"
}
fn params(self) -> Option<Form> {
Some(
FormBuilder::new()
fn send(self) -> RequestFuture<ResponseResult<Self::ReturnValue>> {
Box::new(async {
let params = FormBuilder::new()
.add("chat_id", &self.chat_id)
.add("text", &self.text)
.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("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();
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
})
}
}