sdk_base: message events in message queue have content redacted
The MessageQueue holds MessageEventStub<AnyMessageEventContent> so when a redaction event is encountered the redacted event's content can be replaced. The Unsigned field redacted_because is also populated with the redaction event itself with the addition of a room_id Stub -> full event.master
parent
dcc3d6e755
commit
e7c70854ab
|
@ -7,28 +7,42 @@ use std::cmp::Ordering;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
use std::vec::IntoIter;
|
||||
|
||||
use crate::events::AnyMessageEventStub;
|
||||
use crate::events::{AnyMessageEventContent, AnyMessageEventStub, MessageEventStub};
|
||||
|
||||
use serde::{de, ser, Serialize};
|
||||
|
||||
const MESSAGE_QUEUE_CAP: usize = 35;
|
||||
|
||||
pub type SyncMessageEvent = MessageEventStub<AnyMessageEventContent>;
|
||||
|
||||
/// A queue that holds the 35 most recent messages received from the server.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MessageQueue {
|
||||
msgs: Vec<MessageWrapper>,
|
||||
pub(crate) msgs: Vec<MessageWrapper>,
|
||||
}
|
||||
|
||||
/// A wrapper for `ruma_events::AnyMessageEventStub` that allows implementation of
|
||||
/// A wrapper for `ruma_events::SyncMessageEvent` that allows implementation of
|
||||
/// Eq, Ord and the Partial versions of the traits.
|
||||
///
|
||||
/// `MessageWrapper` also implements Deref and DerefMut so accessing the events contents
|
||||
/// are simplified.
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct MessageWrapper(pub AnyMessageEventStub);
|
||||
pub struct MessageWrapper(pub SyncMessageEvent);
|
||||
|
||||
impl MessageWrapper {
|
||||
pub fn clone_into_any_content(event: &AnyMessageEventStub) -> SyncMessageEvent {
|
||||
MessageEventStub {
|
||||
content: event.content().clone(),
|
||||
sender: event.sender().clone(),
|
||||
origin_server_ts: event.origin_server_ts().clone(),
|
||||
event_id: event.event_id().clone(),
|
||||
unsigned: event.unsigned().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for MessageWrapper {
|
||||
type Target = AnyMessageEventStub;
|
||||
type Target = SyncMessageEvent;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
|
@ -43,7 +57,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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +65,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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +82,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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,10 +97,10 @@ impl MessageQueue {
|
|||
/// Inserts a `MessageEvent` into `MessageQueue`, sorted by by `origin_server_ts`.
|
||||
///
|
||||
/// Removes the oldest element in the queue if there are more than 10 elements.
|
||||
pub fn push(&mut self, msg: AnyMessageEventStub) -> bool {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +145,7 @@ pub(crate) mod ser_deser {
|
|||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
let messages: Vec<AnyMessageEventStub> = de::Deserialize::deserialize(deserializer)?;
|
||||
let messages: Vec<SyncMessageEvent> = de::Deserialize::deserialize(deserializer)?;
|
||||
|
||||
let mut msgs = vec![];
|
||||
for msg in messages {
|
||||
|
@ -172,7 +186,7 @@ mod test {
|
|||
let mut room = Room::new(&id, &user);
|
||||
|
||||
let json: &serde_json::Value = &test_json::MESSAGE_TEXT;
|
||||
let msg = serde_json::from_value::<AnyMessageEventStub>(json.clone()).unwrap();
|
||||
let msg = serde_json::from_value::<SyncMessageEvent>(json.clone()).unwrap();
|
||||
|
||||
let mut msgs = MessageQueue::new();
|
||||
msgs.push(msg.clone());
|
||||
|
@ -218,7 +232,7 @@ mod test {
|
|||
let mut room = Room::new(&id, &user);
|
||||
|
||||
let json: &serde_json::Value = &test_json::MESSAGE_TEXT;
|
||||
let msg = serde_json::from_value::<AnyMessageEventStub>(json.clone()).unwrap();
|
||||
let msg = serde_json::from_value::<SyncMessageEvent>(json.clone()).unwrap();
|
||||
|
||||
let mut msgs = MessageQueue::new();
|
||||
msgs.push(msg.clone());
|
||||
|
|
|
@ -34,18 +34,34 @@ use crate::events::room::{
|
|||
};
|
||||
|
||||
use crate::events::{
|
||||
Algorithm, AnyRoomEventStub, AnyStateEventStub, AnyStrippedStateEventStub, EventType,
|
||||
StateEventStub, StrippedStateEventStub,
|
||||
Algorithm, AnyMessageEventContent, AnyRoomEventStub, AnyStateEventStub,
|
||||
AnyStrippedStateEventStub, EventJson, EventType, StateEventStub, StrippedStateEventStub,
|
||||
};
|
||||
|
||||
#[cfg(feature = "messages")]
|
||||
use crate::events::{room::redaction::RedactionEventStub, AnyMessageEventStub};
|
||||
use crate::events::{
|
||||
room::redaction::{RedactionEvent, RedactionEventStub},
|
||||
AnyMessageEventStub,
|
||||
};
|
||||
|
||||
use crate::identifiers::{RoomAliasId, RoomId, UserId};
|
||||
|
||||
use crate::js_int::{Int, UInt};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "messages")]
|
||||
fn full_event_from_stub(event: RedactionEventStub, room_id: RoomId) -> RedactionEvent {
|
||||
RedactionEvent {
|
||||
content: event.content,
|
||||
redacts: event.redacts,
|
||||
event_id: event.event_id,
|
||||
unsigned: event.unsigned,
|
||||
sender: event.sender,
|
||||
origin_server_ts: event.origin_server_ts,
|
||||
room_id,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
/// `RoomName` allows the calculation of a text room name.
|
||||
pub struct RoomName {
|
||||
|
@ -618,7 +634,8 @@ impl Room {
|
|||
#[cfg(feature = "messages")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "messages")))]
|
||||
pub fn handle_message(&mut self, event: &AnyMessageEventStub) -> bool {
|
||||
self.messages.push(event.clone())
|
||||
let message = MessageWrapper::clone_into_any_content(event);
|
||||
self.messages.push(message)
|
||||
}
|
||||
|
||||
/// Handle a room.redaction event and update the `MessageQueue` if necessary.
|
||||
|
@ -630,9 +647,12 @@ impl Room {
|
|||
if let Some(msg) = self
|
||||
.messages
|
||||
.iter_mut()
|
||||
.find(|msg| &event.redacts == msg.event_id())
|
||||
.find(|msg| event.redacts == msg.event_id)
|
||||
{
|
||||
*msg = MessageWrapper(AnyMessageEventStub::RoomRedaction(event.clone()));
|
||||
msg.content = AnyMessageEventContent::RoomRedaction(event.content.clone());
|
||||
|
||||
let redaction = full_event_from_stub(event.clone(), self.room_id.clone());
|
||||
msg.unsigned.redacted_because = Some(EventJson::from(redaction));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -1152,6 +1172,51 @@ mod test {
|
|||
assert_eq!(vec!["example2"], room_names);
|
||||
}
|
||||
|
||||
#[cfg(feature = "messages")]
|
||||
#[async_test]
|
||||
async fn message_queue_redaction_event() {
|
||||
let room_id = get_room_id();
|
||||
|
||||
let mut response = sync_response(SyncResponseFile::DefaultWithSummary);
|
||||
|
||||
let session = Session {
|
||||
access_token: "1234".to_owned(),
|
||||
user_id: UserId::try_from("@example:localhost").unwrap(),
|
||||
device_id: "DEVICEID".to_owned(),
|
||||
};
|
||||
let client = BaseClient::new().unwrap();
|
||||
client.restore_login(session).await.unwrap();
|
||||
client.receive_sync_response(&mut response).await.unwrap();
|
||||
|
||||
let json = serde_json::json!({
|
||||
"content": {
|
||||
"reason": "😀"
|
||||
},
|
||||
"event_id": "$151957878228ssqrJ:localhost",
|
||||
"origin_server_ts": 151957878,
|
||||
"sender": "@example:localhost",
|
||||
"type": "m.room.redaction",
|
||||
"redacts": "$152037280074GZeOm:localhost"
|
||||
});
|
||||
let mut event: EventJson<AnyRoomEventStub> = serde_json::from_value(json).unwrap();
|
||||
client
|
||||
.receive_joined_timeline_event(&room_id, &mut event)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
for room in client.joined_rooms().read().await.values() {
|
||||
let queue = &room.read().await.messages;
|
||||
println!("{:?}", queue);
|
||||
if let crate::events::AnyMessageEventContent::RoomRedaction(content) =
|
||||
&queue.msgs[0].content
|
||||
{
|
||||
assert_eq!(content.reason, Some("😀".to_string()));
|
||||
} else {
|
||||
panic!("message event in message queue should be redacted")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
async fn encryption_info_test() {
|
||||
|
|
|
@ -9,7 +9,8 @@ pub mod sync;
|
|||
|
||||
pub use events::{
|
||||
ALIAS, ALIASES, EVENT_ID, KEYS_QUERY, KEYS_UPLOAD, LOGIN, LOGIN_RESPONSE_ERR, LOGOUT, MEMBER,
|
||||
MESSAGE_EDIT, MESSAGE_TEXT, NAME, POWER_LEVELS, PRESENCE, PUBLIC_ROOMS, REACTION,
|
||||
REGISTRATION_RESPONSE_ERR, ROOM_ID, ROOM_MESSAGES, TYPING,
|
||||
MESSAGE_EDIT, MESSAGE_TEXT, NAME, POWER_LEVELS, PRESENCE, PUBLIC_ROOMS, REACTION, REDACTED,
|
||||
REDACTED_INVALID, REDACTED_STATE, REDACTION, REGISTRATION_RESPONSE_ERR, ROOM_ID, ROOM_MESSAGES,
|
||||
TYPING,
|
||||
};
|
||||
pub use sync::{DEFAULT_SYNC_SUMMARY, INVITE_SYNC, LEAVE_SYNC, LEAVE_SYNC_EVENT, MORE_SYNC, SYNC};
|
||||
|
|
Loading…
Reference in New Issue