tuwunel_core/matrix/event.rs
1//! Event access, conversion, filtering, and state-key utilities.
2//!
3//! The module defines the common event trait and adapters for client and
4//! federation representations. It also exposes helpers for inspecting event
5//! data.
6
7mod content;
8mod filter;
9mod format;
10mod id;
11mod msgtype;
12mod redact;
13mod relation;
14pub mod state_key;
15mod type_ext;
16mod unsigned;
17
18use std::fmt::Debug;
19
20use ruma::{
21 CanonicalJsonObject, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
22 events::{AnySyncMessageLikeEvent, TimelineEventType, room::member::MembershipState},
23 room_version_rules::RoomVersionRules,
24 serde::Raw,
25};
26use serde::Deserialize;
27use serde_json::{Value as JsonValue, value::RawValue as RawJsonValue};
28
29pub use self::{
30 filter::{Matches, trim_event_fields},
31 format::{Owned, Ref},
32 id::*,
33 msgtype::MsgType,
34 relation::RelationTypeEqual,
35 state_key::{StateKey, TypeStateKey},
36 type_ext::TypeExt,
37};
38use self::{format::to_sync_message_like_without_unsigned, msgtype::content_msgtype};
39use super::pdu::Pdu;
40use crate::{Result, utils, utils::BoolExt};
41
42#[derive(Deserialize)]
43struct MemberContent {
44 membership: MembershipState,
45}
46
47/// Abstraction of a PDU so users can have their own PDU types.
48pub trait Event: Clone + Debug + Send + Sync {
49 /// Checks whether this event has both the requested type and state key.
50 ///
51 /// Message-like events never match because their state key is absent. The
52 /// comparison does not inspect event content.
53 #[inline]
54 fn is_type_and_state_key(&self, kind: &TimelineEventType, state_key: &str) -> bool {
55 self.kind() == kind && self.state_key() == Some(state_key)
56 }
57
58 /// The membership this event sets for a user, when it is that user's own
59 /// member event.
60 ///
61 /// Any other event yields `None`, as does member content whose `membership`
62 /// does not parse. Only that one field is deserialized.
63 #[inline]
64 fn membership_for(&self, user_id: &UserId) -> Option<MembershipState>
65 where
66 Self: Sized,
67 {
68 self.is_type_and_state_key(&TimelineEventType::RoomMember, user_id.as_str())
69 .and_then(|| self.get_content().ok())
70 .map(|content: MemberContent| content.membership)
71 }
72
73 /// Serialize into a Ruma JSON format, consuming.
74 #[inline]
75 fn into_format<T>(self) -> T
76 where
77 T: From<Owned<Self>>,
78 Self: Sized,
79 {
80 Owned(self).into()
81 }
82
83 /// Serialize into a Ruma JSON format
84 #[inline]
85 fn to_format<'a, T>(&'a self) -> T
86 where
87 T: From<Ref<'a, Self>>,
88 Self: Sized + 'a,
89 {
90 Ref(self).into()
91 }
92
93 /// Serializes a borrowed sync message-like event without unsigned data.
94 ///
95 /// This is suitable for persisted event embeddings whose shared copy must
96 /// never retain sender-specific unsigned metadata.
97 #[inline]
98 fn to_sync_message_like_without_unsigned(&self) -> Raw<AnySyncMessageLikeEvent>
99 where
100 Self: Sized,
101 {
102 to_sync_message_like_without_unsigned(self)
103 }
104
105 /// Checks an unsigned-data property with a caller-supplied predicate.
106 ///
107 /// The method returns false when the property is absent or the predicate
108 /// rejects its value. Missing or malformed unsigned data is treated as
109 /// empty.
110 #[inline]
111 fn contains_unsigned_property<T>(&self, property: &str, is_type: T) -> bool
112 where
113 T: FnOnce(&JsonValue) -> bool,
114 Self: Sized,
115 {
116 unsigned::contains_unsigned_property::<T, _>(self, property, is_type)
117 }
118
119 /// Deserializes one property from the event's unsigned data.
120 ///
121 /// A missing property or malformed unsigned data is reported as not found.
122 /// A value of the wrong type fails deserialization.
123 #[inline]
124 fn get_unsigned_property<T>(&self, property: &str) -> Result<T>
125 where
126 T: for<'de> Deserialize<'de>,
127 Self: Sized,
128 {
129 unsigned::get_unsigned_property::<T, _>(self, property)
130 }
131
132 /// Deserializes the event's unsigned data as a JSON value.
133 ///
134 /// Missing or malformed unsigned data produces JSON null. Use
135 /// `get_unsigned` when the distinction must be preserved.
136 #[inline]
137 fn get_unsigned_as_value(&self) -> JsonValue
138 where
139 Self: Sized,
140 {
141 unsigned::get_unsigned_as_value(self)
142 }
143
144 /// Deserializes the complete unsigned-data object into a requested type.
145 ///
146 /// Missing unsigned data is reported as not found. Invalid JSON or a type
147 /// mismatch fails deserialization.
148 #[inline]
149 fn get_unsigned<T>(&self) -> Result<T>
150 where
151 T: for<'de> Deserialize<'de>,
152 Self: Sized,
153 {
154 unsigned::get_unsigned::<T, _>(self)
155 }
156
157 /// Deserializes event content as an untyped JSON value.
158 ///
159 /// The returned value owns its data and can be inspected without borrowing
160 /// the event. Typed consumers should prefer `get_content`.
161 ///
162 /// # Panics
163 ///
164 /// Panics when the stored content is not valid JSON.
165 #[inline]
166 fn get_content_as_value(&self) -> JsonValue
167 where
168 Self: Sized,
169 {
170 content::as_value(self)
171 }
172
173 /// Deserializes event content into a requested type.
174 ///
175 /// The target type determines which event-content shape is accepted.
176 /// Invalid JSON or a mismatched target type produces a bad-JSON result.
177 #[inline]
178 fn get_content<T>(&self) -> Result<T>
179 where
180 for<'de> T: Deserialize<'de>,
181 Self: Sized,
182 {
183 content::get::<T, _>(self)
184 }
185
186 /// Reads the `msgtype` of this event's message content.
187 ///
188 /// Only that one field is deserialized, and the event type is not checked.
189 /// Content with no readable `msgtype` returns `None`.
190 #[inline]
191 fn msgtype(&self) -> Option<MsgType>
192 where
193 Self: Sized,
194 {
195 content_msgtype(self)
196 }
197
198 /// Resolves the event ID targeted by a redaction event.
199 ///
200 /// The selected room rules determine whether the ID is read from event
201 /// content or the top-level `redacts` field. Non-redaction events and
202 /// malformed content return `None`.
203 #[inline]
204 fn redacts_id(&self, room_rules: &RoomVersionRules) -> Option<OwnedEventId>
205 where
206 Self: Sized,
207 {
208 redact::redacts_id(self, room_rules)
209 }
210
211 /// Reports whether the event carries redaction metadata.
212 ///
213 /// Redaction is recognized by the presence of `unsigned.redacted_because`.
214 /// Missing or malformed unsigned data is treated as not redacted.
215 #[inline]
216 fn is_redacted(&self) -> bool
217 where
218 Self: Sized,
219 {
220 redact::is_redacted(self)
221 }
222
223 /// Consumes the event and serializes its PDU as a canonical JSON object.
224 ///
225 /// Implementations first convert the event to the common `Pdu`
226 /// representation. The resulting object preserves the stored event fields.
227 ///
228 /// # Panics
229 ///
230 /// Panics if the PDU cannot be serialized as a canonical JSON object.
231 #[inline]
232 fn into_canonical_object(self) -> CanonicalJsonObject
233 where
234 Self: Sized,
235 {
236 utils::to_canonical_object(self.into_pdu()).expect("failed to create Value::Object")
237 }
238
239 /// Serializes the event's PDU as an owned canonical JSON object.
240 ///
241 /// The event remains available after conversion. The resulting object
242 /// preserves the stored event fields.
243 ///
244 /// # Panics
245 ///
246 /// Panics if the PDU cannot be serialized as a canonical JSON object.
247 #[inline]
248 fn to_canonical_object(&self) -> CanonicalJsonObject {
249 utils::to_canonical_object(self.as_pdu()).expect("failed to create Value::Object")
250 }
251
252 /// Consumes the event and serializes its PDU as a JSON value.
253 ///
254 /// Implementations first convert the event to the common `Pdu`
255 /// representation. The returned value is an owned JSON object.
256 ///
257 /// # Panics
258 ///
259 /// Panics if the PDU cannot be serialized as JSON.
260 #[inline]
261 fn into_value(self) -> JsonValue
262 where
263 Self: Sized,
264 {
265 serde_json::to_value(self.into_pdu()).expect("failed to create JSON Value")
266 }
267
268 /// Serializes the event's PDU as an owned JSON value.
269 ///
270 /// The event remains available after conversion. The returned value is an
271 /// owned JSON object.
272 ///
273 /// # Panics
274 ///
275 /// Panics if the PDU cannot be serialized as JSON.
276 #[inline]
277 fn to_value(&self) -> JsonValue {
278 serde_json::to_value(self.as_pdu()).expect("failed to create JSON Value")
279 }
280
281 /// Returns mutable access to the common PDU representation.
282 ///
283 /// Implementations backed by a mutable `Pdu` override this method. The
284 /// default implementation marks mutable conversion as unsupported.
285 ///
286 /// # Panics
287 ///
288 /// Panics when the implementation does not provide mutable PDU access.
289 #[inline]
290 fn as_mut_pdu(&mut self) -> &mut Pdu { unimplemented!("not a mutable Pdu") }
291
292 /// Borrows the event as the common PDU representation.
293 ///
294 /// Implementations may return their underlying PDU directly or a borrowed
295 /// PDU representation with the same event data.
296 fn as_pdu(&self) -> &Pdu;
297
298 /// Converts the event into an owned common PDU representation.
299 ///
300 /// Owned implementations can move their PDU. Borrowed implementations clone
301 /// the PDU so the returned value owns every field.
302 fn into_pdu(self) -> Pdu;
303
304 /// Reports whether consuming conversion can move an owned PDU.
305 ///
306 /// A false result indicates that `into_pdu` must clone borrowed event data.
307 /// The value can help callers choose a conversion path.
308 fn is_owned(&self) -> bool;
309
310 //
311 // Canonical properties
312 //
313
314 /// All the authenticating events for this event.
315 fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Clone + Send + '_;
316
317 /// All the authenticating events for this event.
318 fn auth_events_into(
319 self,
320 ) -> impl IntoIterator<IntoIter = impl Iterator<Item = OwnedEventId>> + Send;
321
322 /// The event's content.
323 fn content(&self) -> &RawJsonValue;
324
325 /// The `EventId` of this event.
326 fn event_id(&self) -> &EventId;
327
328 /// The time of creation on the originating server.
329 fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
330
331 /// The events before this event.
332 fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Clone + Send + '_;
333
334 /// If this event is a redaction event this is the event it redacts.
335 fn redacts(&self) -> Option<&EventId>;
336
337 /// see: <https://spec.matrix.org/v1.14/rooms/v11/#rejected-events>
338 fn rejected(&self) -> bool;
339
340 /// The `RoomId` of this event.
341 fn room_id(&self) -> &RoomId;
342
343 /// The `UserId` of this event.
344 fn sender(&self) -> &UserId;
345
346 /// The state key for this event.
347 fn state_key(&self) -> Option<&str>;
348
349 /// The event type.
350 fn kind(&self) -> &TimelineEventType;
351
352 /// Metadata container; peer-trusted only.
353 fn unsigned(&self) -> Option<&RawJsonValue>;
354
355 //#[deprecated]
356 /// Returns the event's timeline type.
357 ///
358 /// This compatibility accessor delegates directly to `kind`. New callers
359 /// can use either name without changing the returned value.
360 #[inline]
361 fn event_type(&self) -> &TimelineEventType { self.kind() }
362}