This commit is contained in:
Waffle 2019-09-02 10:28:06 +03:00
parent bdaca41eda
commit 57ee4e9223
7 changed files with 147 additions and 12 deletions

View file

@ -12,3 +12,5 @@ serde_json = "1.0.39"
serde = {version = "1.0.92", features = ["derive"] } serde = {version = "1.0.92", features = ["derive"] }
lazy_static = "1.3" lazy_static = "1.3"
apply = "0.2.2" apply = "0.2.2"
typed-builder = "0.3.0"
derive_more = "0.15.0"

View file

@ -1,3 +1,6 @@
mod network;
mod requests;
mod games; mod games;
mod getting_updates; mod getting_updates;
mod inline_mode; mod inline_mode;
@ -5,5 +8,4 @@ mod other;
mod payments; mod payments;
mod stickers; mod stickers;
mod telegram_passport; mod telegram_passport;
mod network;
mod updating_messages; mod updating_messages;

View file

@ -2,9 +2,9 @@ use reqwest::StatusCode;
use reqwest::r#async::Client; use reqwest::r#async::Client;
use serde_json::Value; use serde_json::Value;
use futures::compat::Future01CompatExt; use futures::compat::Future01CompatExt;
use reqwest::r#async::multipart::Form;
use apply::Apply; use apply::Apply;
use serde::de::DeserializeOwned;
use super::requests::Request;
const TELEGRAM_URL_START: &str = "https://api.telegram.org/bot"; const TELEGRAM_URL_START: &str = "https://api.telegram.org/bot";
@ -20,20 +20,18 @@ pub enum Error {
pub type Response<T> = Result<T, Error>; pub type Response<T> = Result<T, Error>;
pub async fn request<T: serde::de::DeserializeOwned>( pub async fn request<R: DeserializeOwned, Req: Request<R>>(
client: &Client, client: &Client,
token: &str, request: Req,
method_name: &str,
params: Option<Form>,
) -> Response<T> { ) -> Response<T> {
let mut response = client let mut response = client
.post(&format!( .post(&format!(
"{}{token}/{method}", "{}{token}/{method}",
TELEGRAM_URL_START, TELEGRAM_URL_START,
token = token, token = request.token(),
method = method_name, method = request.name(),
)) ))
.apply(|req| if let Some(params) = params { .apply(|req| if let Some(params) = request.params() {
req.multipart(params) req.multipart(params)
} else { req }) } else { req })
.send() .send()

View file

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

27
src/core/requests/mod.rs Normal file
View file

@ -0,0 +1,27 @@
use reqwest::r#async::multipart::Form;
/// Request that can be sended to telegram.
/// `R` - return type.
pub trait Request<R: serde::de::DeserializeOwned> {
/// Get name of the request (e.g. "getMe" or "sendMessage")
fn name(&self) -> &str;
/// Form with params
fn params(self) -> Option<Form>;
/// Bot token
fn token(&self) -> &str;
}
/// Unique identifier for the target chat or username of the target channel (in the format @channelusername)
#[derive(Debug, Serialize, From)]
pub enum ChatId {
/// chat identifier
Id(i32), // 32?
/// _channel_ username (in the format @channelusername)
ChannelUsername(String)
}
pub mod get_me;
pub mod send_message;

View file

@ -0,0 +1,81 @@
use crate::core::other::Message;
use super::{ChatId, Request};
use reqwest::r#async::multipart::Form;
#[derive(Debug, TypedBuilder)]
pub struct SendMessage {
token: String,
chat_id: ChatId,
text: String,
#[builder(default)]
parse_mode: Option<String>, // TODO: enum
#[builder(default)]
disable_web_page_preview: Option<bool>,
#[builder(default)]
disable_notification: Option<bool>,
#[builder(default)]
reply_to_message_id: Option<i32>,
#[builder(default)]
reply_markup: Option<()>, // TODO: ReplyMarkup enum
}
impl Request<Message> for SendMessage {
fn name(&self) -> &str { "getMe" }
fn params(self) -> Option<Form> {
use apply::Apply;
// TODO: we need better serialization
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 {
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));
f
} 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 {
unimplemented!();
//f.text("reply_markup", );
f
} else { f });
Some(params)
}
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");
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);
}
}

View file

@ -1,3 +1,12 @@
#![feature(async_await)] #![feature(async_await)]
#[macro_use]
extern crate typed_builder;
#[macro_use]
extern crate derive_more;
#[macro_use]
extern crate serde;
mod core; mod core;