Skip to content

Commit 68ee9d6

Browse files
committed
read receipts: move the unread messages and mentions counts to separate fields of RoomInfo
1 parent d6733e2 commit 68ee9d6

File tree

4 files changed

+70
-35
lines changed

4 files changed

+70
-35
lines changed

bindings/matrix-sdk-ffi/src/room_info.rs

+4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub struct RoomInfo {
3131
user_defined_notification_mode: Option<RoomNotificationMode>,
3232
has_room_call: bool,
3333
active_room_call_participants: Vec<String>,
34+
num_unread_messages: u64,
35+
num_unread_mentions: u64,
3436
}
3537

3638
impl RoomInfo {
@@ -75,6 +77,8 @@ impl RoomInfo {
7577
.iter()
7678
.map(|u| u.to_string())
7779
.collect(),
80+
num_unread_messages: room.num_unread_messages(),
81+
num_unread_mentions: room.num_unread_mentions(),
7882
})
7983
}
8084
}

crates/matrix-sdk-base/src/read_receipts.rs

+24-27
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,21 @@ use ruma::{
1010
serde::Raw,
1111
EventId, OwnedEventId, UserId,
1212
};
13-
use tracing::{field::display, instrument, trace};
13+
use tracing::{instrument, trace};
1414

1515
use super::BaseClient;
1616
use crate::{error::Result, store::StateChanges, PreviousEventsProvider, RoomInfo};
1717

