Skip to main content

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}