Toward abstracting Pdu into trait Event.

Co-authored-by: Jade Ellis <jade@ellis.link>
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2025-04-26 08:24:47 +00:00 committed by Jade Ellis
commit 116f85360f
No known key found for this signature in database
GPG key ID: 8705A2A3EBF77BD2
41 changed files with 842 additions and 886 deletions

View file

@ -1,63 +1,114 @@
use ruma::{EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId, events::TimelineEventType};
use serde_json::value::RawValue as RawJsonValue;
mod content;
mod format;
mod redact;
mod type_ext;
use ruma::{
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, UserId,
events::TimelineEventType,
};
use serde::Deserialize;
use serde_json::{Value as JsonValue, value::RawValue as RawJsonValue};
pub use self::type_ext::TypeExt;
use super::state_key::StateKey;
use crate::Result;
/// Abstraction of a PDU so users can have their own PDU types.
pub trait Event {
/// Serialize into a Ruma JSON format, consuming.
#[inline]
fn into_format<T>(self) -> T
where
T: From<format::Owned<Self>>,
Self: Sized,
{
format::Owned(self).into()
}
/// Serialize into a Ruma JSON format
#[inline]
fn to_format<'a, T>(&'a self) -> T
where
T: From<format::Ref<'a, Self>>,
Self: Sized + 'a,
{
format::Ref(self).into()
}
#[inline]
fn get_content_as_value(&self) -> JsonValue
where
Self: Sized,
{
content::as_value(self)
}
#[inline]
fn get_content<T>(&self) -> Result<T>
where
for<'de> T: Deserialize<'de>,
Self: Sized,
{
content::get::<T, _>(self)
}
#[inline]
fn redacts_id(&self, room_version: &RoomVersionId) -> Option<OwnedEventId>
where
Self: Sized,
{
redact::redacts_id(self, room_version)
}
#[inline]
fn is_redacted(&self) -> bool
where
Self: Sized,
{
redact::is_redacted(self)
}
fn is_owned(&self) -> bool;
//
// Canonical properties
//
/// All the authenticating events for this event.
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
/// The event's content.
fn content(&self) -> &RawJsonValue;
/// The `EventId` of this event.
fn event_id(&self) -> &EventId;
/// The time of creation on the originating server.
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
/// The events before this event.
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
/// If this event is a redaction event this is the event it redacts.
fn redacts(&self) -> Option<&EventId>;
/// The `RoomId` of this event.
fn room_id(&self) -> &RoomId;
/// The `UserId` of this event.
fn sender(&self) -> &UserId;
/// The time of creation on the originating server.
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
/// The event type.
fn event_type(&self) -> &TimelineEventType;
/// The event's content.
fn content(&self) -> &RawJsonValue;
/// The state key for this event.
fn state_key(&self) -> Option<&str>;
/// The events before this event.
// Requires GATs to avoid boxing (and TAIT for making it convenient).
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
/// The event type.
fn kind(&self) -> &TimelineEventType;
/// All the authenticating events for this event.
// Requires GATs to avoid boxing (and TAIT for making it convenient).
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_;
/// Metadata container; peer-trusted only.
fn unsigned(&self) -> Option<&RawJsonValue>;
/// If this event is a redaction event this is the event it redacts.
fn redacts(&self) -> Option<&EventId>;
}
impl<T: Event> Event for &T {
fn event_id(&self) -> &EventId { (*self).event_id() }
fn room_id(&self) -> &RoomId { (*self).room_id() }
fn sender(&self) -> &UserId { (*self).sender() }
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { (*self).origin_server_ts() }
fn event_type(&self) -> &TimelineEventType { (*self).event_type() }
fn content(&self) -> &RawJsonValue { (*self).content() }
fn state_key(&self) -> Option<&str> { (*self).state_key() }
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
(*self).prev_events()
}
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
(*self).auth_events()
}
fn redacts(&self) -> Option<&EventId> { (*self).redacts() }
//#[deprecated]
#[inline]
fn event_type(&self) -> &TimelineEventType { self.kind() }
}

View file

@ -0,0 +1,21 @@
use serde::Deserialize;
use serde_json::value::Value as JsonValue;
use super::Event;
use crate::{Result, err};
#[inline]
#[must_use]
pub(super) fn as_value<E: Event>(event: &E) -> JsonValue {
get(event).expect("Failed to represent Event content as JsonValue")
}
#[inline]
pub(super) fn get<T, E>(event: &E) -> Result<T>
where
T: for<'de> Deserialize<'de>,
E: Event,
{
serde_json::from_str(event.content().get())
.map_err(|e| err!(Request(BadJson("Failed to deserialize content into type: {e}"))))
}

View file

