Skip to main content

garudust_platforms/
telegram.rs

1use std::pin::Pin;
2use std::sync::Arc;
3
4use async_trait::async_trait;
5use futures::Stream;
6use garudust_core::{
7    error::PlatformError,
8    platform::{MessageHandler, PlatformAdapter},
9    types::{ChannelId, InboundMessage, OutboundMessage},
10};
11use teloxide::prelude::*;
12
13pub struct TelegramAdapter {
14    bot: Bot,
15}
16
17impl TelegramAdapter {
18    pub fn new(token: String) -> Self {
19        Self {
20            bot: Bot::new(token),
21        }
22    }
23}
24
25#[async_trait]
26impl PlatformAdapter for TelegramAdapter {
27    fn name(&self) -> &'static str {
28        "telegram"
29    }
30
31    async fn start(&self, handler: Arc<dyn MessageHandler>) -> Result<(), PlatformError> {
32        let bot = self.bot.clone();
33        tokio::spawn(async move {
34            teloxide::repl(bot, move |_bot: Bot, msg: Message| {
35                let handler = handler.clone();
36                async move {
37                    if let Some(text) = msg.text() {
38                        let is_group = msg.chat.is_group() || msg.chat.is_supergroup();
39                        let inbound = InboundMessage {
40                            channel: ChannelId {
41                                platform: "telegram".into(),
42                                chat_id: msg.chat.id.to_string(),
43                                thread_id: None,
44                            },
45                            user_id: msg
46                                .from
47                                .as_ref()
48                                .map(|u| u.id.to_string())
49                                .unwrap_or_default(),
50                            user_name: msg
51                                .from
52                                .as_ref()
53                                .and_then(|u| u.username.clone())
54                                .unwrap_or_default(),
55                            text: text.to_string(),
56                            session_key: format!("telegram:{}", msg.chat.id),
57                            is_group,
58                            bot_mentioned: None,
59                        };
60                        let _ = handler.handle(inbound).await;
61                    }
62                    respond(())
63                }
64            })
65            .await;
66        });
67        Ok(())
68    }
69
70    async fn send_message(
71        &self,
72        channel: &ChannelId,
73        message: OutboundMessage,
74    ) -> Result<(), PlatformError> {
75        let chat_id: i64 = channel
76            .chat_id
77            .parse()
78            .map_err(|_| PlatformError::Send("invalid chat_id".into()))?;
79        self.bot
80            .send_message(ChatId(chat_id), &message.text)
81            .await
82            .map_err(|e| PlatformError::Send(e.to_string()))?;
83        Ok(())
84    }
85
86    async fn send_stream(
87        &self,
88        channel: &ChannelId,
89        mut stream: Pin<Box<dyn Stream<Item = String> + Send>>,
90    ) -> Result<(), PlatformError> {
91        use futures::StreamExt;
92        let mut buf = String::new();
93        while let Some(chunk) = stream.next().await {
94            buf.push_str(&chunk);
95        }
96        self.send_message(channel, OutboundMessage::text(buf)).await
97    }
98}