tuwunel_core/matrix/pdu/
unsigned.rs1use std::collections::BTreeMap;
2
3use ruma::{
4 MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedUserId,
5 events::{AnySyncMessageLikeEvent, room::member::MembershipState},
6 serde::Raw,
7};
8use serde::{Deserialize, Serialize};
9use serde_json::value::{RawValue as RawJsonValue, Value as JsonValue, to_raw_value};
10
11use super::{Pdu, Unsigned};
12use crate::{Result, err, implement, utils::BoolExt};
13
14#[implement(Pdu)]
19pub fn remove_transaction_id(&mut self) -> Result {
20 use BTreeMap as Map;
21
22 let Some(unsigned) = &self.unsigned else {
23 return Ok(());
24 };
25
26 let mut unsigned: Map<&str, Raw<JsonValue>> = serde_json::from_str(unsigned.json().get())
27 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
28
29 unsigned.remove("transaction_id");
30 self.unsigned = to_raw_value(&unsigned)
31 .map(Into::into)
32 .map(Some)
33 .expect("unsigned is valid");
34
35 Ok(())
36}
37
38#[implement(Pdu)]
42pub fn remove_prev_state(&mut self) -> Result {
43 use BTreeMap as Map;
44
45 let Some(unsigned) = &self.unsigned else {
46 return Ok(());
47 };
48
49 let raw = unsigned.json().get();
50 let prev_keys = raw.contains("\"prev_content\"") || raw.contains("\"prev_sender\"");
51 if !prev_keys && raw != "{}" {
52 return Ok(());
53 }
54
55 let mut unsigned: Map<&str, Raw<JsonValue>> = serde_json::from_str(raw)
56 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
57
58 unsigned.remove("prev_content");
59 unsigned.remove("prev_sender");
60 self.unsigned = unsigned
61 .is_empty()
62 .is_false()
63 .then(|| to_raw_value(&unsigned))
64 .transpose()?
65 .map(Into::into);
66
67 Ok(())
68}
69
70#[implement(Pdu)]
76pub fn add_age(&mut self) -> Result {
77 use BTreeMap as Map;
78
79 let mut unsigned: Map<&str, Raw<JsonValue>> = self
80 .unsigned
81 .as_ref()
82 .map(Unsigned::json)
83 .map(RawJsonValue::get)
84 .map_or_else(|| Ok(Map::new()), serde_json::from_str)
85 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
86
87 let now: i128 = MilliSecondsSinceUnixEpoch::now().get().into();
89 let then: i128 = self.origin_server_ts.into();
90 let this_age = now.saturating_sub(then);
91
92 unsigned.insert("age", raw_of(&this_age)?);
93 self.unsigned = Some(to_raw_value(&unsigned)?.into());
94
95 Ok(())
96}
97
98#[implement(Pdu)]
101pub fn add_membership(&mut self, membership: &MembershipState) -> Result {
102 use BTreeMap as Map;
103
104 let mut unsigned: Map<&str, Raw<JsonValue>> = self
105 .unsigned
106 .as_ref()
107 .map(Unsigned::json)
108 .map(RawJsonValue::get)
109 .map_or_else(|| Ok(Map::new()), serde_json::from_str)
110 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
111
112 unsigned.insert("membership", raw_of(membership)?);
113 self.unsigned = Some(to_raw_value(&unsigned)?.into());
114
115 Ok(())
116}
117
118#[implement(Pdu)]
124pub fn add_relation(&mut self, name: &str, pdu: Option<&Pdu>) -> Result {
125 use serde_json::Map;
126
127 let mut unsigned: Map<String, JsonValue> = self
128 .unsigned
129 .as_ref()
130 .map(Unsigned::json)
131 .map(RawJsonValue::get)
132 .map_or_else(|| Ok(Map::new()), serde_json::from_str)
133 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
134
135 let pdu = pdu
136 .map(serde_json::to_value)
137 .transpose()?
138 .unwrap_or_else(|| JsonValue::Object(Map::new()));
139
140 unsigned
141 .entry("m.relations")
142 .or_insert(JsonValue::Object(Map::new()))
143 .as_object_mut()
144 .map(|object| object.insert(name.to_owned(), pdu));
145
146 self.unsigned = Some(to_raw_value(&unsigned)?.into());
147
148 Ok(())
149}
150
151#[implement(Pdu)]
154pub fn set_thread_participated(&mut self, participated: bool) -> Result {
155 use serde_json::Map;
156
157 let Some(unsigned) = self.unsigned.as_ref() else {
158 return Ok(());
159 };
160
161 let mut unsigned: Map<String, JsonValue> = serde_json::from_str(unsigned.json().get())
162 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
163
164 let updated = unsigned
165 .get_mut("m.relations")
166 .and_then(JsonValue::as_object_mut)
167 .and_then(|relations| relations.get_mut("m.thread"))
168 .and_then(JsonValue::as_object_mut)
169 .map(|thread| {
170 thread.insert("current_user_participated".to_owned(), participated.into());
171 })
172 .is_some();
173
174 if updated {
175 self.unsigned = Some(to_raw_value(&unsigned)?.into());
176 }
177
178 Ok(())
179}
180
181#[implement(Pdu)]
185#[must_use]
186pub fn thread_latest_event(&self) -> Option<(OwnedEventId, OwnedUserId)> {
187 #[derive(Deserialize)]
188 struct Relations {
189 #[serde(rename = "m.thread")]
190 thread: Option<Thread>,
191 }
192
193 #[derive(Deserialize)]
194 struct Thread {
195 latest_event: Option<Identity>,
196 }
197
198 #[derive(Deserialize)]
199 struct Identity {
200 event_id: OwnedEventId,
201 sender: OwnedUserId,
202 }
203
204 let relations: Relations = self
205 .unsigned
206 .as_ref()?
207 .get_field("m.relations")
208 .ok()
209 .flatten()?;
210
211 let identity = relations.thread?.latest_event?;
212
213 Some((identity.event_id, identity.sender))
214}
215
216#[implement(Pdu)]
220pub fn set_thread_latest_event(&mut self, latest: &Raw<AnySyncMessageLikeEvent>) -> Result {
221 use serde_json::Map;
222
223 let Some(unsigned) = self.unsigned.as_ref() else {
224 return Ok(());
225 };
226
227 let latest = serde_json::to_value(latest)?;
228
229 let mut unsigned: Map<String, JsonValue> = serde_json::from_str(unsigned.json().get())
230 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
231
232 let updated = unsigned
233 .get_mut("m.relations")
234 .and_then(JsonValue::as_object_mut)
235 .and_then(|relations| relations.get_mut("m.thread"))
236 .and_then(JsonValue::as_object_mut)
237 .map(|thread| {
238 thread.insert("latest_event".to_owned(), latest);
239 })
240 .is_some();
241
242 if updated {
243 self.unsigned = Some(to_raw_value(&unsigned)?.into());
244 }
245
246 Ok(())
247}
248
249#[implement(Pdu)]
253pub fn set_thread_count(&mut self, count: usize) -> Result {
254 use serde_json::Map;
255
256 let Some(unsigned) = self.unsigned.as_ref() else {
257 return Ok(());
258 };
259
260 let mut unsigned: Map<String, JsonValue> = serde_json::from_str(unsigned.json().get())
261 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
262
263 let updated = unsigned
264 .get_mut("m.relations")
265 .and_then(JsonValue::as_object_mut)
266 .and_then(|relations| relations.get_mut("m.thread"))
267 .and_then(JsonValue::as_object_mut)
268 .map(|thread| {
269 thread.insert("count".to_owned(), count.into());
270 })
271 .is_some();
272
273 if updated {
274 self.unsigned = Some(to_raw_value(&unsigned)?.into());
275 }
276
277 Ok(())
278}
279
280#[implement(Pdu)]
284pub fn set_replacement_bundle(&mut self, replacement: &Raw<AnySyncMessageLikeEvent>) -> Result {
285 use BTreeMap as Map;
286
287 type Object = Map<String, Raw<JsonValue>>;
288
289 let parse = |raw: &RawJsonValue| -> Result<Object> {
290 serde_json::from_str(raw.get())
291 .map_err(|e| err!(Database("Invalid object in pdu unsigned: {e}")))
292 };
293
294 let mut unsigned: Object = self
295 .unsigned
296 .as_ref()
297 .map(|unsigned| parse(unsigned.json()))
298 .transpose()?
299 .unwrap_or_default();
300
301 let mut relations: Object = unsigned
302 .get("m.relations")
303 .map(|relations| parse(relations.json()))
304 .transpose()?
305 .unwrap_or_default();
306
307 relations.insert("m.replace".to_owned(), replacement.cast_ref().clone());
308 unsigned.insert("m.relations".to_owned(), to_raw_value(&relations)?.into());
309 self.unsigned = Some(to_raw_value(&unsigned)?.into());
310
311 Ok(())
312}
313
314#[implement(Pdu)]
318pub fn remove_replacement_bundle(&mut self) -> Result {
319 use BTreeMap as Map;
320
321 type Object = Map<String, Raw<JsonValue>>;
322
323 let Some(unsigned) = &self.unsigned else {
324 return Ok(());
325 };
326
327 if !unsigned.json().get().contains("\"m.replace\"") {
328 return Ok(());
329 }
330
331 let parse = |raw: &RawJsonValue| -> Result<Object> {
332 serde_json::from_str(raw.get())
333 .map_err(|e| err!(SerdeDe("Invalid object in pdu unsigned: {e}")))
334 };
335
336 let mut unsigned: Object = parse(unsigned.json())?;
337
338 let Some(relations) = unsigned.get("m.relations") else {
339 return Ok(());
340 };
341
342 let mut relations: Object = parse(relations.json())?;
343
344 if relations.remove("m.replace").is_none() {
345 return Ok(());
346 }
347
348 match relations.is_empty() {
349 | true => unsigned.remove("m.relations"),
350 | false => unsigned.insert("m.relations".to_owned(), to_raw_value(&relations)?.into()),
351 };
352
353 self.unsigned = unsigned
354 .is_empty()
355 .is_false()
356 .then(|| to_raw_value(&unsigned))
357 .transpose()?
358 .map(Into::into);
359
360 Ok(())
361}
362
363#[implement(Pdu)]
368pub fn set_reference_bundle(&mut self, event_ids: &[OwnedEventId]) -> Result {
369 use BTreeMap as Map;
370
371 type Object = Map<String, Raw<JsonValue>>;
372
373 let parse = |raw: &RawJsonValue| -> Result<Object> {
374 serde_json::from_str(raw.get())
375 .map_err(|e| err!(Database("Invalid object in pdu unsigned: {e}")))
376 };
377
378 let mut unsigned: Object = self
379 .unsigned
380 .as_ref()
381 .map(|unsigned| parse(unsigned.json()))
382 .transpose()?
383 .unwrap_or_default();
384
385 let mut relations: Object = unsigned
386 .get("m.relations")
387 .map(|relations| parse(relations.json()))
388 .transpose()?
389 .unwrap_or_default();
390
391 let chunk: Vec<JsonValue> = event_ids
392 .iter()
393 .map(|event_id| serde_json::json!({ "event_id": event_id }))
394 .collect();
395
396 let reference = serde_json::json!({ "chunk": chunk });
397
398 relations.insert("m.reference".to_owned(), to_raw_value(&reference)?.into());
399 unsigned.insert("m.relations".to_owned(), to_raw_value(&relations)?.into());
400 self.unsigned = Some(to_raw_value(&unsigned)?.into());
401
402 Ok(())
403}
404
405#[inline]
406fn raw_of<T: Serialize>(value: &T) -> Result<Raw<JsonValue>> {
407 Ok(Raw::from_raw_value(&to_raw_value(value)?))
408}