telbot_reqwest/
lib.rs

1use reqwest::{
2    multipart::{Form, Part},
3    Client, Response,
4};
5pub use telbot_types as types;
6use types::{ApiResponse, FileMethod, JsonMethod, TelegramError, TelegramMethod};
7
8#[derive(Clone)]
9pub struct Api {
10    base_url: String,
11    client: Client,
12}
13
14#[derive(Debug)]
15pub enum Error {
16    TelegramError(TelegramError),
17    Reqwest(reqwest::Error),
18}
19
20impl From<reqwest::Error> for Error {
21    fn from(e: reqwest::Error) -> Self {
22        Self::Reqwest(e)
23    }
24}
25
26pub type Result<T> = std::result::Result<T, Error>;
27
28impl Api {
29    pub fn new(token: impl AsRef<str>) -> Self {
30        Self {
31            base_url: format!("https://api.telegram.org/bot{}/", token.as_ref()),
32            client: Client::new(),
33        }
34    }
35
36    pub async fn send_json<Method: JsonMethod>(&self, method: &Method) -> Result<Method::Response> {
37        let url = format!("{}{}", self.base_url, Method::name());
38        let response = self.client.post(url).json(method).send().await?;
39        Self::parse_response::<Method>(response).await
40    }
41
42    pub async fn send_file<Method: FileMethod>(&self, method: &Method) -> Result<Method::Response> {
43        let url = format!("{}{}", self.base_url, Method::name());
44        let files = method.files();
45        let serialized = serde_json::to_value(method).unwrap();
46
47        let mut form = Form::new();
48        for (key, value) in serialized.as_object().unwrap() {
49            if let Some(file) = files.as_ref().and_then(|map| map.get(key.as_str())) {
50                form = form.part(
51                    key.to_string(),
52                    Part::bytes(file.data.clone())
53                        .file_name(file.name.clone())
54                        .mime_str(&file.mime)
55                        .unwrap(),
56                );
57            } else if let Some(value) = value.as_str() {
58                form = form.text(key.to_string(), value.to_string());
59            } else {
60                form = form.text(key.to_string(), value.to_string());
61            }
62        }
63
64        let response = self.client.post(url).multipart(form).send().await?;
65
66        Self::parse_response::<Method>(response).await
67    }
68
69    async fn parse_response<Method: TelegramMethod>(
70        response: Response,
71    ) -> Result<Method::Response> {
72        let tg_response: ApiResponse<_> = response.json().await?;
73        match tg_response {
74            ApiResponse::Ok { result } => Ok(result),
75            ApiResponse::Err(error) => Err(Error::TelegramError(error)),
76        }
77    }
78}