tg_flows/api/
mod.rs

1mod method;
2
3use std::collections::HashMap;
4
5use anyhow::{anyhow, Context, Result};
6use http_req::{request::Request, uri::Uri};
7use serde::{de::DeserializeOwned, Serialize};
8use serde_json::Value;
9
10use crate::{
11    Chat, ChatId, ChatInviteLink, ChatMember, ChatPermissions, File, InputFile, Me, Message,
12    MessageId, ParseMode, True, UserId, UserProfilePhotos,
13};
14
15pub use self::method::Method;
16
17const BASE_URL: &str = "https://api.telegram.org/bot";
18
19pub struct Telegram {
20    base_url: &'static str,
21    token: String,
22}
23
24impl Telegram {
25    pub fn new(token: String) -> Self {
26        Self {
27            base_url: BASE_URL,
28            token,
29        }
30    }
31
32    pub fn new_with_base_url(token: String, base_url: &'static str) -> Self {
33        Self { base_url, token }
34    }
35}
36
37impl Telegram {
38    pub fn request<T>(&self, method: Method, body: &[u8]) -> Result<T>
39    where
40        T: DeserializeOwned,
41    {
42        let url = format!("{}{}/{}", self.base_url, self.token, method.to_string());
43        let uri = Uri::try_from(url.as_str())?;
44
45        let mut writer = Vec::new();
46        Request::new(&uri)
47            .header("Content-Type", "application/json")
48            .header("Content-Length", &body.len())
49            .body(body)
50            .send(&mut writer)?;
51
52        let value = serde_json::from_str::<Value>(&String::from_utf8(writer)?)?;
53
54        let result = value
55            .get("result")
56            .ok_or(anyhow!("tg api returned without result"))?;
57        let t: T = serde_json::from_value(result.clone())?;
58
59        Ok(t)
60    }
61
62    pub fn request_with_attach<T, S>(
63        &self,
64        method: Method,
65        query: HashMap<S, S>,
66        body: &[u8],
67    ) -> Result<T>
68    where
69        T: DeserializeOwned,
70        S: Serialize,
71    {
72        let mut url = format!("{}{}/{}", self.base_url, self.token, method.to_string());
73        if !query.is_empty() {
74            let mut iter = query.iter();
75            let (k, v) = iter.next().unwrap();
76            let k = serde_json::to_string(k).context("query key serialize error")?;
77            let v = serde_json::to_string(v).context("query value serialize error")?;
78
79            url += &format!("?{k}={v}");
80
81            for (k, v) in iter {
82                let k = serde_json::to_string(k).context("query key serialize error")?;
83                let v = serde_json::to_string(v).context("query value serialize error")?;
84                url += &format!("&{k}={v}");
85            }
86        }
87
88        let uri = Uri::try_from(url.as_str())?;
89
90        let mut writer = Vec::new();
91        Request::new(&uri)
92            .header("Content-Type", "multipart/form-data")
93            .header("Content-Length", &body.len())
94            .body(body)
95            .send(&mut writer)?;
96
97        let value = serde_json::from_str::<Value>(&String::from_utf8(writer)?)?;
98
99        let result = value
100            .get("result")
101            .ok_or(anyhow!("tg api returned without result"))?;
102        let t: T = serde_json::from_value(result.clone())?;
103
104        Ok(t)
105    }
106}
107
108// TODO: general & meaningful api
109impl Telegram {
110    pub fn get_me(&self) -> Result<Me> {
111        self.request(Method::GetMe, &[])
112    }
113
114    pub fn log_out(&self) -> Result<True> {
115        self.request(Method::LogOut, &[])
116    }
117
118    pub fn close(&self) -> Result<True> {
119        self.request(Method::Close, &[])
120    }
121
122    pub fn send_message<T>(&self, chat_id: ChatId, text: T) -> Result<Message>
123    where
124        T: Into<String>,
125    {
126        let text: String = text.into();
127        let body = serde_json::json!({
128            "chat_id": chat_id,
129            "text": text,
130        });
131        self.request(Method::SendMessage, body.to_string().as_bytes())
132    }
133
134    pub fn send_message_with_parse_mode<T>(
135        &self,
136        chat_id: ChatId,
137        text: T,
138        parse_mode: ParseMode,
139    ) -> Result<Message>
140    where
141        T: Into<String>,
142    {
143        let text: String = text.into();
144        let body = serde_json::json!({
145            "chat_id": chat_id,
146            "text": text,
147            "parse_mode": parse_mode,
148        });
149        self.request(Method::SendMessage, body.to_string().as_bytes())
150    }
151
152    pub fn forward_message(&self, chat_id: ChatId, from_chat_id: ChatId) -> Result<Message> {
153        let body = serde_json::json!({
154            "chat_id": chat_id,
155            "from_chat_id": from_chat_id,
156        });
157        self.request(Method::ForwardMessage, body.to_string().as_bytes())
158    }
159
160    pub fn copy_message(
161        &self,
162        chat_id: ChatId,
163        from_chat_id: ChatId,
164        message_id: MessageId,
165    ) -> Result<Message> {
166        let body = serde_json::json!({
167            "chat_id": chat_id,
168            "from_chat_id": from_chat_id,
169            "message_id": message_id,
170        });
171        self.request(Method::CopyMessage, body.to_string().as_bytes())
172    }
173
174    // TODO: multipart request support
175    pub fn send_photo(&self, chat_id: ChatId, photo: InputFile) -> Result<Message> {
176        if photo.needs_attach() {
177            panic!("unsupport attach currently")
178        } else {
179            let body = serde_json::json!({
180                "chat_id": chat_id,
181                "photo": photo,
182            });
183            self.request(Method::SendPhoto, body.to_string().as_bytes())
184        }
185    }
186
187    pub fn send_audio(&self, chat_id: ChatId, audio: InputFile) -> Result<Message> {
188        if audio.needs_attach() {
189            panic!("unsupport attach currently")
190        } else {
191            let body = serde_json::json!({
192                "chat_id": chat_id,
193                "audio": audio,
194            });
195            self.request(Method::SendAudio, body.to_string().as_bytes())
196        }
197    }
198
199    pub fn send_document(&self, chat_id: ChatId, document: InputFile) -> Result<Message> {
200        if document.needs_attach() {
201            panic!("unsupport attach currently")
202        } else {
203            let body = serde_json::json!({
204                "chat_id": chat_id,
205                "document": document,
206            });
207            self.request(Method::SendDocument, body.to_string().as_bytes())
208        }
209    }
210
211    pub fn send_video(&self, chat_id: ChatId, video: InputFile) -> Result<Message> {
212        if video.needs_attach() {
213            panic!("unsupport attach currently")
214        } else {
215            let body = serde_json::json!({
216                "chat_id": chat_id,
217                "video": video,
218            });
219            self.request(Method::SendVideo, body.to_string().as_bytes())
220        }
221    }
222
223    pub fn send_animation(&self, chat_id: ChatId, animation: InputFile) -> Result<Message> {
224        if animation.needs_attach() {
225            panic!("unsupport attach currently")
226        } else {
227            let body = serde_json::json!({
228                "chat_id": chat_id,
229                "animation": animation,
230            });
231            self.request(Method::SendAnimation, body.to_string().as_bytes())
232        }
233    }
234
235    pub fn send_voice(&self, chat_id: ChatId, voice: InputFile) -> Result<Message> {
236        if voice.needs_attach() {
237            panic!("unsupport attach currently")
238        } else {
239            let body = serde_json::json!({
240                "chat_id": chat_id,
241                "voice": voice,
242            });
243            self.request(Method::SendVoice, body.to_string().as_bytes())
244        }
245    }
246
247    pub fn send_video_note(&self, chat_id: ChatId, video_note: InputFile) -> Result<Message> {
248        if video_note.needs_attach() {
249            panic!("unsupport attach currently")
250        } else {
251            let body = serde_json::json!({
252                "chat_id": chat_id,
253                "video_note": video_note,
254            });
255            self.request(Method::SendVideoNote, body.to_string().as_bytes())
256        }
257    }
258
259    // pub fn send_media_group(&self, chat_id: ChatId, media: vec![])
260
261    pub fn send_location(&self, chat_id: ChatId, latitude: f32, longitude: f32) -> Result<Message> {
262        let body = serde_json::json!({
263            "chat_id": chat_id,
264            "latitude": latitude,
265            "longitude": longitude,
266        });
267        self.request(Method::SendLocation, body.to_string().as_bytes())
268    }
269
270    pub fn send_venue(
271        &self,
272        chat_id: ChatId,
273        latitude: f32,
274        longitude: f32,
275        title: String,
276        address: String,
277    ) -> Result<Message> {
278        let body = serde_json::json!({
279            "chat_id": chat_id,
280            "latitude": latitude,
281            "longitude": longitude,
282            "title": title,
283            "address": address,
284        });
285        self.request(Method::SendLocation, body.to_string().as_bytes())
286    }
287
288    pub fn send_contract(
289        &self,
290        chat_id: ChatId,
291        photo_number: String,
292        first_name: String,
293    ) -> Result<Message> {
294        let body = serde_json::json!({
295            "chat_id": chat_id,
296            "photo_number":photo_number,
297            "first_name": first_name,
298        });
299        self.request(Method::SendContract, body.to_string().as_bytes())
300    }
301
302    pub fn send_poll(
303        &self,
304        chat_id: ChatId,
305        question: String,
306        options: Vec<String>,
307    ) -> Result<Message> {
308        let body = serde_json::json!({
309            "chat_id": chat_id,
310            "question": question,
311            "options": options,
312        });
313        self.request(Method::SendPoll, body.to_string().as_bytes())
314    }
315
316    pub fn send_dice(&self, chat_id: ChatId) -> Result<Message> {
317        let body = serde_json::json!({
318            "chat_id": chat_id,
319        });
320        self.request(Method::SendDice, body.to_string().as_bytes())
321    }
322
323    pub fn send_chat_action(&self, chat_id: ChatId, action: String) -> Result<Message> {
324        let body = serde_json::json!({
325            "chat_id": chat_id,
326            "action": action,
327        });
328        self.request(Method::SendChatAction, body.to_string().as_bytes())
329    }
330
331    pub fn get_user_profile_photos(&self, user_id: UserId) -> Result<UserProfilePhotos> {
332        let body = serde_json::json!({
333            "user_id": user_id,
334        });
335        self.request(Method::GetUserProfilePhotos, body.to_string().as_bytes())
336    }
337
338    pub fn get_file(&self, file_id: String) -> Result<File> {
339        let body = serde_json::json!({
340            "file_id": file_id,
341        });
342        self.request(Method::GetFile, body.to_string().as_bytes())
343    }
344
345    pub fn ban_chat_member(&self, chat_id: ChatId, user_id: UserId) -> Result<True> {
346        let body = serde_json::json!({
347            "chat_id": chat_id,
348            "user_id": user_id,
349        });
350        self.request(Method::BanChatMember, body.to_string().as_bytes())
351    }
352
353    pub fn unban_chat_member(&self, chat_id: ChatId, user_id: UserId) -> Result<True> {
354        let body = serde_json::json!({
355            "chat_id": chat_id,
356            "user_id": user_id,
357        });
358        self.request(Method::UnbanChatMember, body.to_string().as_bytes())
359    }
360
361    pub fn restrict_chat_member(
362        &self,
363        chat_id: ChatId,
364        user_id: UserId,
365        permissions: ChatPermissions,
366    ) -> Result<True> {
367        let body = serde_json::json!({
368            "chat_id": chat_id,
369            "user_id": user_id,
370            "permissions": permissions,
371        });
372        self.request(Method::RestrictChatMember, body.to_string().as_bytes())
373    }
374
375    pub fn promote_chat_member(&self, chat_id: ChatId, user_id: UserId) -> Result<True> {
376        let body = serde_json::json!({
377            "chat_id": chat_id,
378            "user_id": user_id,
379        });
380        self.request(Method::PromoteChatMember, body.to_string().as_bytes())
381    }
382
383    pub fn set_chat_administrator_custom_title(
384        &self,
385        chat_id: ChatId,
386        user_id: UserId,
387        custom_title: String,
388    ) -> Result<True> {
389        let body = serde_json::json!({
390            "chat_id": chat_id,
391            "user_id": user_id,
392            "custom_title": custom_title,
393        });
394        self.request(
395            Method::SetChatAdministratorCustomTitle,
396            body.to_string().as_bytes(),
397        )
398    }
399
400    pub fn ban_chat_sender_chat(&self, chat_id: ChatId, sender_chat_id: i32) -> Result<True> {
401        let body = serde_json::json!({
402            "chat_id": chat_id,
403            "sender_chat_id": sender_chat_id,
404        });
405        self.request(Method::BanChatSenderChat, body.to_string().as_bytes())
406    }
407
408    pub fn unban_chat_sender_chat(&self, chat_id: ChatId, sender_chat_id: i32) -> Result<True> {
409        let body = serde_json::json!({
410            "chat_id": chat_id,
411            "sender_chat_id": sender_chat_id,
412        });
413        self.request(Method::UnbanChatSenderChat, body.to_string().as_bytes())
414    }
415
416    pub fn set_chat_permissions(
417        &self,
418        chat_id: ChatId,
419        permissions: ChatPermissions,
420    ) -> Result<True> {
421        let body = serde_json::json!({
422            "chat_id": chat_id,
423            "permissions": permissions,
424        });
425        self.request(Method::SetChatPermissions, body.to_string().as_bytes())
426    }
427
428    pub fn export_chat_invite_link(&self, chat_id: ChatId) -> Result<String> {
429        let body = serde_json::json!({
430            "chat_id": chat_id,
431        });
432        self.request(Method::ExportChatInviteLink, body.to_string().as_bytes())
433    }
434
435    pub fn create_chat_invite_link(&self, chat_id: ChatId) -> Result<ChatInviteLink> {
436        let body = serde_json::json!({
437            "chat_id": chat_id,
438        });
439        self.request(Method::CreateChatInviteLink, body.to_string().as_bytes())
440    }
441
442    pub fn edit_chat_invite_link(
443        &self,
444        chat_id: ChatId,
445        invite_link: String,
446    ) -> Result<ChatInviteLink> {
447        let body = serde_json::json!({
448            "chat_id": chat_id,
449            "invite_link": invite_link,
450        });
451        self.request(Method::EditChatInviteLink, body.to_string().as_bytes())
452    }
453
454    pub fn revoke_chat_invite_link(
455        &self,
456        chat_id: ChatId,
457        invite_link: String,
458    ) -> Result<ChatInviteLink> {
459        let body = serde_json::json!({
460            "chat_id": chat_id,
461            "invite_link": invite_link,
462        });
463        self.request(Method::RevokeChatInviteLink, body.to_string().as_bytes())
464    }
465
466    pub fn approve_chat_join_request(&self, chat_id: ChatId, user_id: UserId) -> Result<True> {
467        let body = serde_json::json!({
468            "chat_id": chat_id,
469            "user_id": user_id,
470        });
471        self.request(Method::ApproveChatJoinRequest, body.to_string().as_bytes())
472    }
473
474    pub fn decline_chat_join_request(&self, chat_id: ChatId, user_id: UserId) -> Result<True> {
475        let body = serde_json::json!({
476            "chat_id": chat_id,
477            "user_id": user_id,
478        });
479        self.request(Method::DeclineChatJoinRequest, body.to_string().as_bytes())
480    }
481
482    pub fn set_chat_photo(&self, chat_id: ChatId, photo: InputFile) -> Result<True> {
483        if photo.needs_attach() {
484            panic!("unsupport attach currently");
485        } else {
486            let body = serde_json::json!({
487                "chat_id": chat_id,
488                "photo": photo,
489            });
490            self.request(Method::SetChatPhoto, body.to_string().as_bytes())
491        }
492    }
493
494    pub fn delete_chat_photo(&self, chat_id: ChatId) -> Result<True> {
495        let body = serde_json::json!({
496            "chat_id": chat_id,
497        });
498        self.request(Method::DeleteChatPhoto, body.to_string().as_bytes())
499    }
500
501    pub fn set_chat_title(&self, chat_id: ChatId, title: String) -> Result<True> {
502        let body = serde_json::json!({
503            "chat_id": chat_id,
504            "title": title,
505        });
506        self.request(Method::SetChatTitle, body.to_string().as_bytes())
507    }
508
509    pub fn set_chat_description(&self, chat_id: ChatId) -> Result<True> {
510        let body = serde_json::json!({
511            "chat_id": chat_id,
512        });
513        self.request(Method::SetChatDescription, body.to_string().as_bytes())
514    }
515
516    pub fn pin_chat_message(&self, chat_id: ChatId, message_id: i32) -> Result<True> {
517        let body = serde_json::json!({
518            "chat_id": chat_id,
519            "message_id": message_id,
520        });
521        self.request(Method::PinChatMessage, body.to_string().as_bytes())
522    }
523
524    pub fn unpin_chat_message(&self, chat_id: ChatId) -> Result<True> {
525        let body = serde_json::json!({
526            "chat_id": chat_id,
527        });
528        self.request(Method::UnpinChatMessage, body.to_string().as_bytes())
529    }
530
531    pub fn unpin_all_chat_message(&self, chat_id: ChatId) -> Result<True> {
532        let body = serde_json::json!({
533            "chat_id": chat_id,
534        });
535        self.request(Method::UnpinAllChatMessages, body.to_string().as_bytes())
536    }
537
538    pub fn leave_chat(&self, chat_id: ChatId) -> Result<True> {
539        let body = serde_json::json!({
540            "chat_id": chat_id,
541        });
542        self.request(Method::LeaveChat, body.to_string().as_bytes())
543    }
544
545    pub fn get_chat(&self, chat_id: ChatId) -> Result<Chat> {
546        let body = serde_json::json!({
547            "chat_id": chat_id,
548        });
549        self.request(Method::GetChat, body.to_string().as_bytes())
550    }
551
552    pub fn get_chat_administrators(&self, chat_id: ChatId) -> Result<ChatMember> {
553        let body = serde_json::json!({
554            "chat_id": chat_id,
555        });
556        self.request(Method::GetChatAdministrators, body.to_string().as_bytes())
557    }
558
559    pub fn get_chat_member_count(&self, chat_id: ChatId) -> Result<i32> {
560        let body = serde_json::json!({
561            "chat_id": chat_id,
562        });
563        self.request(Method::GetChatMemberCount, body.to_string().as_bytes())
564    }
565
566    pub fn get_chat_member(&self, chat_id: ChatId, user_id: UserId) -> Result<ChatMember> {
567        let body = serde_json::json!({
568            "chat_id": chat_id,
569            "user_id": user_id,
570        });
571        self.request(Method::GetChatMember, body.to_string().as_bytes())
572    }
573
574    // TODO: https://core.telegram.org/bots/api#setchatstickerset
575
576    pub fn edit_message_text<T>(
577        &self,
578        chat_id: ChatId,
579        message_id: MessageId,
580        text: T,
581    ) -> Result<Message>
582    where
583        T: Into<String>,
584    {
585        let text = text.into();
586        let body = serde_json::json!({
587            "chat_id": chat_id,
588            "message_id": message_id.0,
589            "text": text,
590        });
591        self.request(Method::EditMessageText, body.to_string().as_bytes())
592    }
593
594    pub fn edit_message_text_with_parse_mode<T>(
595        &self,
596        chat_id: ChatId,
597        message_id: MessageId,
598        text: T,
599        parse_mode: ParseMode,
600    ) -> Result<Message>
601    where
602        T: Into<String>,
603    {
604        let text = text.into();
605        let body = serde_json::json!({
606            "chat_id": chat_id,
607            "message_id": message_id.0,
608            "text": text,
609            "parse_mode": parse_mode,
610        });
611        self.request(Method::EditMessageText, body.to_string().as_bytes())
612    }
613
614    pub fn delete_message(&self, chat_id: ChatId, message_id: MessageId) -> Result<True> {
615        let body = serde_json::json!({
616            "chat_id": chat_id,
617            "message_id": message_id.0,
618        });
619        self.request(Method::DeleteMessage, body.to_string().as_bytes())
620    }
621
622    pub fn delete_messages(&self, chat_id: ChatId, message_ids: Vec<MessageId>) -> Result<True> {
623        let body = serde_json::json!({
624            "chat_id": chat_id,
625            "message_ids": message_ids.iter().map(|id| id.0).collect::<Vec<i32>>(),
626        });
627        self.request(Method::DeleteMessages, body.to_string().as_bytes())
628    }
629}