mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-13 12:16:54 +00:00
feat: Create versioned PDU types
This commit is contained in:
6 files changed
+299
-9
No files matched your search
@@ -143,8 +143,6 @@ pub trait Event: Clone + Debug {
|
||||
|
||||
fn into_pdu(self) -> Pdu;
|
||||
|
||||
fn is_owned(&self) -> bool;
|
||||
|
||||
//
|
||||
// Canonical properties
|
||||
//
|
||||
@@ -182,12 +180,12 @@ pub trait Event: Clone + Debug {
|
||||
fn state_key(&self) -> Option<&str>;
|
||||
|
||||
/// The event type.
|
||||
// #[deprecated]
|
||||
fn kind(&self) -> &TimelineEventType;
|
||||
|
||||
/// Metadata container; peer-trusted only.
|
||||
fn unsigned(&self) -> Option<&RawJsonValue>;
|
||||
|
||||
//#[deprecated]
|
||||
#[inline]
|
||||
fn event_type(&self) -> &TimelineEventType { self.kind() }
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
mod count;
|
||||
pub mod hashes;
|
||||
mod id;
|
||||
pub mod metadata;
|
||||
mod partial;
|
||||
mod raw_id;
|
||||
mod redact;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod unsigned;
|
||||
pub mod v2;
|
||||
pub mod v3;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
@@ -151,9 +155,6 @@ impl Event for Pdu {
|
||||
|
||||
#[inline]
|
||||
fn into_pdu(self) -> Pdu { self }
|
||||
|
||||
#[inline]
|
||||
fn is_owned(&self) -> bool { true }
|
||||
}
|
||||
|
||||
impl Event for &Pdu {
|
||||
@@ -219,9 +220,6 @@ impl Event for &Pdu {
|
||||
|
||||
#[inline]
|
||||
fn into_pdu(self) -> Pdu { self.clone() }
|
||||
|
||||
#[inline]
|
||||
fn is_owned(&self) -> bool { false }
|
||||
}
|
||||
|
||||
/// Prevent derived equality which wouldn't limit itself to event_id
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The content hash map for a PDU.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Hashes {
|
||||
/// The SHA256 content hash.
|
||||
pub sha256: String,
|
||||
|
||||
/// Any other hashes present, if any.
|
||||
#[serde(flatten, default, skip_serializing_if = "HashMap::is_empty")]
|
||||
pub other: HashMap<String, String>,
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
use ruma::OwnedEventId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct PduMetadata {
|
||||
/// This event's calculated event ID.
|
||||
pub event_id: OwnedEventId,
|
||||
|
||||
/// Indicates whether the event has been rejected under auth rules.
|
||||
pub rejected: bool,
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
use ruma::{
|
||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId,
|
||||
ServerSignatures, UInt, UserId, events::TimelineEventType,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use crate::{
|
||||
Pdu,
|
||||
pdu::{hashes::Hashes, metadata::PduMetadata},
|
||||
};
|
||||
|
||||
/// Represents a persistent data unit (PDU) version 2, introduced in room
|
||||
/// version 3, up until room version 11.
|
||||
///
|
||||
/// Spec: https://spec.matrix.org/v1.19/rooms/v3/#event-format
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct PDU {
|
||||
/// The event IDs which authorise this event. Between 0 and 10 entries.
|
||||
pub auth_events: Vec<OwnedEventId>,
|
||||
/// This event's content.
|
||||
pub content: Box<RawJsonValue>,
|
||||
/// The depth of this event.
|
||||
pub depth: UInt,
|
||||
/// The content hashes for this event.
|
||||
pub hashes: Hashes,
|
||||
/// Timestamp in milliseconds on origin homeserver when this event was
|
||||
/// created.
|
||||
pub origin_server_ts: MilliSecondsSinceUnixEpoch,
|
||||
/// The event IDs which immediately precede this event. Between 0 and 20
|
||||
/// entries.
|
||||
pub prev_events: Vec<OwnedEventId>,
|
||||
/// For redaction events, the ID of the event being redacted.
|
||||
///
|
||||
/// Not used in v11.
|
||||
pub redacts: Option<OwnedEventId>,
|
||||
/// The room in which this event resides.
|
||||
pub room_id: OwnedRoomId,
|
||||
/// The user who sent this event.
|
||||
pub sender: OwnedUserId,
|
||||
/// The signatures on this event.
|
||||
pub signatures: ServerSignatures,
|
||||
/// The state key for this PDU, if any.
|
||||
pub state_key: Option<String>,
|
||||
/// The type of this PDU.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: TimelineEventType,
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
///
|
||||
/// This should be `None` when receiving from and transmitting over
|
||||
/// federation.
|
||||
pub unsigned: Option<Box<RawJsonValue>>,
|
||||
|
||||
pub internal_metadata: PduMetadata,
|
||||
}
|
||||
|
||||
impl PDU {
|
||||
#[must_use]
|
||||
pub fn internal_metadata(&self) -> &PduMetadata { &self.internal_metadata }
|
||||
}
|
||||
|
||||
impl ruma::state_res::Event for PDU {
|
||||
type Id = OwnedEventId;
|
||||
|
||||
fn event_id(&self) -> &Self::Id { &self.internal_metadata.event_id }
|
||||
|
||||
fn room_id(&self) -> Option<&RoomId> { Some(&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.as_ref() }
|
||||
|
||||
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
||||
|
||||
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + '_> {
|
||||
Box::new(self.prev_events.iter())
|
||||
}
|
||||
|
||||
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + '_> {
|
||||
Box::new(self.auth_events.iter())
|
||||
}
|
||||
|
||||
fn redacts(&self) -> Option<&Self::Id> { self.redacts.as_ref() }
|
||||
|
||||
fn rejected(&self) -> bool { self.internal_metadata().rejected }
|
||||
}
|
||||
|
||||
impl super::Event for PDU {
|
||||
fn as_pdu(&self) -> &Pdu { todo!() }
|
||||
|
||||
fn into_pdu(self) -> Pdu { todo!() }
|
||||
|
||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Clone + Send + '_ {
|
||||
self.auth_events.iter().map(AsRef::as_ref)
|
||||
}
|
||||
|
||||
fn content(&self) -> &RawJsonValue { self.content.as_ref() }
|
||||
|
||||
fn event_id(&self) -> &EventId { &self.internal_metadata.event_id }
|
||||
|
||||
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { self.origin_server_ts }
|
||||
|
||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Clone + Send + '_ {
|
||||
self.prev_events.iter().map(AsRef::as_ref)
|
||||
}
|
||||
|
||||
fn redacts(&self) -> Option<&EventId> { self.redacts.as_deref() }
|
||||
|
||||
fn room_id(&self) -> Option<&RoomId> { Some(&self.room_id) }
|
||||
|
||||
fn room_id_or_hash(&self) -> OwnedRoomId { self.room_id.clone() }
|
||||
|
||||
fn sender(&self) -> &UserId { &self.sender }
|
||||
|
||||
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
||||
|
||||
fn kind(&self) -> &TimelineEventType { self.event_type() }
|
||||
|
||||
fn unsigned(&self) -> Option<&RawJsonValue> { self.unsigned.as_deref() }
|
||||
|
||||
fn event_type(&self) -> &TimelineEventType { &self.event_type }
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
use ruma::{
|
||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId,
|
||||
ServerSignatures, UInt, UserId,
|
||||
events::{StateEventType, TimelineEventType},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
|
||||
use crate::{
|
||||
Pdu,
|
||||
pdu::{hashes::Hashes, metadata::PduMetadata},
|
||||
};
|
||||
|
||||
/// Represents a persistent data unit (PDU) version 3, introduced in room
|
||||
/// version 12.
|
||||
///
|
||||
/// Spec: https://spec.matrix.org/v1.19/rooms/v12/#event-format
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct PDU {
|
||||
/// The event IDs which authorise this event. Between 0 and 10 entries.
|
||||
pub auth_events: Vec<OwnedEventId>,
|
||||
/// This event's content.
|
||||
pub content: Box<RawJsonValue>,
|
||||
/// The depth of this event.
|
||||
pub depth: UInt,
|
||||
/// The content hashes for this event.
|
||||
pub hashes: Hashes,
|
||||
/// Timestamp in milliseconds on origin homeserver when this event was
|
||||
/// created.
|
||||
pub origin_server_ts: MilliSecondsSinceUnixEpoch,
|
||||
/// The event IDs which immediately precede this event. Between 0 and 20
|
||||
/// entries.
|
||||
pub prev_events: Vec<OwnedEventId>,
|
||||
/// The room in which this event resides.
|
||||
/// May be None if the event is a create event.
|
||||
pub room_id: Option<OwnedRoomId>,
|
||||
/// The user who sent this event.
|
||||
pub sender: OwnedUserId,
|
||||
/// The signatures on this event.
|
||||
pub signatures: ServerSignatures,
|
||||
/// The state key for this PDU, if any.
|
||||
pub state_key: Option<String>,
|
||||
/// The type of this PDU.
|
||||
#[serde(rename = "type")]
|
||||
pub event_type: TimelineEventType,
|
||||
/// Additional data added by the origin server but not covered by the
|
||||
/// signatures.
|
||||
///
|
||||
/// This should be `None` when receiving from and transmitting over
|
||||
/// federation.
|
||||
pub unsigned: Option<Box<RawJsonValue>>,
|
||||
|
||||
pub internal_metadata: PduMetadata,
|
||||
}
|
||||
|
||||
impl PDU {
|
||||
#[must_use]
|
||||
pub fn internal_metadata(&self) -> &PduMetadata { &self.internal_metadata }
|
||||
}
|
||||
|
||||
impl ruma::state_res::Event for PDU {
|
||||
type Id = OwnedEventId;
|
||||
|
||||
fn event_id(&self) -> &Self::Id { &self.internal_metadata.event_id }
|
||||
|
||||
fn room_id(&self) -> Option<&RoomId> { self.room_id.as_deref() }
|
||||
|
||||
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.as_ref() }
|
||||
|
||||
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
||||
|
||||
fn prev_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + '_> {
|
||||
Box::new(self.prev_events.iter())
|
||||
}
|
||||
|
||||
fn auth_events(&self) -> Box<dyn DoubleEndedIterator<Item = &Self::Id> + '_> {
|
||||
Box::new(self.auth_events.iter())
|
||||
}
|
||||
|
||||
fn redacts(&self) -> Option<&Self::Id> { None }
|
||||
|
||||
fn rejected(&self) -> bool { self.internal_metadata().rejected }
|
||||
}
|
||||
|
||||
impl super::Event for PDU {
|
||||
fn as_pdu(&self) -> &Pdu { todo!() }
|
||||
|
||||
fn into_pdu(self) -> Pdu { todo!() }
|
||||
|
||||
fn auth_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Clone + Send + '_ {
|
||||
self.auth_events.iter().map(AsRef::as_ref)
|
||||
}
|
||||
|
||||
fn content(&self) -> &RawJsonValue { self.content.as_ref() }
|
||||
|
||||
fn event_id(&self) -> &EventId { &self.internal_metadata.event_id }
|
||||
|
||||
fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch { self.origin_server_ts }
|
||||
|
||||
fn prev_events(&self) -> impl DoubleEndedIterator<Item = &EventId> + Clone + Send + '_ {
|
||||
self.prev_events.iter().map(AsRef::as_ref)
|
||||
}
|
||||
|
||||
fn redacts(&self) -> Option<&EventId> { None }
|
||||
|
||||
fn room_id(&self) -> Option<&RoomId> { self.room_id.as_deref() }
|
||||
|
||||
fn room_id_or_hash(&self) -> OwnedRoomId {
|
||||
if self.event_type == StateEventType::RoomCreate.into()
|
||||
&& self.state_key().is_some_and(str::is_empty)
|
||||
{
|
||||
// Calculate the room ID for a create event.
|
||||
RoomId::new_v2(
|
||||
self.internal_metadata()
|
||||
.event_id
|
||||
.as_str()
|
||||
.strip_prefix("$")
|
||||
.expect("event ID must start with $ sigil"),
|
||||
)
|
||||
.expect("must be able to create a room ID from create event reference hash")
|
||||
} else {
|
||||
// Otherwise, all other events have a room ID field.
|
||||
self.room_id.clone().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn sender(&self) -> &UserId { &self.sender }
|
||||
|
||||
fn state_key(&self) -> Option<&str> { self.state_key.as_deref() }
|
||||
|
||||
fn kind(&self) -> &TimelineEventType { self.event_type() }
|
||||
|
||||
fn unsigned(&self) -> Option<&RawJsonValue> { self.unsigned.as_deref() }
|
||||
|
||||
fn event_type(&self) -> &TimelineEventType { &self.event_type }
|
||||
}
|
||||
Reference in new issue
Block a user