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                        };
59                        let _ = handler.handle(inbound).await;
60                    }
61                    respond(())
62                }
63            })
64            .await;
65        });
66        Ok(())
67    }
68
69    async fn send_message(
70        &self,
71        channel: &ChannelId,
72        message: OutboundMessage,
73    ) -> Result<(), PlatformError> {
74        let chat_id: i64 = channel
75            .chat_id
76            .parse()
77            .map_err(|_| PlatformError::Send("invalid chat_id".into()))?;
78        self.bot
79            .send_message(ChatId(chat_id), &message.text)
80            .await
81            .map_err(|e| PlatformError::Send(e.to_string()))?;
82        Ok(())
83    }
84
85    async fn send_stream(
86        &self,
87        channel: &ChannelId,
88        mut stream: Pin<Box<dyn Stream<Item = String> + Send>>,
89    ) -> Result<(), PlatformError> {
90        use futures::StreamExt;
91        let mut buf = String::new();
92        while let Some(chunk) = stream.next().await {
93            buf.push_str(&chunk);
94        }
95        self.send_message(channel, OutboundMessage::text(buf)).await
96    }
97}