From 2e8fc3e23203a42bd2eabe770f56c08b3353ee74 Mon Sep 17 00:00:00 2001 From: Devin R Date: Sat, 11 Jul 2020 21:12:40 -0400 Subject: [PATCH] matrix-sdk-base: Integrate redacted events into message queue Redact message events according to spec and ruma types. Remove content using events redact() method and insert the redacting event into the event being redacted. --- matrix_sdk/src/lib.rs | 2 + matrix_sdk_base/src/client.rs | 28 ++++-- matrix_sdk_base/src/event_emitter/mod.rs | 2 +- matrix_sdk_base/src/lib.rs | 11 ++- matrix_sdk_base/src/models/message.rs | 75 +++++++++++----- matrix_sdk_base/src/models/mod.rs | 3 + matrix_sdk_base/src/models/room.rs | 109 +++++++++++++++++------ matrix_sdk_common/Cargo.toml | 2 +- 8 files changed, 170 insertions(+), 62 deletions(-) diff --git a/matrix_sdk/src/lib.rs b/matrix_sdk/src/lib.rs index 6bdfd0dc..809b8e20 100644 --- a/matrix_sdk/src/lib.rs +++ b/matrix_sdk/src/lib.rs @@ -40,6 +40,8 @@ pub use matrix_sdk_base::Error as BaseError; #[cfg(not(target_arch = "wasm32"))] pub use matrix_sdk_base::JsonStore; pub use matrix_sdk_base::{CustomOrRawEvent, EventEmitter, Room, Session, SyncRoom}; +#[cfg(feature = "messages")] +pub use matrix_sdk_base::{FullOrRedactedEvent, MessageQueue, MessageWrapper}; pub use matrix_sdk_base::{RoomState, StateStore}; pub use matrix_sdk_common::*; pub use reqwest::header::InvalidHeaderValue; diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index 1c38b90c..660bfe1f 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -1511,6 +1511,8 @@ impl BaseClient { } _ => {} }, + AnyRoomEventStub::RedactedState(_event) => {} + AnyRoomEventStub::RedactedMessage(_event) => {} } } @@ -1836,7 +1838,7 @@ impl BaseClient { #[cfg(test)] mod test { - use crate::identifiers::{RoomId, UserId}; + use crate::identifiers::{EventId, RoomId, UserId}; use crate::{BaseClient, BaseClientConfig, Session}; use matrix_sdk_common::events::{AnyRoomEventStub, EventJson}; use matrix_sdk_common_macros::async_trait; @@ -2402,12 +2404,17 @@ mod test { // check that the message has actually been redacted for room in client.joined_rooms().read().await.values() { let queue = &room.read().await.messages; - if let crate::events::AnyMessageEventContent::RoomRedaction(content) = - &queue.msgs[0].content + if let crate::models::FullOrRedactedEvent::Redacted( + crate::events::AnyRedactedMessageEventStub::RoomMessage(event), + ) = &queue.msgs[0].deref() { - assert_eq!(content.reason, Some("😀".to_string())); + // this is the id from the message event in the sync response + assert_eq!( + event.event_id, + EventId::try_from("$152037280074GZeOm:localhost").unwrap() + ) } else { - panic!("[pre store sync] message event in message queue should be redacted") + panic!("message event in message queue should be redacted") } } @@ -2425,10 +2432,15 @@ mod test { // properly for room in client.joined_rooms().read().await.values() { let queue = &room.read().await.messages; - if let crate::events::AnyMessageEventContent::RoomRedaction(content) = - &queue.msgs[0].content + if let crate::models::FullOrRedactedEvent::Redacted( + crate::events::AnyRedactedMessageEventStub::RoomMessage(event), + ) = &queue.msgs[0].deref() { - assert_eq!(content.reason, Some("😀".to_string())); + // this is the id from the message event in the sync response + assert_eq!( + event.event_id, + EventId::try_from("$152037280074GZeOm:localhost").unwrap() + ) } else { panic!("[post store sync] message event in message queue should be redacted") } diff --git a/matrix_sdk_base/src/event_emitter/mod.rs b/matrix_sdk_base/src/event_emitter/mod.rs index e0722eb1..bb7c6420 100644 --- a/matrix_sdk_base/src/event_emitter/mod.rs +++ b/matrix_sdk_base/src/event_emitter/mod.rs @@ -581,7 +581,7 @@ mod test { "unrecognized event", "redaction", "unrecognized event", - "unrecognized event", + // "unrecognized event", this is actually a redacted "m.room.messages" event "receipt event", "typing event" ], diff --git a/matrix_sdk_base/src/lib.rs b/matrix_sdk_base/src/lib.rs index 1ca09880..ab7f1e77 100644 --- a/matrix_sdk_base/src/lib.rs +++ b/matrix_sdk_base/src/lib.rs @@ -47,11 +47,16 @@ mod state; pub use client::{BaseClient, BaseClientConfig, RoomState, RoomStateType}; pub use event_emitter::{CustomOrRawEvent, EventEmitter, SyncRoom}; +pub use models::Room; +pub use state::{AllRooms, ClientState}; + #[cfg(feature = "encryption")] pub use matrix_sdk_crypto::{Device, TrustState}; -pub use models::Room; -pub use state::AllRooms; -pub use state::ClientState; + +#[cfg(feature = "messages")] +#[cfg_attr(docsrs, doc(cfg(feature = "messages")))] +pub use models::{FullOrRedactedEvent, MessageQueue, MessageWrapper}; + #[cfg(not(target_arch = "wasm32"))] pub use state::JsonStore; pub use state::StateStore; diff --git a/matrix_sdk_base/src/models/message.rs b/matrix_sdk_base/src/models/message.rs index 4bb0aae2..401b258a 100644 --- a/matrix_sdk_base/src/models/message.rs +++ b/matrix_sdk_base/src/models/message.rs @@ -3,17 +3,50 @@ //! The `Room` struct optionally holds a `MessageQueue` if the "messages" //! feature is enabled. -use std::cmp::Ordering; -use std::ops::{Deref, DerefMut}; -use std::vec::IntoIter; +use std::{ + cmp::Ordering, + ops::{Deref, DerefMut}, + time::SystemTime, + vec::IntoIter, +}; -use crate::events::{AnyMessageEventContent, AnyMessageEventStub, MessageEventStub}; +use matrix_sdk_common::identifiers::EventId; +use serde::{de, ser, Deserialize, Serialize}; -use serde::{de, ser, Serialize}; +use crate::events::{AnyMessageEventStub, AnyRedactedMessageEventStub}; + +/// Represents either a redacted event or a non-redacted event. +/// +/// Note: ruma may create types that solve this. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum FullOrRedactedEvent { + /// A non-redacted event. + Full(AnyMessageEventStub), + /// An event that has been redacted. + Redacted(AnyRedactedMessageEventStub), +} + +impl FullOrRedactedEvent { + /// Access the underlying events `event_id`. + pub fn event_id(&self) -> &EventId { + match self { + Self::Full(e) => e.event_id(), + Self::Redacted(e) => e.event_id(), + } + } + + /// Access the underlying events `origin_server_ts`. + pub fn origin_server_ts(&self) -> &SystemTime { + match self { + Self::Full(e) => e.origin_server_ts(), + Self::Redacted(e) => e.origin_server_ts(), + } + } +} const MESSAGE_QUEUE_CAP: usize = 35; -pub type SyncMessageEvent = MessageEventStub; +pub type SyncMessageEvent = FullOrRedactedEvent; /// A queue that holds the 35 most recent messages received from the server. #[derive(Clone, Debug, Default)] @@ -29,18 +62,6 @@ pub struct MessageQueue { #[derive(Clone, Debug, Serialize)] pub struct MessageWrapper(pub SyncMessageEvent); -impl MessageWrapper { - pub fn clone_into_any_content(event: &AnyMessageEventStub) -> SyncMessageEvent { - MessageEventStub { - content: event.content(), - sender: event.sender().clone(), - origin_server_ts: *event.origin_server_ts(), - event_id: event.event_id().clone(), - unsigned: event.unsigned().clone(), - } - } -} - impl Deref for MessageWrapper { type Target = SyncMessageEvent; @@ -57,7 +78,7 @@ impl DerefMut for MessageWrapper { impl PartialEq for MessageWrapper { fn eq(&self, other: &MessageWrapper) -> bool { - self.0.event_id == other.0.event_id + self.0.event_id() == other.0.event_id() } } @@ -65,7 +86,7 @@ impl Eq for MessageWrapper {} impl PartialOrd for MessageWrapper { fn partial_cmp(&self, other: &MessageWrapper) -> Option { - Some(self.0.origin_server_ts.cmp(&other.0.origin_server_ts)) + Some(self.0.origin_server_ts().cmp(&other.0.origin_server_ts())) } } @@ -82,7 +103,7 @@ impl PartialEq for MessageQueue { .msgs .iter() .zip(other.msgs.iter()) - .all(|(msg_a, msg_b)| msg_a.event_id == msg_b.event_id) + .all(|(msg_a, msg_b)| msg_a.event_id() == msg_b.event_id()) } } @@ -100,7 +121,7 @@ impl MessageQueue { pub fn push(&mut self, msg: SyncMessageEvent) -> bool { // only push new messages into the queue if let Some(latest) = self.msgs.last() { - if msg.origin_server_ts < latest.origin_server_ts && self.msgs.len() >= 10 { + if msg.origin_server_ts() < latest.origin_server_ts() && self.msgs.len() >= 10 { return false; } } @@ -120,10 +141,12 @@ impl MessageQueue { true } + /// Iterate over the messages in the queue. pub fn iter(&self) -> impl Iterator { self.msgs.iter() } + /// Iterate over each message mutably. pub fn iter_mut(&mut self) -> impl Iterator { self.msgs.iter_mut() } @@ -204,7 +227,9 @@ mod test { let mut room = Room::new(&id, &user); let json: &serde_json::Value = &test_json::MESSAGE_TEXT; - let msg = serde_json::from_value::(json.clone()).unwrap(); + let msg = FullOrRedactedEvent::Full( + serde_json::from_value::(json.clone()).unwrap(), + ); let mut msgs = MessageQueue::new(); msgs.push(msg.clone()); @@ -249,7 +274,9 @@ mod test { let mut room = Room::new(&id, &user); let json: &serde_json::Value = &test_json::MESSAGE_TEXT; - let msg = serde_json::from_value::(json.clone()).unwrap(); + let msg = FullOrRedactedEvent::Full( + serde_json::from_value::(json.clone()).unwrap(), + ); let mut msgs = MessageQueue::new(); msgs.push(msg.clone()); diff --git a/matrix_sdk_base/src/models/mod.rs b/matrix_sdk_base/src/models/mod.rs index 211e5b5d..4cf49a20 100644 --- a/matrix_sdk_base/src/models/mod.rs +++ b/matrix_sdk_base/src/models/mod.rs @@ -4,5 +4,8 @@ mod message; mod room; mod room_member; +#[cfg(feature = "messages")] +#[cfg_attr(docsrs, doc(cfg(feature = "messages")))] +pub use message::{FullOrRedactedEvent, MessageQueue, MessageWrapper}; pub use room::{Room, RoomName}; pub use room_member::RoomMember; diff --git a/matrix_sdk_base/src/models/room.rs b/matrix_sdk_base/src/models/room.rs index ae1d9c88..3be5980d 100644 --- a/matrix_sdk_base/src/models/room.rs +++ b/matrix_sdk_base/src/models/room.rs @@ -20,22 +20,21 @@ use serde::{Deserialize, Serialize}; use tracing::{debug, error, trace}; #[cfg(feature = "messages")] -use super::message::{MessageQueue, MessageWrapper}; +use super::message::{FullOrRedactedEvent, MessageQueue}; use super::RoomMember; use crate::api::r0::sync::sync_events::{RoomSummary, UnreadNotificationsCount}; -use crate::events::presence::{PresenceEvent, PresenceEventContent}; -use crate::events::room::{ - aliases::AliasesEventContent, - canonical_alias::CanonicalAliasEventContent, - encryption::EncryptionEventContent, - member::{MemberEventContent, MembershipChange, MembershipState}, - name::NameEventContent, - power_levels::{NotificationPowerLevels, PowerLevelsEventContent}, - tombstone::TombstoneEventContent, -}; - use crate::events::{ + presence::PresenceEvent, + room::{ + aliases::AliasesEventContent, + canonical_alias::CanonicalAliasEventContent, + encryption::EncryptionEventContent, + member::{MemberEventContent, MembershipChange}, + name::NameEventContent, + power_levels::{NotificationPowerLevels, PowerLevelsEventContent}, + tombstone::TombstoneEventContent, + }, Algorithm, AnyRoomEventStub, AnyStateEventStub, AnyStrippedStateEventStub, EventType, StateEventStub, StrippedStateEventStub, }; @@ -43,7 +42,7 @@ use crate::events::{ #[cfg(feature = "messages")] use crate::events::{ room::redaction::{RedactionEvent, RedactionEventStub}, - AnyMessageEventContent, AnyMessageEventStub, EventJson, + AnyMessageEventStub, EventJson, }; use crate::identifiers::{RoomAliasId, RoomId, UserId}; @@ -674,8 +673,7 @@ impl Room { #[cfg(feature = "messages")] #[cfg_attr(docsrs, doc(cfg(feature = "messages")))] pub fn handle_message(&mut self, event: &AnyMessageEventStub) -> bool { - let message = MessageWrapper::clone_into_any_content(event); - self.messages.push(message) + self.messages.push(FullOrRedactedEvent::Full(event.clone())) } /// Handle a room.redaction event and update the `MessageQueue`. @@ -686,17 +684,72 @@ impl Room { /// field. #[cfg(feature = "messages")] #[cfg_attr(docsrs, doc(cfg(feature = "messages")))] - pub fn handle_redaction(&mut self, event: &RedactionEventStub) -> bool { + pub fn handle_redaction(&mut self, redacted_event: &RedactionEventStub) -> bool { + use matrix_sdk_common::events::{ + AnyRedactedMessageEventStub, MessageEventStub, RedactedMessageEventStub, + }; + use std::ops::DerefMut; + if let Some(msg) = self .messages .iter_mut() - .find(|msg| event.redacts == msg.event_id) + .find(|msg| &redacted_event.redacts == msg.event_id()) { - msg.content = AnyMessageEventContent::RoomRedaction(event.content.clone()); - - let redaction = - redaction_event_from_redaction_stub(event.clone(), self.room_id.clone()); - msg.unsigned.redacted_because = Some(EventJson::from(redaction)); + match msg.deref_mut() { + FullOrRedactedEvent::Full(event) => match event { + AnyMessageEventStub::RoomMessage(event) => { + let MessageEventStub { + content, + event_id, + sender, + origin_server_ts, + mut unsigned, + } = event.clone(); + unsigned.redacted_because = + Some(EventJson::from(redaction_event_from_redaction_stub( + redacted_event.clone(), + self.room_id.clone(), + ))); + let redacted = content.redact(); + msg.0 = FullOrRedactedEvent::Redacted( + AnyRedactedMessageEventStub::RoomMessage(RedactedMessageEventStub { + content: redacted, + event_id, + origin_server_ts, + sender, + unsigned, + }), + ) + } + AnyMessageEventStub::Sticker(event) => { + let MessageEventStub { + content, + event_id, + sender, + origin_server_ts, + mut unsigned, + } = event.clone(); + unsigned.redacted_because = + Some(EventJson::from(redaction_event_from_redaction_stub( + redacted_event.clone(), + self.room_id.clone(), + ))); + let redacted = content.redact(); + msg.0 = FullOrRedactedEvent::Redacted(AnyRedactedMessageEventStub::Sticker( + RedactedMessageEventStub { + content: redacted, + event_id, + origin_server_ts, + sender, + unsigned, + }, + )) + } + // TODO handle the rest of the message events + _ => {} + }, + FullOrRedactedEvent::Redacted(_) => return false, + } true } else { false @@ -815,6 +868,7 @@ impl Room { AnyMessageEventStub::RoomRedaction(event) => self.handle_redaction(event), _ => false, }, + AnyRoomEventStub::RedactedMessage(_) | AnyRoomEventStub::RedactedState(_) => false, } } @@ -1661,10 +1715,15 @@ mod test { for room in client.joined_rooms().read().await.values() { let queue = &room.read().await.messages; - if let crate::events::AnyMessageEventContent::RoomRedaction(content) = - &queue.msgs[0].content + if let crate::models::message::FullOrRedactedEvent::Redacted( + crate::events::AnyRedactedMessageEventStub::RoomMessage(event), + ) = &queue.msgs[0].deref() { - assert_eq!(content.reason, Some("😀".to_string())); + // this is the id from the message event in the sync response + assert_eq!( + event.event_id, + EventId::try_from("$152037280074GZeOm:localhost").unwrap() + ) } else { panic!("message event in message queue should be redacted") } diff --git a/matrix_sdk_common/Cargo.toml b/matrix_sdk_common/Cargo.toml index 9700f812..b1ae4696 100644 --- a/matrix_sdk_common/Cargo.toml +++ b/matrix_sdk_common/Cargo.toml @@ -17,7 +17,7 @@ js_int = "0.1.8" [dependencies.ruma] git = "https://github.com/ruma/ruma" features = ["client-api"] -rev = "c19bcaab" +rev = "5e428ac" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] uuid = { version = "0.8.1", features = ["v4"] }