char/phoebe

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

videogame hackerForward images to Matrixe0731c2

legacy
12.0 KiB309 linesraw
1use std::{cell::RefCell, collections::HashSet, str::FromStr, sync::Mutex};
2
3use sled::Db;
4
5use crate::{
6    channels::ChannelReference,
7    discord::{
8        self, delete_on_discord, edit_on_discord, forward_image_to_discord, forward_to_discord,
9    },
10    matrix::{self, delete_on_matrix, edit_on_matrix, forward_image_to_matrix, forward_to_matrix},
11    messages::{DeletedMessage, EditedMessage, MessageReference, SentImageMessage, SentMessage},
12};
13
14pub struct Bridgers {
15    pub db: Db,
16    pub discord: Mutex<RefCell<Option<discord::Context>>>,
17    pub matrix: Mutex<RefCell<Option<matrix::Client>>>,
18}
19
20impl Bridgers {
21    pub fn new() -> Self {
22        let db = sled::open("data/phoebe.sled").expect("Failed to open database");
23
24        Self {
25            db,
26            discord: Mutex::new(RefCell::new(None)),
27            matrix: Mutex::new(RefCell::new(None)),
28        }
29    }
30
31    fn get_linked_discord_channel(&self, source: &MessageReference) -> Option<discord::ChannelId> {
32        let discord_channels = self
33            .db
34            .open_tree("discord_channels")
35            .expect("Failed to open discord channels tree");
36
37        match source {
38            MessageReference::Matrix(room_id, _) => {
39                let channel_ref = ChannelReference::Matrix(room_id.to_string());
40                let channel_ref = bincode::serialize(&channel_ref).unwrap();
41
42                discord_channels
43                    .get(channel_ref)
44                    .unwrap()
45                    .map(|bytes| bincode::deserialize::<u64>(&bytes).unwrap())
46                    .map(discord::ChannelId)
47            }
48            _ => None,
49        }
50    }
51
52    fn get_linked_matrix_room(&self, source: &MessageReference) -> Option<matrix::RoomId> {
53        let matrix_channels = self
54            .db
55            .open_tree("matrix_channels")
56            .expect("Failed to open matrix channels tree");
57
58        match source {
59            MessageReference::Discord(channel_id, _) => {
60                let channel_ref = ChannelReference::Discord(*channel_id);
61                let channel_ref = bincode::serialize(&channel_ref).unwrap();
62
63                matrix_channels
64                    .get(channel_ref)
65                    .unwrap()
66                    .map(|bytes| bincode::deserialize::<String>(&bytes).unwrap())
67                    .as_deref()
68                    .map(matrix::RoomId::from_str)
69                    .map(Result::unwrap)
70            }
71            _ => None,
72        }
73    }
74
75    fn get_related_messages(&self, source: &MessageReference) -> Option<Vec<MessageReference>> {
76        let message_relations = self
77            .db
78            .open_tree("message_relations")
79            .expect("Failed to open relations tree");
80
81        let key = bincode::serialize(source).expect("Failed to serialize message reference");
82        message_relations
83            .get(key)
84            .expect("Failed to retrieve message references")
85            .map(|r| {
86                bincode::deserialize::<Vec<MessageReference>>(&r)
87                    .expect("Failed to deserialize message references")
88            })
89    }
90
91    fn get_related_discord_message(&self, source: &MessageReference) -> Option<(u64, u64)> {
92        if let MessageReference::Discord(channel_id, message_id) = source {
93            return Some((*channel_id, *message_id));
94        }
95
96        if let Some(relations) = self.get_related_messages(source) {
97            for relation in relations {
98                if let MessageReference::Discord(channel_id, message_id) = relation {
99                    return Some((channel_id, message_id));
100                }
101            }
102        }
103
104        None
105    }
106
107    fn get_related_matrix_message(&self, source: &MessageReference) -> Option<matrix::EventId> {
108        if let MessageReference::Matrix(_, event_id) = source {
109            return Some(matrix::EventId::from_str(event_id).unwrap());
110        }
111
112        if let Some(relations) = self.get_related_messages(source) {
113            for relation in relations {
114                if let MessageReference::Matrix(_, event_id) = relation {
115                    return Some(matrix::EventId::from_str(&event_id).unwrap());
116                }
117            }
118        }
119
120        None
121    }
122
123    pub fn link_channels(&self, channels: &[ChannelReference]) {
124        let discord_channels = self
125            .db
126            .open_tree("discord_channels")
127            .expect("Failed to open discord channels tree");
128
129        let matrix_channels = self
130            .db
131            .open_tree("matrix_channels")
132            .expect("Failed to open matrix channels tree");
133
134        for channel in channels.iter() {
135            let other_channels = channels
136                .iter()
137                .filter(|r| r != &channel)
138                .collect::<Vec<_>>();
139
140            match channel {
141                ChannelReference::Discord(channel_id) => {
142                    for other_channel in other_channels {
143                        let key = bincode::serialize(other_channel).unwrap();
144                        let value = bincode::serialize(channel_id).unwrap();
145                        discord_channels.insert(key, value).unwrap();
146                    }
147                }
148                ChannelReference::Matrix(room_id) => {
149                    for other_channel in other_channels {
150                        let key = bincode::serialize(other_channel).unwrap();
151                        let value = bincode::serialize(room_id.as_str()).unwrap();
152                        matrix_channels.insert(key, value).unwrap();
153                    }
154                }
155            }
156        }
157    }
158
159    fn store_related_messages(&self, related_messages: &[MessageReference]) {
160        let tree = self
161            .db
162            .open_tree("message_relations")
163            .expect("Failed to open relations tree");
164
165        for source in related_messages {
166            let relations = related_messages
167                .iter()
168                .filter(|r| r != &source)
169                .collect::<Vec<_>>();
170
171            let key = bincode::serialize(source).expect("Failed to serialize message reference");
172            let value =
173                bincode::serialize(&relations).expect("Failed to serialize message relations");
174
175            tree.insert(key, value)
176                .expect("Failed to store message relations");
177        }
178    }
179
180    pub async fn send_message(&self, message: SentMessage) {
181        if self.get_related_messages(&message.source).is_some() {
182            return;
183        }
184
185        let mut related_messages = vec![message.source.clone()];
186
187        if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() {
188            if let Some(channel) = self.get_linked_discord_channel(&message.source) {
189                let reply = message
190                    .replies_to
191                    .as_ref()
192                    .and_then(|r| self.get_related_discord_message(r));
193
194                if let Some(m) = forward_to_discord(discord, channel, &message, reply).await {
195                    related_messages.push(m);
196                }
197            }
198        }
199
200        if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
201            if let Some(room_id) = self.get_linked_matrix_room(&message.source) {
202                let reply = message
203                    .replies_to
204                    .as_ref()
205                    .and_then(|r| self.get_related_matrix_message(r));
206
207                if let Some(m) = forward_to_matrix(matrix, room_id, &message, reply).await {
208                    related_messages.push(m);
209                }
210            }
211        }
212
213        self.store_related_messages(&related_messages);
214    }
215
216    pub async fn edit_message(&self, message: EditedMessage) {
217        if let Some(related_messages) = self.get_related_messages(&message.replacing) {
218            let mut new_related_messages = HashSet::new();
219            related_messages.iter().for_each(|r| {
220                new_related_messages.insert(r.clone());
221            });
222
223            for related_message in related_messages.iter() {
224                match related_message {
225                    MessageReference::Discord(channel_id, message_id) => {
226                        if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() {
227                            let channel_id = discord::ChannelId(*channel_id);
228                            let message_id = discord::MessageId(*message_id);
229
230                            if let Some(m) =
231                                edit_on_discord(discord, channel_id, message_id, &message).await
232                            {
233                                new_related_messages.insert(m);
234                            }
235                        }
236                    }
237                    MessageReference::Matrix(room_id, event_id) => {
238                        if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
239                            let room_id = matrix::RoomId::from_str(room_id).unwrap();
240                            let event_id = matrix::EventId::from_str(event_id).unwrap();
241
242                            if let Some(m) =
243                                edit_on_matrix(matrix, room_id, event_id, &message).await
244                            {
245                                new_related_messages.insert(m);
246                            }
247                        }
248                    }
249                }
250            }
251
252            self.store_related_messages(&new_related_messages.into_iter().collect::<Vec<_>>())
253        }
254    }
255
256    pub async fn delete_message(&self, message: DeletedMessage) {
257        if let Some(related_messages) = self.get_related_messages(&message.reference) {
258            for related_message in related_messages.iter() {
259                match related_message {
260                    MessageReference::Discord(channel_id, message_id) => {
261                        if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() {
262                            let channel_id = discord::ChannelId(*channel_id);
263                            let message_id = discord::MessageId(*message_id);
264
265                            let _success =
266                                delete_on_discord(discord, channel_id, message_id, &message).await;
267                        }
268                    }
269                    MessageReference::Matrix(room_id, event_id) => {
270                        if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
271                            let room_id = matrix::RoomId::from_str(room_id).unwrap();
272                            let event_id = matrix::EventId::from_str(event_id).unwrap();
273
274                            let _success =
275                                delete_on_matrix(matrix, room_id, event_id, &message).await;
276                        }
277                    }
278                }
279            }
280        }
281    }
282
283    pub async fn send_image(&self, message: SentImageMessage) {
284        if self.get_related_messages(&message.source).is_some() {
285            return;
286        }
287
288        let mut related_messages = vec![message.source.clone()];
289
290        if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() {
291            if let Some(discord_channel) = self.get_linked_discord_channel(&message.source) {
292                if let Some(m) = forward_image_to_discord(discord, discord_channel, &message).await
293                {
294                    related_messages.push(m);
295                }
296            }
297        }
298
299        if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
300            if let Some(room_id) = self.get_linked_matrix_room(&message.source) {
301                if let Some(m) = forward_image_to_matrix(matrix, room_id, &message).await {
302                    related_messages.push(m);
303                }
304            }
305        }
306
307        self.store_related_messages(&related_messages);
308    }
309}