feat(base): Store the timestamp from SS in RoomInfo::recency_timestamp.

This patch adds a new field in `RoomInfo`: `recency_timestamp:
Option<MilliSecondsSinceUnixEpoch>>`. Its value comes from a Sliding
Sync Room response, that's why all this API is behind `cfg(feature =
"experimental-sliding-sync")`.
This commit is contained in:
Ivan Enderlin
2024-07-03 10:41:26 +02:00
parent 765b95468a
commit 9a02d6877f
3 changed files with 114 additions and 3 deletions

View File

@@ -24,8 +24,6 @@ use bitflags::bitflags;
use eyeball::{SharedObservable, Subscriber};
#[cfg(all(feature = "e2e-encryption", feature = "experimental-sliding-sync"))]
use matrix_sdk_common::ring_buffer::RingBuffer;
#[cfg(feature = "experimental-sliding-sync")]
use ruma::events::AnySyncTimelineEvent;
use ruma::{
api::client::sync::sync_events::v3::RoomSummary as RumaSummary,
events::{
@@ -51,6 +49,8 @@ use ruma::{
EventId, MxcUri, OwnedEventId, OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedUserId,
RoomAliasId, RoomId, RoomVersionId, UserId,
};
#[cfg(feature = "experimental-sliding-sync")]
use ruma::{events::AnySyncTimelineEvent, MilliSecondsSinceUnixEpoch};
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast;
use tracing::{debug, field::debug, info, instrument, warn};
@@ -888,6 +888,14 @@ impl Room {
pub fn is_marked_unread(&self) -> bool {
self.inner.read().base_info.is_marked_unread
}
/// Returns the recency timestamp of the room.
///
/// Please read `RoomInfo::recency_timestamp` to learn more.
#[cfg(feature = "experimental-sliding-sync")]
pub fn recency_timestamp(&self) -> Option<MilliSecondsSinceUnixEpoch> {
self.inner.read().recency_timestamp
}
}
/// The underlying pure data structure for joined and left rooms.
@@ -946,6 +954,16 @@ pub struct RoomInfo {
/// filled at start when creating a room, or on every successful sync.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) cached_display_name: Option<DisplayName>,
/// The recency timestamp of this room.
///
/// It's not to be confused with `origin_server_ts` of the latest event.
/// Sliding Sync might "ignore” some events when computing the recency
/// timestamp of the room. Thus, using this `recency_timestamp` value is
/// more accurate than relying on the latest event.
#[cfg(feature = "experimental-sliding-sync")]
#[serde(default)]
pub(crate) recency_timestamp: Option<MilliSecondsSinceUnixEpoch>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
@@ -983,6 +1001,8 @@ impl RoomInfo {
base_info: Box::new(BaseRoomInfo::new()),
warned_about_unknown_room_version: Arc::new(false.into()),
cached_display_name: None,
#[cfg(feature = "experimental-sliding-sync")]
recency_timestamp: None,
}
}
@@ -1387,6 +1407,14 @@ impl RoomInfo {
pub fn latest_event(&self) -> Option<&LatestEvent> {
self.latest_event.as_deref()
}
/// Updates the recency timestamp of this room.
///
/// Please read [`Self::recency_timestamp`] to learn more.
#[cfg(feature = "experimental-sliding-sync")]
pub(crate) fn update_recency_timestamp(&mut self, timestamp: MilliSecondsSinceUnixEpoch) {
self.recency_timestamp = Some(timestamp);
}
}
#[cfg(feature = "experimental-sliding-sync")]
@@ -1601,6 +1629,7 @@ mod tests {
read_receipts: Default::default(),
warned_about_unknown_room_version: Arc::new(false.into()),
cached_display_name: None,
recency_timestamp: Some(MilliSecondsSinceUnixEpoch(42u32.into())),
};
let info_json = json!({
@@ -1653,6 +1682,7 @@ mod tests {
"latest_active": null,
"pending": []
},
"recency_timestamp": 42,
});
assert_eq!(serde_json::to_value(info).unwrap(), info_json);

View File

@@ -733,6 +733,10 @@ fn process_room_properties(room_data: &v4::SlidingSyncRoom, room_info: &mut Room
if room_data.limited {
room_info.mark_members_missing();
}
if let Some(recency_timestamp) = &room_data.timestamp {
room_info.update_recency_timestamp(*recency_timestamp);
}
}
#[cfg(test)]
@@ -762,7 +766,8 @@ mod tests {
},
mxc_uri, owned_mxc_uri, owned_user_id, room_alias_id, room_id,
serde::Raw,
uint, user_id, JsOption, MxcUri, OwnedRoomId, OwnedUserId, RoomAliasId, RoomId, UserId,
uint, user_id, JsOption, MilliSecondsSinceUnixEpoch, MxcUri, OwnedRoomId, OwnedUserId,
RoomAliasId, RoomId, UserId,
};
use serde_json::json;
@@ -1736,6 +1741,80 @@ mod tests {
assert_eq!(rawev_id(room.latest_event().unwrap().event().clone()), "$a");
}
#[async_test]
async fn test_recency_timestamp_is_found_when_processing_sliding_sync_response() {
// Given a logged-in client
let client = logged_in_base_client(None).await;
let room_id = room_id!("!r:e.uk");
// When I send sliding sync response containing a room with a recency timestamp
let room = assign!(v4::SlidingSyncRoom::new(), {
timestamp: Some(MilliSecondsSinceUnixEpoch(42u32.into())),
});
let response = response_with_room(room_id, room);
client.process_sliding_sync(&response, &()).await.expect("Failed to process sync");
// Then the room in the client has the recency timestamp
let client_room = client.get_room(room_id).expect("No room found");
assert_eq!(client_room.recency_timestamp().expect("No recency timestamp").0, 42u32.into());
}
#[async_test]
async fn test_recency_timestamp_can_be_overwritten_when_present_in_a_sliding_sync_response() {
// Given a logged-in client
let client = logged_in_base_client(None).await;
let room_id = room_id!("!r:e.uk");
{
// When I send sliding sync response containing a room with a recency timestamp
let room = assign!(v4::SlidingSyncRoom::new(), {
timestamp: Some(MilliSecondsSinceUnixEpoch(42u32.into())),
});
let response = response_with_room(room_id, room);
client.process_sliding_sync(&response, &()).await.expect("Failed to process sync");
// Then the room in the client has the recency timestamp
let client_room = client.get_room(room_id).expect("No room found");
assert_eq!(
client_room.recency_timestamp().expect("No recency timestamp").0,
42u32.into()
);
}
{
// When I send sliding sync response containing a room with NO recency timestamp
let room = assign!(v4::SlidingSyncRoom::new(), {
timestamp: None,
});
let response = response_with_room(room_id, room);
client.process_sliding_sync(&response, &()).await.expect("Failed to process sync");
// Then the room in the client has the previous recency timestamp
let client_room = client.get_room(room_id).expect("No room found");
assert_eq!(
client_room.recency_timestamp().expect("No recency timestamp").0,
42u32.into()
);
}
{
// When I send sliding sync response containing a room with a NEW recency
// timestamp
let room = assign!(v4::SlidingSyncRoom::new(), {
timestamp: Some(MilliSecondsSinceUnixEpoch(153u32.into())),
});
let response = response_with_room(room_id, room);
client.process_sliding_sync(&response, &()).await.expect("Failed to process sync");
// Then the room in the client has the recency timestamp
let client_room = client.get_room(room_id).expect("No room found");
assert_eq!(
client_room.recency_timestamp().expect("No recency timestamp").0,
153u32.into()
);
}
}
async fn choose_event_to_cache(events: &[SyncTimelineEvent]) -> Option<SyncTimelineEvent> {
let room = make_room();
let mut room_info = room.clone_info();

View File

@@ -125,6 +125,8 @@ impl RoomInfoV1 {
base_info: base_info.migrate(create),
warned_about_unknown_room_version: Arc::new(false.into()),
cached_display_name: None,
#[cfg(feature = "experimental-sliding-sync")]
recency_timestamp: None,
}
}
}