@ -0,0 +1,219 @@
use ruma::{
events::{
AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent,
AnySyncTimelineEvent, AnyTimelineEvent, StateEvent, room::member::RoomMemberEventContent,
space::child::HierarchySpaceChildEvent,
},
serde::Raw,
};
use serde_json::json;
use super::{Event, redact};
pub struct Owned<E: Event>(pub(super) E);
pub struct Ref<'a, E: Event>(pub(super) &'a E);
impl<E: Event> From<Owned<E>> for Raw<AnySyncTimelineEvent> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnySyncTimelineEvent> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let (redacts, content) = redact::copy(event);
let mut json = json!({
"content": content,
"event_id": event.event_id(),
"origin_server_ts": event.origin_server_ts(),
"sender": event.sender(),
"type": event.event_type(),
});
if let Some(redacts) = redacts {
json["redacts"] = json!(redacts);
}
if let Some(state_key) = event.state_key() {
json["state_key"] = json!(state_key);
}
if let Some(unsigned) = event.unsigned() {
json["unsigned"] = json!(unsigned);
}
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}
impl<E: Event> From<Owned<E>> for Raw<AnyTimelineEvent> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyTimelineEvent> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let (redacts, content) = redact::copy(event);
let mut json = json!({
"content": content,
"event_id": event.event_id(),
"origin_server_ts": event.origin_server_ts(),
"room_id": event.room_id(),
"sender": event.sender(),
"type": event.kind(),
});
if let Some(redacts) = redacts {
json["redacts"] = json!(redacts);
}
if let Some(state_key) = event.state_key() {
json["state_key"] = json!(state_key);
}
if let Some(unsigned) = event.unsigned() {
json["unsigned"] = json!(unsigned);
}
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}
impl<E: Event> From<Owned<E>> for Raw<AnyMessageLikeEvent> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyMessageLikeEvent> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let (redacts, content) = redact::copy(event);
let mut json = json!({
"content": content,
"event_id": event.event_id(),
"origin_server_ts": event.origin_server_ts(),
"room_id": event.room_id(),
"sender": event.sender(),
"type": event.kind(),
});
if let Some(redacts) = &redacts {
json["redacts"] = json!(redacts);
}
if let Some(state_key) = event.state_key() {
json["state_key"] = json!(state_key);
}
if let Some(unsigned) = event.unsigned() {
json["unsigned"] = json!(unsigned);
}
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}
impl<E: Event> From<Owned<E>> for Raw<AnyStateEvent> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyStateEvent> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let mut json = json!({
"content": event.content(),
"event_id": event.event_id(),
"origin_server_ts": event.origin_server_ts(),
"room_id": event.room_id(),
"sender": event.sender(),
"state_key": event.state_key(),
"type": event.kind(),
});
if let Some(unsigned) = event.unsigned() {
json["unsigned"] = json!(unsigned);
}
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}
impl<E: Event> From<Owned<E>> for Raw<AnySyncStateEvent> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnySyncStateEvent> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let mut json = json!({
"content": event.content(),
"event_id": event.event_id(),
"origin_server_ts": event.origin_server_ts(),
"sender": event.sender(),
"state_key": event.state_key(),
"type": event.kind(),
});
if let Some(unsigned) = event.unsigned() {
json["unsigned"] = json!(unsigned);
}
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}
impl<E: Event> From<Owned<E>> for Raw<AnyStrippedStateEvent> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<AnyStrippedStateEvent> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let json = json!({
"content": event.content(),
"sender": event.sender(),
"state_key": event.state_key(),
"type": event.kind(),
});
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}
impl<E: Event> From<Owned<E>> for Raw<HierarchySpaceChildEvent> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<HierarchySpaceChildEvent> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let json = json!({
"content": event.content(),
"origin_server_ts": event.origin_server_ts(),
"sender": event.sender(),
"state_key": event.state_key(),
"type": event.kind(),
});
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}
impl<E: Event> From<Owned<E>> for Raw<StateEvent<RoomMemberEventContent>> {
fn from(event: Owned<E>) -> Self { Ref(&event.0).into() }
}
impl<'a, E: Event> From<Ref<'a, E>> for Raw<StateEvent<RoomMemberEventContent>> {
fn from(event: Ref<'a, E>) -> Self {
let event = event.0;
let mut json = json!({
"content": event.content(),
"event_id": event.event_id(),
"origin_server_ts": event.origin_server_ts(),
"redacts": event.redacts(),
"room_id": event.room_id(),
"sender": event.sender(),
"state_key": event.state_key(),
"type": event.kind(),
});
if let Some(unsigned) = event.unsigned() {
json["unsigned"] = json!(unsigned);
}
serde_json::from_value(json).expect("Failed to serialize Event value")
}
}

View file

@ -0,0 +1,86 @@
use ruma::{
OwnedEventId, RoomVersionId,
events::{TimelineEventType, room::redaction::RoomRedactionEventContent},
};
use serde::Deserialize;
use serde_json::value::{RawValue as RawJsonValue, to_raw_value};
use super::Event;
/// Copies the `redacts` property of the event to the `content` dict and
/// vice-versa.
///
/// This follows the specification's
/// [recommendation](https://spec.matrix.org/v1.10/rooms/v11/#moving-the-redacts-property-of-mroomredaction-events-to-a-content-property):
///
/// > For backwards-compatibility with older clients, servers should add a
/// > redacts property to the top level of m.room.redaction events in when
/// > serving such events over the Client-Server API.
///
/// > For improved compatibility with newer clients, servers should add a
/// > redacts property to the content of m.room.redaction events in older
/// > room versions when serving such events over the Client-Server API.
#[must_use]
pub(super) fn copy<E: Event>(event: &E) -> (Option<OwnedEventId>, Box<RawJsonValue>) {
if *event.event_type() != TimelineEventType::RoomRedaction {
return (event.redacts().map(ToOwned::to_owned), event.content().to_owned());
}
let Ok(mut content) = event.get_content::<RoomRedactionEventContent>() else {
return (event.redacts().map(ToOwned::to_owned), event.content().to_owned());
};
if let Some(redacts) = content.redacts {
return (Some(redacts), event.content().to_owned());
}
if let Some(redacts) = event.redacts().map(ToOwned::to_owned) {
content.redacts = Some(redacts);
return (
event.redacts().map(ToOwned::to_owned),
to_raw_value(&content).expect("Must be valid, we only added redacts field"),
);
}
(event.redacts().map(ToOwned::to_owned), event.content().to_owned())
}
#[must_use]
pub(super) fn is_redacted<E: Event>(event: &E) -> bool {
let Some(unsigned) = event.unsigned() else {
return false;
};
let Ok(unsigned) = ExtractRedactedBecause::deserialize(unsigned) else {
return false;
};
unsigned.redacted_because.is_some()
}
#[must_use]
pub(super) fn redacts_id<E: Event>(
event: &E,
room_version: &RoomVersionId,
) -> Option<OwnedEventId> {
use RoomVersionId::*;
if *event.kind() != TimelineEventType::RoomRedaction {
return None;
}
match *room_version {
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 =>
event.redacts().map(ToOwned::to_owned),
| _ =>
event
.get_content::<RoomRedactionEventContent>()
.ok()?
.redacts,
}
}
#[derive(Deserialize)]
struct ExtractRedactedBecause {
redacted_because: Option<serde::de::IgnoredAny>,
}

View file

@ -0,0 +1,32 @@
use ruma::events::{StateEventType, TimelineEventType};
use super::StateKey;
/// Convenience trait for adding event type plus state key to state maps.
pub trait TypeExt {
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey);
}
impl TypeExt for StateEventType {
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
(self, state_key.into())
}
}
impl TypeExt for &StateEventType {
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
(self.clone(), state_key.into())
}
}
impl TypeExt for TimelineEventType {
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
(self.into(), state_key.into())
}
}
impl TypeExt for &TimelineEventType {
fn with_state_key(self, state_key: impl Into<StateKey>) -> (StateEventType, StateKey) {
(self.clone().into(), state_key.into())
}
}

