From 3f88c45d6b37715e5c99ca32c8b919793555350d Mon Sep 17 00:00:00 2001 From: Waffle Date: Tue, 3 Sep 2019 12:03:38 +0300 Subject: [PATCH] Rework `Request` trait --- src/core/network/mod.rs | 24 +++++----- src/core/requests/get_me.rs | 29 ++++++------ src/core/requests/mod.rs | 25 +++++++---- src/core/requests/send_message.rs | 73 ++++++++++--------------------- 4 files changed, 68 insertions(+), 83 deletions(-) diff --git a/src/core/network/mod.rs b/src/core/network/mod.rs index dae61fc5..c1d5eba0 100644 --- a/src/core/network/mod.rs +++ b/src/core/network/mod.rs @@ -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 = Result; -pub async fn request>( +pub async fn request( client: &Client, - request: R, + token: &str, + method_name: &str, + params: Option
, ) -> ResponseResult { 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 diff --git a/src/core/requests/get_me.rs b/src/core/requests/get_me.rs index d72f5ced..ca391477 100644 --- a/src/core/requests/get_me.rs +++ b/src/core/requests/get_me.rs @@ -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 { - None - } - fn token(&self) -> &str { - &self.token + fn send(self) -> RequestFuture> { + Box::new(async { + request(&self.info.client, &self.info.token, "getMe", None).await + }) } } diff --git a/src/core/requests/mod.rs b/src/core/requests/mod.rs index 166aa7e1..7faab8b0 100644 --- a/src/core/requests/mod.rs +++ b/src/core/requests/mod.rs @@ -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>; +} - /// Form with params - fn params(self) -> Option; +pub type RequestFuture = Box>; - /// 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 diff --git a/src/core/requests/send_message.rs b/src/core/requests/send_message.rs index 9907c0af..b0142a98 100644 --- a/src/core/requests/send_message.rs +++ b/src/core/requests/send_message.rs @@ -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, - // TODO: enum + parse_mode: Option, // TODO: ParseMode enum #[builder(default)] disable_web_page_preview: Option, #[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 { - Some( - FormBuilder::new() + + fn send(self) -> RequestFuture> { + 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(), - ) + .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 + }) } }