char/phoebe

git clone https://git.t4t.associates/char/phoebe

videogame hackerAdd message editing support & impl for Discord4fc8c15

main
4.5 KiB147 linesraw
1use phoebe::{get_message_link_id, mid_chat::*, prelude::*};
2use serenity::{
3    client::{Context, EventHandler},
4    model::prelude::*,
5};
6use tracing::debug;
7
8use crate::discord_reference;
9
10pub struct DiscordHandler {
11    pub core_db: SqlitePool,
12    pub discord_media_db: SqlitePool,
13    pub chat_event_tx: ChatEventSender,
14    pub ctx_tx: tokio::sync::mpsc::UnboundedSender<Context>,
15}
16
17impl DiscordHandler {
18    async fn get_author(&self, ctx: &Context, message: &Message) -> ChatAuthor {
19        let display_name = message
20            .author_nick(ctx)
21            .await
22            .unwrap_or_else(|| message.author.name.clone());
23
24        async fn tag_color(ctx: &Context, message: &Message) -> Option<[u8; 3]> {
25            let color = message.member(ctx).await.ok()?.colour(ctx).await?;
26            Some([color.r(), color.b(), color.g()])
27        }
28
29        let display_color = tag_color(ctx, message).await;
30
31        let avatar_url = message
32            .author
33            .static_avatar_url()
34            .unwrap_or_else(|| message.author.default_avatar_url());
35
36        ChatAuthor {
37            reference: discord_reference(message.author.id),
38            display_name,
39            display_color,
40            avatar: ChatAttachment::Online {
41                media_type: None,
42                url: avatar_url,
43            },
44        }
45    }
46}
47
48#[async_trait]
49impl EventHandler for DiscordHandler {
50    async fn ready(&self, ctx: Context, _ready: Ready) {
51        debug!("Discord signalled ready!");
52        let _ = self.ctx_tx.send(ctx);
53    }
54
55    async fn message(&self, ctx: Context, message: Message) {
56        let origin = ChatMessageReference::new(discord_reference(message.channel_id), message.id);
57
58        // skip messages linked to ones we have already seen
59        if let Ok(mut conn) = self.core_db.acquire().await {
60            if get_message_link_id(&mut conn, &origin).await.is_ok() {
61                return;
62            }
63        }
64
65        let author = self.get_author(&ctx, &message).await;
66
67        let content = discord_message_format::parse(&message.content);
68        let content = super::chat_conv::convert(&content);
69
70        let replies_to = message
71            .referenced_message
72            .as_ref()
73            .map(|m| ChatMessageReference::new(discord_reference(m.channel_id), m.id));
74
75        let attachments = message
76            .attachments
77            .into_iter()
78            .map(|a| ChatAttachment::Online {
79                media_type: a.content_type,
80                url: a.url,
81            })
82            .collect::<Vec<_>>();
83
84        let chat_message = ChatMessage {
85            origin,
86            author,
87            content,
88            attachments,
89            replying: replies_to,
90        };
91
92        let _ = self
93            .chat_event_tx
94            .send(ChatEvent::NewMessage(Box::new(chat_message)))
95            .expect("Failed to dispatch incoming Discord chat message");
96    }
97
98    async fn message_delete(
99        &self,
100        _ctx: Context,
101        channel_id: ChannelId,
102        deleted_message_id: MessageId,
103        _guild_id: Option<GuildId>,
104    ) {
105        let origin = ChatMessageReference::new(discord_reference(channel_id), deleted_message_id);
106        let _ = self
107            .chat_event_tx
108            .send(ChatEvent::DeleteMessage(origin))
109            .expect("Failed to dispatch incoming Discord chat message deletion");
110    }
111
112    async fn message_update(
113        &self,
114        ctx: Context,
115        _old_if_available: Option<Message>,
116        new: Option<Message>,
117        event: MessageUpdateEvent,
118    ) {
119        if let Ok(new_message) = {
120            if let Some(m) = new {
121                Ok(m)
122            } else {
123                event.channel_id.message(&ctx, event.id).await
124            }
125        } {
126            let origin = ChatMessageReference::new(
127                discord_reference(new_message.channel_id),
128                new_message.id,
129            );
130            let author = self.get_author(&ctx, &new_message).await;
131
132            let content = discord_message_format::parse(&new_message.content);
133            let content = super::chat_conv::convert(&content);
134
135            let edit = ChatMessageEdit {
136                origin: origin.clone(),
137                author,
138                new_content: content,
139            };
140
141            let _ = self
142                .chat_event_tx
143                .send(ChatEvent::EditMessage(origin, Box::new(edit)))
144                .expect("Failed to dispatch incoming Discord chat message update");
145        }
146    }
147}