View file

@ -2,8 +2,10 @@
pub mod event;
pub mod pdu;
pub mod state_key;
pub mod state_res;
pub use event::Event;
pub use pdu::{PduBuilder, PduCount, PduEvent, PduId, RawPduId, StateKey};
pub use state_res::{EventTypeExt, RoomVersion, StateMap, TypeStateKey};
pub use event::{Event, TypeExt as EventTypeExt};
pub use pdu::{Pdu, PduBuilder, PduCount, PduEvent, PduId, RawPduId, ShortId};
pub use state_key::StateKey;
pub use state_res::{RoomVersion, StateMap, TypeStateKey};

View file

@ -7,8 +7,6 @@ mod id;
mod raw_id;
mod redact;
mod relation;
mod state_key;
mod strip;
#[cfg(test)]
mod tests;
mod unsigned;
@ -27,37 +25,50 @@ pub use self::{
builder::{Builder, Builder as PduBuilder},
count::Count,
event_id::*,
id::*,
id::{ShortId, *},
raw_id::*,
state_key::{ShortStateKey, StateKey},
};
use super::Event;
use super::{Event, StateKey};
use crate::Result;
/// Persistent Data Unit (Event)
#[derive(Clone, Deserialize, Serialize, Debug)]
pub struct Pdu {
pub event_id: OwnedEventId,
pub room_id: OwnedRoomId,
pub sender: OwnedUserId,
#[serde(skip_serializing_if = "Option::is_none")]
pub origin: Option<OwnedServerName>,
pub origin_server_ts: UInt,
#[serde(rename = "type")]
pub kind: TimelineEventType,
pub content: Box<RawJsonValue>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state_key: Option<StateKey>,
pub prev_events: Vec<OwnedEventId>,
pub depth: UInt,
pub auth_events: Vec<OwnedEventId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub redacts: Option<OwnedEventId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub unsigned: Option<Box<RawJsonValue>>,
pub hashes: EventHash,
#[serde(default, skip_serializing_if = "Option::is_none")]
// BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>
#[serde(default, skip_serializing_if = "Option::is_none")]
pub signatures: Option<Box<RawJsonValue>>,
}
@ -79,31 +90,91 @@ impl Pdu {
}
impl Event for Pdu {
fn event_id(&self) -> &EventId { &self.event_id }
fn room_id(&self) -> &RoomId { &self.room_id }
fn sender(&self) -> &UserId { &self.sender }
fn event_type(&self) -> &TimelineEventType { &self.kind }
fn content(&self) -> &RawJsonValue { &self.content }
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
MilliSecondsSinceUnixEpoch(self.origin_server_ts)
}
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
self.prev_events.iter().map(AsRef::as_ref)
}
#[inline]
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
self.auth_events.iter().map(AsRef::as_ref)
}
#[inline]
fn content(&self) -> &RawJsonValue { &self.content }
#[inline]
fn event_id(&self) -> &EventId { &self.event_id }
#[inline]
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
MilliSecondsSinceUnixEpoch(self.origin_server_ts)
}
#[inline]
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
self.prev_events.iter().map(AsRef::as_ref)
}
#[inline]
fn redacts(&self) -> Option<&EventId> { self.redacts.as_deref() }
#[inline]
fn room_id(&self) -> &RoomId { &self.room_id }
#[inline]
fn sender(&self) -> &UserId { &self.sender }
#[inline]
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
#[inline]
fn kind(&self) -> &TimelineEventType { &self.kind }
#[inline]
fn unsigned(&self) -> Option<&RawJsonValue> { self.unsigned.as_deref() }
#[inline]
fn is_owned(&self) -> bool { true }
}
impl Event for &Pdu {
#[inline]
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
self.auth_events.iter().map(AsRef::as_ref)
}
#[inline]
fn content(&self) -> &RawJsonValue { &self.content }
#[inline]
fn event_id(&self) -> &EventId { &self.event_id }
#[inline]
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
MilliSecondsSinceUnixEpoch(self.origin_server_ts)
}
#[inline]
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Send + '_ {
self.prev_events.iter().map(AsRef::as_ref)
}
#[inline]
fn redacts(&self) -> Option<&EventId> { self.redacts.as_deref() }
#[inline]
fn room_id(&self) -> &RoomId { &self.room_id }
#[inline]
fn sender(&self) -> &UserId { &self.sender }
#[inline]
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
#[inline]
fn kind(&self) -> &TimelineEventType { &self.kind }
#[inline]
fn unsigned(&self) -> Option<&RawJsonValue> { self.unsigned.as_deref() }
#[inline]
fn is_owned(&self) -> bool { false }
}
/// Prevent derived equality which wouldn't limit itself to event_id

View file

@ -3,6 +3,7 @@ use crate::utils::u64_from_u8x8;
pub type ShortRoomId = ShortId;
pub type ShortEventId = ShortId;
pub type ShortStateKey = ShortId;
pub type ShortId = u64;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]

View file

