tuwunel_core/matrix/pdu/
unsigned.rs1use std::collections::BTreeMap;
2
3use ruma::{
4 MilliSecondsSinceUnixEpoch, OwnedEventId,
5 events::{AnySyncMessageLikeEvent, room::member::MembershipState},
6 serde::Raw,
7};
8use serde::Serialize;
9use serde_json::value::{RawValue as RawJsonValue, Value as JsonValue, to_raw_value};
10
11use super::{Pdu, Unsigned};
12use crate::{Result, err, implement};
13
14#[implement(Pdu)]
15pub fn remove_transaction_id(&mut self) -> Result {
16 use BTreeMap as Map;
17
18 let Some(unsigned) = &self.unsigned else {
19 return Ok(());
20 };
21
22 let mut unsigned: Map<&str, Raw<JsonValue>> = serde_json::from_str(unsigned.json().get())
23 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
24
25 unsigned.remove("transaction_id");
26 self.unsigned = to_raw_value(&unsigned)
27 .map(Into::into)
28 .map(Some)
29 .expect("unsigned is valid");
30
31 Ok(())
32}
33
34#[implement(Pdu)]
35pub fn add_age(&mut self) -> Result {
36 use BTreeMap as Map;
37
38 let mut unsigned: Map<&str, Raw<JsonValue>> = self
39 .unsigned
40 .as_ref()
41 .map(Unsigned::json)
42 .map(RawJsonValue::get)
43 .map_or_else(|| Ok(Map::new()), serde_json::from_str)
44 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
45
46 let now: i128 = MilliSecondsSinceUnixEpoch::now().get().into();
48 let then: i128 = self.origin_server_ts.into();
49 let this_age = now.saturating_sub(then);
50
51 unsigned.insert("age", raw_of(&this_age)?);
52 self.unsigned = Some(to_raw_value(&unsigned)?.into());
53
54 Ok(())
55}
56
57#[implement(Pdu)]
60pub fn add_membership(&mut self, membership: &MembershipState) -> Result {
61 use BTreeMap as Map;
62
63 let mut unsigned: Map<&str, Raw<JsonValue>> = self
64 .unsigned
65 .as_ref()
66 .map(Unsigned::json)
67 .map(RawJsonValue::get)
68 .map_or_else(|| Ok(Map::new()), serde_json::from_str)
69 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
70
71 unsigned.insert("membership", raw_of(membership)?);
72 self.unsigned = Some(to_raw_value(&unsigned)?.into());
73
74 Ok(())
75}
76
77#[implement(Pdu)]
78pub fn add_relation(&mut self, name: &str, pdu: Option<&Pdu>) -> Result {
79 use serde_json::Map;
80
81 let mut unsigned: Map<String, JsonValue> = self
82 .unsigned
83 .as_ref()
84 .map(Unsigned::json)
85 .map(RawJsonValue::get)
86 .map_or_else(|| Ok(Map::new()), serde_json::from_str)
87 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
88
89 let pdu = pdu
90 .map(serde_json::to_value)
91 .transpose()?
92 .unwrap_or_else(|| JsonValue::Object(Map::new()));
93
94 unsigned
95 .entry("m.relations")
96 .or_insert(JsonValue::Object(Map::new()))
97 .as_object_mut()
98 .map(|object| object.insert(name.to_owned(), pdu));
99
100 self.unsigned = Some(to_raw_value(&unsigned)?.into());
101
102 Ok(())
103}
104
105#[implement(Pdu)]
108pub fn set_thread_participated(&mut self, participated: bool) -> Result {
109 use serde_json::Map;
110
111 let Some(unsigned) = self.unsigned.as_ref() else {
112 return Ok(());
113 };
114
115 let mut unsigned: Map<String, JsonValue> = serde_json::from_str(unsigned.json().get())
116 .map_err(|e| err!(Database("Invalid unsigned in pdu event: {e}")))?;
117
118 let updated = unsigned
119 .get_mut("m.relations")
120 .and_then(JsonValue::as_object_mut)
121 .and_then(|relations| relations.get_mut("m.thread"))
122 .and_then(JsonValue::as_object_mut)
123 .map(|thread| {
124 thread.insert("current_user_participated".to_owned(), participated.into());
125 })
126 .is_some();
127
128 if updated {
129 self.unsigned = Some(to_raw_value(&unsigned)?.into());
130 }
131
132 Ok(())
133}
134
135#[implement(Pdu)]
139pub fn set_replacement_bundle(&mut self, replacement: &Raw<AnySyncMessageLikeEvent>) -> Result {
140 use BTreeMap as Map;
141
142 type Object = Map<String, Raw<JsonValue>>;
143
144 let parse = |raw: &RawJsonValue| -> Result<Object> {
145 serde_json::from_str(raw.get())
146 .map_err(|e| err!(Database("Invalid object in pdu unsigned: {e}")))
147 };
148
149 let mut unsigned: Object = self
150 .unsigned
151 .as_ref()
152 .map(|unsigned| parse(unsigned.json()))
153 .transpose()?
154 .unwrap_or_default();
155
156 let mut relations: Object = unsigned
157 .get("m.relations")
158 .map(|relations| parse(relations.json()))
159 .transpose()?
160 .unwrap_or_default();
161
162 relations.insert("m.replace".to_owned(), replacement.cast_ref().clone());
163 unsigned.insert("m.relations".to_owned(), to_raw_value(&relations)?.into());
164 self.unsigned = Some(to_raw_value(&unsigned)?.into());
165
166 Ok(())
167}
168
169#[implement(Pdu)]
174pub fn set_reference_bundle(&mut self, event_ids: &[OwnedEventId]) -> Result {
175 use BTreeMap as Map;
176
177 type Object = Map<String, Raw<JsonValue>>;
178
179 let parse = |raw: &RawJsonValue| -> Result<Object> {
180 serde_json::from_str(raw.get())
181 .map_err(|e| err!(Database("Invalid object in pdu unsigned: {e}")))
182 };
183
184 let mut unsigned: Object = self
185 .unsigned
186 .as_ref()
187 .map(|unsigned| parse(unsigned.json()))
188 .transpose()?
189 .unwrap_or_default();
190
191 let mut relations: Object = unsigned
192 .get("m.relations")
193 .map(|relations| parse(relations.json()))
194 .transpose()?
195 .unwrap_or_default();
196
197 let chunk: Vec<JsonValue> = event_ids
198 .iter()
199 .map(|event_id| serde_json::json!({ "event_id": event_id }))
200 .collect();
201
202 let reference = serde_json::json!({ "chunk": chunk });
203
204 relations.insert("m.reference".to_owned(), to_raw_value(&reference)?.into());
205 unsigned.insert("m.relations".to_owned(), to_raw_value(&relations)?.into());
206 self.unsigned = Some(to_raw_value(&unsigned)?.into());
207
208 Ok(())
209}
210
211#[inline]
212fn raw_of<T: Serialize>(value: &T) -> Result<Raw<JsonValue>> {
213 Ok(Raw::from_raw_value(&to_raw_value(value)?))
214}