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.
This commit is contained in:
parent
d273786d83
commit
2e8fc3e232
8 changed files with 170 additions and 62 deletions
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
],
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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"] }
|
||||
|
|
Loading…
Reference in a new issue