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.
master
Devin R 2020-07-11 21:12:40 -04:00
parent d273786d83
commit 2e8fc3e232
8 changed files with 170 additions and 62 deletions

View File

@ -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;

View File

@ -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")
}

View File

@ -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"
],

View File

@ -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;

View File

@ -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<AnyMessageEventContent>;
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<Ordering> {
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<Item = &MessageWrapper> {
self.msgs.iter()
}
/// Iterate over each message mutably.
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut MessageWrapper> {
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::<SyncMessageEvent>(json.clone()).unwrap();
let msg = FullOrRedactedEvent::Full(
serde_json::from_value::<AnyMessageEventStub>(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::<SyncMessageEvent>(json.clone()).unwrap();
let msg = FullOrRedactedEvent::Full(
serde_json::from_value::<AnyMessageEventStub>(json.clone()).unwrap(),
);
let mut msgs = MessageQueue::new();
msgs.push(msg.clone());

View File

@ -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;

View File

@ -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::{
use crate::events::{
presence::PresenceEvent,
room::{
aliases::AliasesEventContent,
canonical_alias::CanonicalAliasEventContent,
encryption::EncryptionEventContent,
member::{MemberEventContent, MembershipChange, MembershipState},
member::{MemberEventContent, MembershipChange},
name::NameEventContent,
power_levels::{NotificationPowerLevels, PowerLevelsEventContent},
tombstone::TombstoneEventContent,
};
use crate::events::{
},
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")
}

View File

@ -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"] }