18-
#[instrument(skip_all, fields(room_id))]
18+
#[instrument(skip_all, fields(room_id = %room_info.room_id))]
1919
pub(crate) async fn compute_notifications(
2020
client: &BaseClient,
2121
changes: &StateChanges,
2222
previous_events_provider: &dyn PreviousEventsProvider,
2323
new_events: &[SyncTimelineEvent],
2424
room_info: &mut RoomInfo,
2525
) -> Result<()> {
26-
// Only apply the algorithm to encrypted rooms, since unencrypted rooms' unread
27-
// notification counts ought to be properly computed by the server.
28-
if !room_info.is_encrypted() {
29-
return Ok(());
30-
}
31-
32-
tracing::Span::current().record("room_id", display(&room_info.room_id));
33-
3426
let user_id = &client.session_meta().unwrap().user_id;
35-
let prev_latest_receipt_event_id = room_info.latest_read_receipt_event_id.clone();
27+
let prev_latest_receipt_event_id = room_info.read_receipts.latest_read_receipt_event_id.clone();
3628

3729
if let Some(receipt_event) = changes.receipts.get(room_info.room_id()) {
3830
trace!("Got a new receipt event!");
@@ -62,7 +54,7 @@ pub(crate) async fn compute_notifications(
6254
// about.
6355

6456
// First, save the event id as the latest one that has a read receipt.
65-
room_info.latest_read_receipt_event_id = Some(receipt_event_id.clone());
57+
room_info.read_receipts.latest_read_receipt_event_id = Some(receipt_event_id.clone());
6658

6759
// Try to find if the read receipts refers to an event from the current sync, to
6860
// avoid searching the cached timeline events.
@@ -110,17 +102,28 @@ pub(crate) async fn compute_notifications(
110102
// for the next receipt.
111103
trace!("All other ways failed, including all new events for the receipts count.");
112104
for event in new_events {
113-
if event.push_actions.iter().any(ruma::push::Action::is_highlight) {
114-
room_info.notification_counts.highlight_count += 1;
115-
}
116-
if marks_as_unread(&event.event, user_id) {
117-
room_info.notification_counts.notification_count += 1;
118-
}
105+
count_unread_and_mentions(event, user_id, room_info);
119106
}
120107

121108
Ok(())
122109
}
123110

111+
#[inline(always)]
112+
fn count_unread_and_mentions(
113+
event: &SyncTimelineEvent,
114+
user_id: &UserId,
115+
room_info: &mut RoomInfo,
116+
) {
117+
for action in &event.push_actions {
118+
if action.should_notify() && marks_as_unread(&event.event, user_id) {
119+
room_info.read_receipts.num_unread += 1;
120+
}
121+
if action.is_highlight() {
122+
room_info.read_receipts.num_mentions += 1;
123+
}
124+
}
125+
}
126+
124127
/// Try to find the event to which the receipt attaches to, and if found, will
125128
/// update the notification count in the room.
126129
///
@@ -134,20 +137,14 @@ fn find_and_count_events<'a>(
134137
let mut counting_receipts = false;
135138
for event in events {
136139
if counting_receipts {
137-
for action in &event.push_actions {
138-
if action.is_highlight() {
139-
room_info.notification_counts.highlight_count += 1;
140-
}
141-
if action.should_notify() && marks_as_unread(&event.event, user_id) {
142-
room_info.notification_counts.notification_count += 1;
143-
}
144-
}
140+
count_unread_and_mentions(event, user_id, room_info);
145141
} else if let Ok(Some(event_id)) = event.event.get_field::<OwnedEventId>("event_id") {
146142
if event_id == receipt_event_id {
147143
// Bingo! Switch over to the counting state, after resetting the
148144
// previous counts.
149145
trace!("Found the event the receipt was referring to! Starting to count.");
150-
room_info.notification_counts = Default::default();
146+
room_info.read_receipts.num_unread = 0;
147+
room_info.read_receipts.num_mentions = 0;
151148
counting_receipts = true;
152149
}
153150
}

crates/matrix-sdk-base/src/rooms/normal.rs

+41-7
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,23 @@ impl Room {
187187
self.inner.read().notification_counts
188188
}
189189

190+
/// Get the number of unread messages (computed client-side).
191+
///
192+
/// This might be more precise than [`Self::unread_notification_counts`] for
193+
/// encrypted rooms.
194+
pub fn num_unread_messages(&self) -> u64 {
195+
self.inner.read().read_receipts.num_unread
196+
}
197+
198+
/// Get the number of unread mentions (computed client-side), that is,
199+
/// messages causing a highlight in a room.
200+
///
201+
/// This might be more precise than [`Self::unread_notification_counts`] for
202+
/// encrypted rooms.
203+
pub fn num_unread_mentions(&self) -> u64 {
204+
self.inner.read().read_receipts.num_mentions
205+
}
206+
190207
/// Check if the room has its members fully synced.
191208
///
192209
/// Members might be missing if lazy member loading was enabled for the
@@ -710,6 +727,22 @@ impl Room {
710727
}
711728
}
712729

730+
/// Information abount read receipts collected during processing of that room.
731+
#[derive(Clone, Debug, Serialize, Deserialize, Default)]
732+
pub struct RoomReadReceipts {
733+
/// Does the room have unread messages?
734+
pub(crate) num_unread: u64,
735+
736+
/// Does the room have messages causing highlights for the users? (aka
737+
/// mentions)
738+
pub(crate) num_mentions: u64,
739+
740+
/// The id of the event the last unthreaded (or main-threaded, for better
741+
/// compatibility with clients that have thread support) read receipt is
742+
/// attached to.
743+
pub(crate) latest_read_receipt_event_id: Option<OwnedEventId>,
744+
}
745+
713746
/// The underlying pure data structure for joined and left rooms.
714747
///
715748
/// Holds all the info needed to persist a room into the state store.
@@ -721,7 +754,10 @@ pub struct RoomInfo {
721754
/// The state of the room.
722755
pub(crate) room_state: RoomState,
723756

724-
/// The unread notifications counts.
757+
/// The unread notifications counts, as returned by the server.
758+
///
759+
/// These might be incorrect for encrypted rooms, since the server doesn't
760+
/// have access to the content of the encrypted events.
725761
pub(crate) notification_counts: UnreadNotificationsCount,
726762

727763
/// The summary of this room.
@@ -743,11 +779,9 @@ pub struct RoomInfo {
743779
#[cfg(feature = "experimental-sliding-sync")]
744780
pub(crate) latest_event: Option<Box<LatestEvent>>,
745781

746-
/// The id of the event the last unthreaded (or main-threaded, for better
747-
/// compatibility with clients that have thread support) read receipt is
748-
/// attached to.
782+
/// Information about read receipts for this room.
749783
#[serde(default)]
750-
pub(crate) latest_read_receipt_event_id: Option<OwnedEventId>,
784+
pub(crate) read_receipts: RoomReadReceipts,
751785

752786
/// Base room info which holds some basic event contents important for the
753787
/// room state.
@@ -785,7 +819,7 @@ impl RoomInfo {
785819
encryption_state_synced: false,
786820
#[cfg(feature = "experimental-sliding-sync")]
787821
latest_event: None,
788-
latest_read_receipt_event_id: None,
822+
read_receipts: Default::default(),
789823
base_info: Box::new(BaseRoomInfo::new()),
790824
}
791825
}
@@ -1267,7 +1301,7 @@ mod tests {
12671301
Raw::from_json_string(json!({"sender": "@u:i.uk"}).to_string()).unwrap().into(),
12681302
))),
12691303
base_info: Box::new(BaseRoomInfo::new()),
1270-
latest_read_receipt_event_id: None,
1304+
read_receipts: Default::default(),
12711305
};
12721306

12731307
let info_json = json!({

crates/matrix-sdk-base/src/store/migration_helpers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ impl RoomInfoV1 {
118118
encryption_state_synced,
119119
#[cfg(feature = "experimental-sliding-sync")]
120120
latest_event: latest_event.map(|ev| Box::new(LatestEvent::new(ev))),
121-
latest_read_receipt_event_id: None,
121+
read_receipts: Default::default(),
122122
base_info: base_info.migrate(create),
123123
}
124124
}

0 commit comments

Comments
 (0)