telegram_api/
lib.rs

1use reqwest::{Client, Error as ReqwestError};
2use serde::{Deserialize, Serialize};
3use std::time::Duration;
4
5const BASE_URL: &str = "https://api.telegram.org/bot";
6
7#[derive(Debug)]
8pub enum TelegramError {
9    RequestError(ReqwestError),
10    ApiError(String),
11}
12
13impl From<ReqwestError> for TelegramError {
14    fn from(error: ReqwestError) -> Self {
15        TelegramError::RequestError(error)
16    }
17}
18
19#[derive(Debug, Deserialize)]
20pub struct Update {
21    pub update_id: i64,
22    pub message: Option<Message>,
23}
24
25#[derive(Debug, Deserialize)]
26pub struct Message {
27    pub message_id: i64,
28    pub from: Option<User>,
29    pub chat: Chat,
30    pub text: Option<String>,
31}
32
33#[derive(Debug, Deserialize)]
34pub struct User {
35    pub id: i64,
36    pub first_name: String,
37    pub last_name: Option<String>,
38    pub username: Option<String>,
39}
40
41#[derive(Debug, Deserialize)]
42pub struct Chat {
43    pub id: i64,
44    pub chat_type: String,
45    pub title: Option<String>,
46    pub username: Option<String>,
47}
48
49#[derive(Debug, Serialize)]
50pub struct SendMessageRequest {
51    pub chat_id: i64,
52    pub text: String,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub reply_to_message_id: Option<i64>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub parse_mode: Option<String>,
57}
58
59pub struct Bot {
60    token: String,
61    client: Client,
62}
63
64impl Bot {
65    pub fn new(token: String) -> Result<Self, TelegramError> {
66        let client = Client::builder().timeout(Duration::from_secs(30)).build()?;
67
68        Ok(Bot { token, client })
69    }
70
71    fn api_url(&self, method: &str) -> String {
72        format!("{}{}/{}", BASE_URL, self.token, method)
73    }
74
75    pub async fn get_updates(&self, offset: Option<i64>) -> Result<Vec<Update>, TelegramError> {
76        let mut url = self.api_url("getUpdates");
77        if let Some(offset) = offset {
78            url = format!("{}?offset={}", url, offset);
79        }
80
81        let response = self
82            .client
83            .get(&url)
84            .send()
85            .await?
86            .json::<serde_json::Value>()
87            .await?;
88
89        if let Some(ok) = response.get("ok").and_then(|v| v.as_bool()) {
90            if !ok {
91                return Err(TelegramError::ApiError(
92                    response
93                        .get("description")
94                        .and_then(|v| v.as_str())
95                        .unwrap_or("Unknown API error")
96                        .to_string(),
97                ));
98            }
99        }
100
101        let updates = response
102            .get("result")
103            .and_then(|v| serde_json::from_value::<Vec<Update>>(v.clone()).ok())
104            .unwrap_or_default();
105
106        Ok(updates)
107    }
108
109    pub async fn send_message(
110        &self,
111        request: SendMessageRequest,
112    ) -> Result<Message, TelegramError> {
113        let url = self.api_url("sendMessage");
114
115        let response = self
116            .client
117            .post(&url)
118            .json(&request)
119            .send()
120            .await?
121            .json::<serde_json::Value>()
122            .await?;
123
124        if let Some(ok) = response.get("ok").and_then(|v| v.as_bool()) {
125            if !ok {
126                return Err(TelegramError::ApiError(
127                    response
128                        .get("description")
129                        .and_then(|v| v.as_str())
130                        .unwrap_or("Unknown API error")
131                        .to_string(),
132                ));
133            }
134        }
135
136        let message = response
137            .get("result")
138            .and_then(|v| serde_json::from_value::<Message>(v.clone()).ok())
139            .ok_or_else(|| {
140                TelegramError::ApiError("Failed to parse message response".to_string())
141            })?;
142
143        Ok(message)
144    }
145}