@ -1,117 +1,29 @@
use ruma::{
OwnedEventId, RoomVersionId,
canonical_json::redact_content_in_place,
events::{TimelineEventType, room::redaction::RoomRedactionEventContent},
};
use serde::Deserialize;
use serde_json::{
json,
value::{RawValue as RawJsonValue, to_raw_value},
};
use ruma::{RoomVersionId, canonical_json::redact_content_in_place};
use serde_json::{json, value::to_raw_value};
use crate::{Error, Result, implement};
#[derive(Deserialize)]
struct ExtractRedactedBecause {
redacted_because: Option<serde::de::IgnoredAny>,
}
use crate::{Error, Result, err, implement};
#[implement(super::Pdu)]
pub fn redact(&mut self, room_version_id: &RoomVersionId, reason: &Self) -> Result {
self.unsigned = None;
let mut content = serde_json::from_str(self.content.get())
.map_err(|_| Error::bad_database("PDU in db has invalid content."))?;
.map_err(|e| err!(Request(BadJson("Failed to deserialize content into type: {e}"))))?;
redact_content_in_place(&mut content, room_version_id, self.kind.to_string())
.map_err(|e| Error::Redaction(self.sender.server_name().to_owned(), e))?;
self.unsigned = Some(
to_raw_value(&json!({
"redacted_because": serde_json::to_value(reason).expect("to_value(Pdu) always works")
}))
.expect("to string always works"),
);
let reason = serde_json::to_value(reason).expect("Failed to preserialize reason");
self.content = to_raw_value(&content).expect("to string always works");
let redacted_because = json!({
"redacted_because": reason,
});
self.unsigned = to_raw_value(&redacted_because)
.expect("Failed to serialize unsigned")
.into();
self.content = to_raw_value(&content).expect("Failed to serialize content");
Ok(())
}
#[implement(super::Pdu)]
#[must_use]
pub fn is_redacted(&self) -> bool {
let Some(unsigned) = &self.unsigned else {
return false;
};
let Ok(unsigned) = ExtractRedactedBecause::deserialize(&**unsigned) else {
return false;
};
unsigned.redacted_because.is_some()
}
/// Copies the `redacts` property of the event to the `content` dict and
/// vice-versa.
///
/// This follows the specification's
/// [recommendation](https://spec.matrix.org/v1.10/rooms/v11/#moving-the-redacts-property-of-mroomredaction-events-to-a-content-property):
///
/// > For backwards-compatibility with older clients, servers should add a
/// > redacts
/// > property to the top level of m.room.redaction events in when serving
/// > such events
/// > over the Client-Server API.
///
/// > For improved compatibility with newer clients, servers should add a
/// > redacts property
/// > to the content of m.room.redaction events in older room versions when
/// > serving
/// > such events over the Client-Server API.
#[implement(super::Pdu)]
#[must_use]
pub fn copy_redacts(&self) -> (Option<OwnedEventId>, Box<RawJsonValue>) {
if self.kind == TimelineEventType::RoomRedaction {
if let Ok(mut content) =
serde_json::from_str::<RoomRedactionEventContent>(self.content.get())
{
match content.redacts {
| Some(redacts) => {
return (Some(redacts), self.content.clone());
},
| _ => match self.redacts.clone() {
| Some(redacts) => {
content.redacts = Some(redacts);
return (
self.redacts.clone(),
to_raw_value(&content)
.expect("Must be valid, we only added redacts field"),
);
},
| _ => {},
},
}
}
}
(self.redacts.clone(), self.content.clone())
}
#[implement(super::Pdu)]
#[must_use]
pub fn redacts_id(&self, room_version: &RoomVersionId) -> Option<OwnedEventId> {
use RoomVersionId::*;
if self.kind != TimelineEventType::RoomRedaction {
return None;
}
match *room_version {
| V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => self.redacts.clone(),
| _ =>
self.get_content::<RoomRedactionEventContent>()
.ok()?
.redacts,
}
}

View file

