170 lines
6.6 KiB
Rust
170 lines
6.6 KiB
Rust
use js_int::Int;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};
|
|
|
|
use super::{relation::Relations, room::redaction::SyncRoomRedactionEvent, StateEventContent};
|
|
use crate::{
|
|
serde::{CanBeEmpty, Raw},
|
|
OwnedTransactionId,
|
|
};
|
|
|
|
/// Extra information about a message event that is not incorporated into the event's hash.
|
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
|
pub struct MessageLikeUnsigned {
|
|
/// The time in milliseconds that has elapsed since the event was sent.
|
|
///
|
|
/// This field is generated by the local homeserver, and may be incorrect if the local time on
|
|
/// at least one of the two servers is out of sync, which can cause the age to either be
|
|
/// negative or greater than it actually is.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub age: Option<Int>,
|
|
|
|
/// The client-supplied transaction ID, if the client being given the event is the same one
|
|
/// which sent it.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub transaction_id: Option<OwnedTransactionId>,
|
|
|
|
/// [Bundled aggregations] of related child events.
|
|
///
|
|
/// [Bundled aggregations]: https://spec.matrix.org/v1.3/client-server-api/#aggregations
|
|
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
|
|
pub relations: Option<Relations>,
|
|
}
|
|
|
|
impl MessageLikeUnsigned {
|
|
/// Create a new `Unsigned` with fields set to `None`.
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
}
|
|
|
|
impl CanBeEmpty for MessageLikeUnsigned {
|
|
/// Whether this unsigned data is empty (all fields are `None`).
|
|
///
|
|
/// This method is used to determine whether to skip serializing the `unsigned` field in room
|
|
/// events. Do not use it to determine whether an incoming `unsigned` field was present - it
|
|
/// could still have been present but contained none of the known fields.
|
|
fn is_empty(&self) -> bool {
|
|
self.age.is_none() && self.transaction_id.is_none() && self.relations.is_none()
|
|
}
|
|
}
|
|
|
|
/// Extra information about a state event that is not incorporated into the event's hash.
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
|
pub struct StateUnsigned<C: StateEventContent> {
|
|
/// The time in milliseconds that has elapsed since the event was sent.
|
|
///
|
|
/// This field is generated by the local homeserver, and may be incorrect if the local time on
|
|
/// at least one of the two servers is out of sync, which can cause the age to either be
|
|
/// negative or greater than it actually is.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub age: Option<Int>,
|
|
|
|
/// The client-supplied transaction ID, if the client being given the event is the same one
|
|
/// which sent it.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub transaction_id: Option<OwnedTransactionId>,
|
|
|
|
/// Optional previous content of the event.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub prev_content: Option<C>,
|
|
|
|
/// [Bundled aggregations] of related child events.
|
|
///
|
|
/// [Bundled aggregations]: https://spec.matrix.org/v1.3/client-server-api/#aggregations
|
|
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
|
|
pub relations: Option<Relations>,
|
|
}
|
|
|
|
impl<C: StateEventContent> StateUnsigned<C> {
|
|
/// Create a new `Unsigned` with fields set to `None`.
|
|
pub fn new() -> Self {
|
|
Self { age: None, transaction_id: None, prev_content: None, relations: None }
|
|
}
|
|
}
|
|
|
|
impl<C: StateEventContent> CanBeEmpty for StateUnsigned<C> {
|
|
/// Whether this unsigned data is empty (all fields are `None`).
|
|
///
|
|
/// This method is used to determine whether to skip serializing the `unsigned` field in room
|
|
/// events. Do not use it to determine whether an incoming `unsigned` field was present - it
|
|
/// could still have been present but contained none of the known fields.
|
|
fn is_empty(&self) -> bool {
|
|
self.age.is_none()
|
|
&& self.transaction_id.is_none()
|
|
&& self.prev_content.is_none()
|
|
&& self.relations.is_none()
|
|
}
|
|
}
|
|
|
|
/// Helper functions for proc-macro code.
|
|
///
|
|
/// Needs to be public for UI tests.
|
|
#[doc(hidden)]
|
|
impl<C: StateEventContent> StateUnsigned<C> {
|
|
pub fn _from_parts(event_type: &str, object: &RawJsonValue) -> serde_json::Result<Self> {
|
|
#[derive(Deserialize)]
|
|
#[serde(bound = "")] // Disable default C: Deserialize bound
|
|
struct WithRawPrevContent<C> {
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
age: Option<Int>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
transaction_id: Option<OwnedTransactionId>,
|
|
prev_content: Option<Raw<C>>,
|
|
#[serde(rename = "m.relations", skip_serializing_if = "Option::is_none")]
|
|
relations: Option<Relations>,
|
|
}
|
|
|
|
let raw: WithRawPrevContent<C> = from_json_str(object.get())?;
|
|
let prev_content =
|
|
raw.prev_content.map(|r| r.deserialize_content(event_type.into())).transpose()?;
|
|
|
|
Ok(Self {
|
|
age: raw.age,
|
|
transaction_id: raw.transaction_id,
|
|
relations: raw.relations,
|
|
prev_content,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<C: StateEventContent> Default for StateUnsigned<C> {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
/// Extra information about a redacted event that is not incorporated into the event's hash.
|
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
|
pub struct RedactedUnsigned {
|
|
/// The event that redacted this event, if any.
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub redacted_because: Option<Box<SyncRoomRedactionEvent>>,
|
|
}
|
|
|
|
impl RedactedUnsigned {
|
|
/// Create a new `RedactedUnsigned` with field set to `None`.
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
/// Create a new `RedactedUnsigned` with the given redacted because.
|
|
pub fn new_because(redacted_because: Box<SyncRoomRedactionEvent>) -> Self {
|
|
Self { redacted_because: Some(redacted_because) }
|
|
}
|
|
}
|
|
|
|
impl CanBeEmpty for RedactedUnsigned {
|
|
/// Whether this unsigned data is empty (`redacted_because` is `None`).
|
|
///
|
|
/// This method is used to determine whether to skip serializing the `unsigned` field in
|
|
/// redacted room events. Do not use it to determine whether an incoming `unsigned` field
|
|
/// was present - it could still have been present but contained none of the known fields.
|
|
fn is_empty(&self) -> bool {
|
|
self.redacted_because.is_none()
|
|
}
|
|
}
|