@ -1,257 +0,0 @@
use ruma::{
events::{
AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent, AnySyncStateEvent,
AnySyncTimelineEvent, AnyTimelineEvent, StateEvent, room::member::RoomMemberEventContent,
space::child::HierarchySpaceChildEvent,
},
serde::Raw,
};
use serde_json::{json, value::Value as JsonValue};
use crate::implement;
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_room_event(self) -> Raw<AnyTimelineEvent> { self.to_room_event() }
#[implement(super::Pdu)]
#[must_use]
pub fn to_room_event(&self) -> Raw<AnyTimelineEvent> {
let value = self.to_room_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn to_room_event_value(&self) -> JsonValue {
let (redacts, content) = self.copy_redacts();
let mut json = json!({
"content": content,
"type": self.kind,
"event_id": self.event_id,
"sender": self.sender,
"origin_server_ts": self.origin_server_ts,
"room_id": self.room_id,
});
if let Some(unsigned) = &self.unsigned {
json["unsigned"] = json!(unsigned);
}
if let Some(state_key) = &self.state_key {
json["state_key"] = json!(state_key);
}
if let Some(redacts) = &redacts {
json["redacts"] = json!(redacts);
}
json
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_message_like_event(self) -> Raw<AnyMessageLikeEvent> { self.to_message_like_event() }
#[implement(super::Pdu)]
#[must_use]
pub fn to_message_like_event(&self) -> Raw<AnyMessageLikeEvent> {
let value = self.to_message_like_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn to_message_like_event_value(&self) -> JsonValue {
let (redacts, content) = self.copy_redacts();
let mut json = json!({
"content": content,
"type": self.kind,
"event_id": self.event_id,
"sender": self.sender,
"origin_server_ts": self.origin_server_ts,
"room_id": self.room_id,
});
if let Some(unsigned) = &self.unsigned {
json["unsigned"] = json!(unsigned);
}
if let Some(state_key) = &self.state_key {
json["state_key"] = json!(state_key);
}
if let Some(redacts) = &redacts {
json["redacts"] = json!(redacts);
}
json
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_sync_room_event(self) -> Raw<AnySyncTimelineEvent> { self.to_sync_room_event() }
#[implement(super::Pdu)]
#[must_use]
pub fn to_sync_room_event(&self) -> Raw<AnySyncTimelineEvent> {
let value = self.to_sync_room_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn to_sync_room_event_value(&self) -> JsonValue {
let (redacts, content) = self.copy_redacts();
let mut json = json!({
"content": content,
"type": self.kind,
"event_id": self.event_id,
"sender": self.sender,
"origin_server_ts": self.origin_server_ts,
});
if let Some(unsigned) = &self.unsigned {
json["unsigned"] = json!(unsigned);
}
if let Some(state_key) = &self.state_key {
json["state_key"] = json!(state_key);
}
if let Some(redacts) = &redacts {
json["redacts"] = json!(redacts);
}
json
}
#[implement(super::Pdu)]
#[must_use]
pub fn into_state_event(self) -> Raw<AnyStateEvent> {
let value = self.into_state_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_state_event_value(self) -> JsonValue {
let mut json = json!({
"content": self.content,
"type": self.kind,
"event_id": self.event_id,
"sender": self.sender,
"origin_server_ts": self.origin_server_ts,
"room_id": self.room_id,
"state_key": self.state_key,
});
if let Some(unsigned) = self.unsigned {
json["unsigned"] = json!(unsigned);
}
json
}
#[implement(super::Pdu)]
#[must_use]
pub fn into_sync_state_event(self) -> Raw<AnySyncStateEvent> {
let value = self.into_sync_state_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_sync_state_event_value(self) -> JsonValue {
let mut json = json!({
"content": self.content,
"type": self.kind,
"event_id": self.event_id,
"sender": self.sender,
"origin_server_ts": self.origin_server_ts,
"state_key": self.state_key,
});
if let Some(unsigned) = &self.unsigned {
json["unsigned"] = json!(unsigned);
}
json
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_stripped_state_event(self) -> Raw<AnyStrippedStateEvent> {
self.to_stripped_state_event()
}
#[implement(super::Pdu)]
#[must_use]
pub fn to_stripped_state_event(&self) -> Raw<AnyStrippedStateEvent> {
let value = self.to_stripped_state_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn to_stripped_state_event_value(&self) -> JsonValue {
json!({
"content": self.content,
"type": self.kind,
"sender": self.sender,
"state_key": self.state_key,
})
}
#[implement(super::Pdu)]
#[must_use]
pub fn into_stripped_spacechild_state_event(self) -> Raw<HierarchySpaceChildEvent> {
let value = self.into_stripped_spacechild_state_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_stripped_spacechild_state_event_value(self) -> JsonValue {
json!({
"content": self.content,
"type": self.kind,
"sender": self.sender,
"state_key": self.state_key,
"origin_server_ts": self.origin_server_ts,
})
}
#[implement(super::Pdu)]
#[must_use]
pub fn into_member_event(self) -> Raw<StateEvent<RoomMemberEventContent>> {
let value = self.into_member_event_value();
serde_json::from_value(value).expect("Failed to serialize Event value")
}
#[implement(super::Pdu)]
#[must_use]
#[inline]
pub fn into_member_event_value(self) -> JsonValue {
let mut json = json!({
"content": self.content,
"type": self.kind,
"event_id": self.event_id,
"sender": self.sender,
"origin_server_ts": self.origin_server_ts,
"redacts": self.redacts,
"room_id": self.room_id,
"state_key": self.state_key,
});
if let Some(unsigned) = self.unsigned {
json["unsigned"] = json!(unsigned);
}
json
}

View file

@ -1,8 +1,5 @@
use smallstr::SmallString;
use super::ShortId;
pub type StateKey = SmallString<[u8; INLINE_SIZE]>;
pub type ShortStateKey = ShortId;
const INLINE_SIZE: usize = 48;

View file

@ -13,7 +13,6 @@ use ruma::{
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, RoomVersionId, Signatures, UserId,
events::{
StateEventType, TimelineEventType,
pdu::{EventHash, Pdu, RoomV3Pdu},
room::{
join_rules::{JoinRule, RoomJoinRulesEventContent},
member::{MembershipState, RoomMemberEventContent},
@ -26,8 +25,10 @@ use serde_json::{
value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value},
};
use self::event::PduEvent;
use crate::state_res::{self as state_res, Error, Event, Result, StateMap};
use crate::{
matrix::{Event, Pdu, pdu::EventHash},
state_res::{self as state_res, Error, Result, StateMap},
};
static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
@ -60,7 +61,7 @@ fn resolution_shallow_auth_chain(c: &mut test::Bencher) {
c.iter(|| async {
let ev_map = store.0.clone();
let state_sets = [&state_at_bob, &state_at_charlie];
let fetch = |id: OwnedEventId| ready(ev_map.get(&id).clone());
let fetch = |id: OwnedEventId| ready(ev_map.get(&id).map(ToOwned::to_owned));
let exists = |id: OwnedEventId| ready(ev_map.get(&id).is_some());
let auth_chain_sets: Vec<HashSet<_>> = state_sets
.iter()
@ -142,7 +143,7 @@ fn resolve_deeper_event_set(c: &mut test::Bencher) {
})
.collect();
let fetch = |id: OwnedEventId| ready(inner.get(&id).clone());
let fetch = |id: OwnedEventId| ready(inner.get(&id).map(ToOwned::to_owned));
let exists = |id: OwnedEventId| ready(inner.get(&id).is_some());
let _ = match state_res::resolve(
&RoomVersionId::V6,
@ -246,7 +247,7 @@ impl<E: Event + Clone> TestStore<E> {
}
}
impl TestStore<PduEvent> {
impl TestStore<Pdu> {
#[allow(clippy::type_complexity)]
fn set_up(
&mut self,
@ -380,7 +381,7 @@ fn to_pdu_event<S>(
content: Box<RawJsonValue>,
auth_events: &[S],
prev_events: &[S],
) -> PduEvent
) -> Pdu
where
S: AsRef<str>,
{
@ -403,30 +404,28 @@ where
.map(event_id)
.collect::<Vec<_>>();
let state_key = state_key.map(ToOwned::to_owned);
PduEvent {
Pdu {
event_id: id.try_into().unwrap(),
rest: Pdu::RoomV3Pdu(RoomV3Pdu {
room_id: room_id().to_owned(),
sender: sender.to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()),
state_key,
kind: ev_type,
content,
redacts: None,
unsigned: btreemap! {},
auth_events,
prev_events,
depth: uint!(0),
hashes: EventHash::new(String::new()),
signatures: Signatures::new(),
}),
room_id: room_id().to_owned(),
sender: sender.to_owned(),
origin_server_ts: ts.try_into().unwrap(),
state_key: state_key.map(Into::into),
kind: ev_type,
content,
origin: None,
redacts: None,
unsigned: None,
auth_events,
prev_events,
depth: uint!(0),
hashes: EventHash { sha256: String::new() },
signatures: None,
}
}
// all graphs start with these input events
#[allow(non_snake_case)]
fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
fn INITIAL_EVENTS() -> HashMap<OwnedEventId, Pdu> {
vec![
to_pdu_event::<&EventId>(
"CREATE",
@ -508,7 +507,7 @@ fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
// all graphs start with these input events
#[allow(non_snake_case)]
fn BAN_STATE_SET() -> HashMap<OwnedEventId, PduEvent> {
fn BAN_STATE_SET() -> HashMap<OwnedEventId, Pdu> {
vec![
to_pdu_event(
"PA",
@ -551,119 +550,3 @@ fn BAN_STATE_SET() -> HashMap<OwnedEventId, PduEvent> {
.map(|ev| (ev.event_id().to_owned(), ev))
.collect()
}
/// Convenience trait for adding event type plus state key to state maps.
trait EventTypeExt {
fn with_state_key(self, state_key: impl Into<String>) -> (StateEventType, String);
}
impl EventTypeExt for &TimelineEventType {
fn with_state_key(self, state_key: impl Into<String>) -> (StateEventType, String) {
(self.to_string().into(), state_key.into())
}
}
mod event {
use ruma::{
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
events::{TimelineEventType, pdu::Pdu},
};
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue;
use super::Event;
impl Event for PduEvent {
fn event_id(&self) -> &EventId { &self.event_id }
fn room_id(&self) -> &RoomId {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.room_id,
| Pdu::RoomV3Pdu(ev) => &ev.room_id,
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn sender(&self) -> &UserId {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.sender,
| Pdu::RoomV3Pdu(ev) => &ev.sender,
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn event_type(&self) -> &TimelineEventType {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.kind,
| Pdu::RoomV3Pdu(ev) => &ev.kind,
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn content(&self) -> &RawJsonValue {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.content,
| Pdu::RoomV3Pdu(ev) => &ev.content,
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => ev.origin_server_ts,
| Pdu::RoomV3Pdu(ev) => ev.origin_server_ts,
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn state_key(&self) -> Option<&str> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => ev.state_key.as_deref(),
| Pdu::RoomV3Pdu(ev) => ev.state_key.as_deref(),
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) =>
Box::new(ev.prev_events.iter().map(|(id, _)| id.as_ref())),
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter().map(AsRef::as_ref)),
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) =>
Box::new(ev.auth_events.iter().map(|(id, _)| id.as_ref())),
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter().map(AsRef::as_ref)),
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
fn redacts(&self) -> Option<&EventId> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_deref(),
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_deref(),
#[cfg(not(feature = "unstable-exhaustive-types"))]
| _ => unreachable!("new PDU version"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub(crate) struct PduEvent {
pub(crate) event_id: OwnedEventId,
#[serde(flatten)]
pub(crate) rest: Pdu,
}
}

View file

@ -136,17 +136,17 @@ pub fn auth_types_for_event(
event_id = incoming_event.event_id().as_str(),
)
)]
pub async fn auth_check<F, Fut, Fetched, Incoming>(
pub async fn auth_check<E, F, Fut>(
room_version: &RoomVersion,
incoming_event: &Incoming,
current_third_party_invite: Option<&Incoming>,
incoming_event: &E,
current_third_party_invite: Option<&E>,
fetch_state: F,
) -> Result<bool, Error>
where
F: Fn(&StateEventType, &str) -> Fut + Send,
Fut: Future<Output = Option<Fetched>> + Send,
Fetched: Event + Send,
Incoming: Event + Send + Sync,
Fut: Future<Output = Option<E>> + Send,
E: Event + Send + Sync,
for<'a> &'a E: Event + Send,
{
debug!(
event_id = format!("{}", incoming_event.event_id()),
@ -514,20 +514,24 @@ where
/// event and the current State.
#[allow(clippy::too_many_arguments)]
#[allow(clippy::cognitive_complexity)]
fn valid_membership_change(
fn valid_membership_change<E>(
room_version: &RoomVersion,
target_user: &UserId,
target_user_membership_event: Option<&impl Event>,
target_user_membership_event: Option<&E>,
sender: &UserId,
sender_membership_event: Option<&impl Event>,
current_event: impl Event,
current_third_party_invite: Option<&impl Event>,
power_levels_event: Option<&impl Event>,
join_rules_event: Option<&impl Event>,
sender_membership_event: Option<&E>,
current_event: &E,
current_third_party_invite: Option<&E>,
power_levels_event: Option<&E>,
join_rules_event: Option<&E>,
user_for_join_auth: Option<&UserId>,
user_for_join_auth_membership: &MembershipState,
create_room: &impl Event,
) -> Result<bool> {
create_room: &E,
) -> Result<bool>
where
E: Event + Send + Sync,
for<'a> &'a E: Event + Send,
{
#[derive(Deserialize)]
struct GetThirdPartyInvite {
third_party_invite: Option<Raw<ThirdPartyInvite>>,
@ -820,7 +824,7 @@ fn valid_membership_change(
///
/// Does the event have the correct userId as its state_key if it's not the ""
/// state_key.
fn can_send_event(event: impl Event, ple: Option<impl Event>, user_level: Int) -> bool {
fn can_send_event(event: &impl Event, ple: Option<&impl Event>, user_level: Int) -> bool {
let event_type_power_level = get_send_level(event.event_type(), event.state_key(), ple);
debug!(
@ -846,8 +850,8 @@ fn can_send_event(event: impl Event, ple: Option<impl Event>, user_level: Int) -
/// Confirm that the event sender has the required power levels.
fn check_power_levels(
room_version: &RoomVersion,
power_event: impl Event,
previous_power_event: Option<impl Event>,
power_event: &impl Event,
previous_power_event: Option<&impl Event>,
user_level: Int,
) -> Option<bool> {
match power_event.state_key() {
@ -1010,7 +1014,7 @@ fn get_deserialize_levels(
/// given event.
fn check_redaction(
_room_version: &RoomVersion,
redaction_event: impl Event,
redaction_event: &impl Event,
user_level: Int,
redact_level: Int,
) -> Result<bool> {
@ -1039,7 +1043,7 @@ fn check_redaction(
fn get_send_level(
e_type: &TimelineEventType,
state_key: Option<&str>,
power_lvl: Option<impl Event>,
power_lvl: Option<&impl Event>,
) -> Int {
power_lvl
.and_then(|ple| {
@ -1062,7 +1066,7 @@ fn verify_third_party_invite(
target_user: Option<&UserId>,
sender: &UserId,
tp_id: &ThirdPartyInvite,
current_third_party_invite: Option<impl Event>,
current_third_party_invite: Option<&impl Event>,
) -> bool {
// 1. Check for user being banned happens before this is called
// checking for mxid and token keys is done by ruma when deserializing
@ -1128,12 +1132,15 @@ mod tests {
};
use serde_json::value::to_raw_value as to_raw_json_value;
use crate::state_res::{
Event, EventTypeExt, RoomVersion, StateMap,
event_auth::valid_membership_change,
test_utils::{
INITIAL_EVENTS, INITIAL_EVENTS_CREATE_ROOM, PduEvent, alice, charlie, ella, event_id,
member_content_ban, member_content_join, room_id, to_pdu_event,
use crate::{
matrix::{Event, EventTypeExt, Pdu as PduEvent},
state_res::{
RoomVersion, StateMap,
event_auth::valid_membership_change,
test_utils::{
INITIAL_EVENTS, INITIAL_EVENTS_CREATE_ROOM, alice, charlie, ella, event_id,
member_content_ban, member_content_join, room_id, to_pdu_event,
},
},
};

View file

@ -37,7 +37,7 @@ pub use self::{
};
use crate::{
debug, debug_error,
matrix::{event::Event, pdu::StateKey},
matrix::{Event, StateKey},
trace,
utils::stream::{BroadbandExt, IterStream, ReadyExt, TryBroadbandExt, WidebandExt},
warn,
@ -90,7 +90,7 @@ where
SetIter: Iterator<Item = &'a StateMap<OwnedEventId>> + Clone + Send,
Hasher: BuildHasher + Send + Sync,
E: Event + Clone + Send + Sync,
for<'b> &'b E: Send,
for<'b> &'b E: Event + Send,
{
debug!("State resolution starting");
@ -522,6 +522,7 @@ where
Fut: Future<Output = Option<E>> + Send,
S: Stream<Item = &'a EventId> + Send + 'a,
E: Event + Clone + Send + Sync,
for<'b> &'b E: Event + Send,
{
debug!("starting iterative auth check");
@ -552,7 +553,7 @@ where
let auth_events = &auth_events;
let mut resolved_state = unconflicted_state;
for event in &events_to_check {
for event in events_to_check {
let state_key = event
.state_key()
.ok_or_else(|| Error::InvalidPdu("State event had no state key".to_owned()))?;
@ -607,11 +608,15 @@ where
});
let fetch_state = |ty: &StateEventType, key: &str| {
future::ready(auth_state.get(&ty.with_state_key(key)))
future::ready(
auth_state
.get(&ty.with_state_key(key))
.map(ToOwned::to_owned),
)
};
let auth_result =
auth_check(room_version, &event, current_third_party.as_ref(), fetch_state).await;
auth_check(room_version, &event, current_third_party, fetch_state).await;
match auth_result {
| Ok(true) => {
@ -794,11 +799,11 @@ where
}
}
fn is_type_and_key(ev: impl Event, ev_type: &TimelineEventType, state_key: &str) -> bool {
fn is_type_and_key(ev: &impl Event, ev_type: &TimelineEventType, state_key: &str) -> bool {
ev.event_type() == ev_type && ev.state_key() == Some(state_key)
}
fn is_power_event(event: impl Event) -> bool {
fn is_power_event(event: &impl Event) -> bool {
match event.event_type() {
| TimelineEventType::RoomPowerLevels
| TimelineEventType::RoomJoinRules
@ -859,15 +864,19 @@ mod tests {
use serde_json::{json, value::to_raw_value as to_raw_json_value};
use super::{
Event, EventTypeExt, StateMap, is_power_event,
StateMap, is_power_event,
room_version::RoomVersion,
test_utils::{
INITIAL_EVENTS, PduEvent, TestStore, alice, bob, charlie, do_check, ella, event_id,
INITIAL_EVENTS, TestStore, alice, bob, charlie, do_check, ella, event_id,
member_content_ban, member_content_join, room_id, to_init_pdu_event, to_pdu_event,
zara,
},
};
use crate::{debug, utils::stream::IterStream};
use crate::{
debug,
matrix::{Event, EventTypeExt, Pdu as PduEvent},
utils::stream::IterStream,
};
async fn test_event_sort() {
use futures::future::ready;

View file

@ -10,7 +10,6 @@ use ruma::{
UserId, event_id,
events::{
TimelineEventType,
pdu::{EventHash, Pdu, RoomV3Pdu},
room::{
join_rules::{JoinRule, RoomJoinRulesEventContent},
member::{MembershipState, RoomMemberEventContent},
@ -23,17 +22,16 @@ use serde_json::{
value::{RawValue as RawJsonValue, to_raw_value as to_raw_json_value},
};
pub(crate) use self::event::PduEvent;
use super::auth_types_for_event;
use crate::{
Result, info,
matrix::{Event, EventTypeExt, StateMap},
matrix::{Event, EventTypeExt, Pdu, StateMap, pdu::EventHash},
};
static SERVER_TIMESTAMP: AtomicU64 = AtomicU64::new(0);
pub(crate) async fn do_check(
events: &[PduEvent],
events: &[Pdu],
edges: Vec<Vec<OwnedEventId>>,
expected_state_ids: Vec<OwnedEventId>,
) {
@ -81,8 +79,8 @@ pub(crate) async fn do_check(
}
}
// event_id -> PduEvent
let mut event_map: HashMap<OwnedEventId, PduEvent> = HashMap::new();
// event_id -> Pdu
let mut event_map: HashMap<OwnedEventId, Pdu> = HashMap::new();
// event_id -> StateMap<OwnedEventId>
let mut state_at_event: HashMap<OwnedEventId, StateMap<OwnedEventId>> = HashMap::new();
@ -265,7 +263,7 @@ impl<E: Event + Clone> TestStore<E> {
// A StateStore implementation for testing
#[allow(clippy::type_complexity)]
impl TestStore<PduEvent> {
impl TestStore<Pdu> {
pub(crate) fn set_up(
&mut self,
) -> (StateMap<OwnedEventId>, StateMap<OwnedEventId>, StateMap<OwnedEventId>) {
@ -390,7 +388,7 @@ pub(crate) fn to_init_pdu_event(
ev_type: TimelineEventType,
state_key: Option<&str>,
content: Box<RawJsonValue>,
) -> PduEvent {
) -> Pdu {
let ts = SERVER_TIMESTAMP.fetch_add(1, SeqCst);
let id = if id.contains('$') {
id.to_owned()
@ -398,24 +396,22 @@ pub(crate) fn to_init_pdu_event(
format!("${id}:foo")
};
let state_key = state_key.map(ToOwned::to_owned);
PduEvent {
Pdu {
event_id: id.try_into().unwrap(),
rest: Pdu::RoomV3Pdu(RoomV3Pdu {
room_id: room_id().to_owned(),
sender: sender.to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()),
state_key,
kind: ev_type,
content,
redacts: None,
unsigned: BTreeMap::new(),
auth_events: vec![],
prev_events: vec![],
depth: uint!(0),
hashes: EventHash::new("".to_owned()),
signatures: ServerSignatures::default(),
}),
room_id: room_id().to_owned(),
sender: sender.to_owned(),
origin_server_ts: ts.try_into().unwrap(),
state_key: state_key.map(Into::into),
kind: ev_type,
content,
origin: None,
redacts: None,
unsigned: None,
auth_events: vec![],
prev_events: vec![],
depth: uint!(0),
hashes: EventHash { sha256: "".to_owned() },
signatures: None,
}
}
@ -427,7 +423,7 @@ pub(crate) fn to_pdu_event<S>(
content: Box<RawJsonValue>,
auth_events: &[S],
prev_events: &[S],
) -> PduEvent
) -> Pdu
where
S: AsRef<str>,
{
@ -448,30 +444,28 @@ where
.map(event_id)
.collect::<Vec<_>>();
let state_key = state_key.map(ToOwned::to_owned);
PduEvent {
Pdu {
event_id: id.try_into().unwrap(),
rest: Pdu::RoomV3Pdu(RoomV3Pdu {
room_id: room_id().to_owned(),
sender: sender.to_owned(),
origin_server_ts: MilliSecondsSinceUnixEpoch(ts.try_into().unwrap()),
state_key,
kind: ev_type,
content,
redacts: None,
unsigned: BTreeMap::new(),
auth_events,
prev_events,
depth: uint!(0),
hashes: EventHash::new("".to_owned()),
signatures: ServerSignatures::default(),
}),
room_id: room_id().to_owned(),
sender: sender.to_owned(),
origin_server_ts: ts.try_into().unwrap(),
state_key: state_key.map(Into::into),
kind: ev_type,
content,
origin: None,
redacts: None,
unsigned: None,
auth_events,
prev_events,
depth: uint!(0),
hashes: EventHash { sha256: "".to_owned() },
signatures: None,
}
}
// all graphs start with these input events
#[allow(non_snake_case)]
pub(crate) fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
pub(crate) fn INITIAL_EVENTS() -> HashMap<OwnedEventId, Pdu> {
vec![
to_pdu_event::<&EventId>(
"CREATE",
@ -553,7 +547,7 @@ pub(crate) fn INITIAL_EVENTS() -> HashMap<OwnedEventId, PduEvent> {
// all graphs start with these input events
#[allow(non_snake_case)]
pub(crate) fn INITIAL_EVENTS_CREATE_ROOM() -> HashMap<OwnedEventId, PduEvent> {
pub(crate) fn INITIAL_EVENTS_CREATE_ROOM() -> HashMap<OwnedEventId, Pdu> {
vec![to_pdu_event::<&EventId>(
"CREATE",
alice(),
@ -575,111 +569,3 @@ pub(crate) fn INITIAL_EDGES() -> Vec<OwnedEventId> {
.map(event_id)
.collect::<Vec<_>>()
}
pub(crate) mod event {
use ruma::{
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, RoomId, UserId,
events::{TimelineEventType, pdu::Pdu},
};
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue as RawJsonValue;
use crate::Event;
impl Event for PduEvent {
fn event_id(&self) -> &EventId { &self.event_id }
fn room_id(&self) -> &RoomId {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.room_id,
| Pdu::RoomV3Pdu(ev) => &ev.room_id,
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
fn sender(&self) -> &UserId {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.sender,
| Pdu::RoomV3Pdu(ev) => &ev.sender,
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
fn event_type(&self) -> &TimelineEventType {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.kind,
| Pdu::RoomV3Pdu(ev) => &ev.kind,
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
fn content(&self) -> &RawJsonValue {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => &ev.content,
| Pdu::RoomV3Pdu(ev) => &ev.content,
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => ev.origin_server_ts,
| Pdu::RoomV3Pdu(ev) => ev.origin_server_ts,
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
fn state_key(&self) -> Option<&str> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => ev.state_key.as_deref(),
| Pdu::RoomV3Pdu(ev) => ev.state_key.as_deref(),
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
#[allow(refining_impl_trait)]
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) =>
Box::new(ev.prev_events.iter().map(|(id, _)| id.as_ref())),
| Pdu::RoomV3Pdu(ev) => Box::new(ev.prev_events.iter().map(AsRef::as_ref)),
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
#[allow(refining_impl_trait)]
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &EventId> + Send + '_> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) =>
Box::new(ev.auth_events.iter().map(|(id, _)| id.as_ref())),
| Pdu::RoomV3Pdu(ev) => Box::new(ev.auth_events.iter().map(AsRef::as_ref)),
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
fn redacts(&self) -> Option<&EventId> {
match &self.rest {
| Pdu::RoomV1Pdu(ev) => ev.redacts.as_deref(),
| Pdu::RoomV3Pdu(ev) => ev.redacts.as_deref(),
#[allow(unreachable_patterns)]
| _ => unreachable!("new PDU version"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[allow(clippy::exhaustive_structs)]
pub(crate) struct PduEvent {
pub(crate) event_id: OwnedEventId,
#[serde(flatten)]
pub(crate) rest: Pdu,
}
}

View file

@ -25,7 +25,9 @@ pub use info::{
rustc_flags_capture, version,
version::{name, version},
};
pub use matrix::{Event, EventTypeExt, PduCount, PduEvent, PduId, RoomVersion, pdu, state_res};
pub use matrix::{
Event, EventTypeExt, Pdu, PduCount, PduEvent, PduId, RoomVersion, pdu, state_res,
};
pub use server::Server;
pub use utils::{ctor, dtor, implement, result, result::Result};