Skip to content

Commit 965390c

Browse files
committed
notification client: use the membership state to match an invite
1 parent 119bee6 commit 965390c

File tree

1 file changed

+77
-13
lines changed

1 file changed

+77
-13
lines changed

crates/matrix-sdk-ui/src/notification_client.rs

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ use ruma::{
2929
assign,
3030
directory::RoomTypeFilter,
3131
events::{
32-
room::{member::StrippedRoomMemberEvent, message::SyncRoomMessageEvent},
32+
room::{
33+
member::{MembershipState, StrippedRoomMemberEvent},
34+
message::SyncRoomMessageEvent,
35+
},
3336
AnyFullStateEventContent, AnyStateEvent, AnySyncMessageLikeEvent, AnySyncTimelineEvent,
3437
FullStateEventContent, StateEventType, TimelineEventType,
3538
},
@@ -280,9 +283,21 @@ impl NotificationClient {
280283
/// Try to run a sliding sync (without encryption) to retrieve the event
281284
/// from the notification.
282285
///
283-
/// This works by requesting explicit state that'll be useful for building
284-
/// the `NotificationItem`, and subscribing to the room which the
285-
/// notification relates to.
286+
/// The event can either be:
287+
/// - an invite event,
288+
/// - or a non-invite event.
289+
///
290+
/// In case it's a non-invite event, it's rather easy: we'll request
291+
/// explicit state that'll be useful for building the
292+
/// `NotificationItem`, and subscribe to the room which the notification
293+
/// relates to.
294+
///
295+
/// In case it's an invite-event, it's trickier because the stripped event
296+
/// may not contain the event id, so we can't just match on it. Rather,
297+
/// we look at stripped room member events that may be fitting (i.e.
298+
/// match the current user and are invites), and if the SDK concludes the
299+
/// room was in the invited state, and we didn't find the event by id,
300+
/// *then* we'll use that stripped room member event.
286301
#[instrument(skip_all)]
287302
async fn try_sliding_sync(
288303
&self,
@@ -297,9 +312,9 @@ impl NotificationClient {
297312
// notification, so we can figure out the full event and associated
298313
// information.
299314

300-
let notification = Arc::new(Mutex::new(None));
315+
let raw_notification = Arc::new(Mutex::new(None));
301316

302-
let cloned_notif = notification.clone();
317+
let handler_raw_notification = raw_notification.clone();
303318
let target_event_id = event_id.to_owned();
304319

305320
let timeline_event_handler =
@@ -309,7 +324,7 @@ impl NotificationClient {
309324
if event_id == target_event_id {
310325
// found it! There shouldn't be a previous event before, but if there
311326
// is, that should be ok to just replace it.
312-
*cloned_notif.lock().unwrap() =
327+
*handler_raw_notification.lock().unwrap() =
313328
Some(RawNotificationEvent::Timeline(raw));
314329
}
315330
}
@@ -322,25 +337,57 @@ impl NotificationClient {
322337
}
323338
});
324339

325-
let cloned_notif = notification.clone();
340+
// We'll only use this event if the room is in the invited state.
341+
let raw_invite = Arc::new(Mutex::new(None));
342+
326343
let target_event_id = event_id.to_owned();
344+
let user_id = self.client.user_id().unwrap().to_owned();
345+
let handler_raw_invite = raw_invite.clone();
346+
let handler_raw_notification = raw_notification.clone();
327347
let stripped_member_handler =
328348
self.client.add_event_handler(move |raw: Raw<StrippedRoomMemberEvent>| async move {
349+
let deserialized = match raw.deserialize() {
350+
Ok(d) => d,
351+
Err(err) => {
352+
warn!("failed to deserialize raw stripped room member event: {err}");
353+
return;
354+
}
355+
};
356+
357+
trace!("received a stripped room member event");
358+
359+
// Try to match the event by event_id, as it's the most precise. In theory, we
360+
// shouldn't receive it, so that's a first attempt.
329361
match raw.get_field::<OwnedEventId>("event_id") {
330362
Ok(Some(event_id)) => {
331363
if event_id == target_event_id {
332364
// found it! There shouldn't be a previous event before, but if there
333365
// is, that should be ok to just replace it.
334-
*cloned_notif.lock().unwrap() = Some(RawNotificationEvent::Invite(raw));
366+
*handler_raw_notification.lock().unwrap() =
367+
Some(RawNotificationEvent::Invite(raw));
368+
return;
335369
}
336370
}
337371
Ok(None) => {
338-
warn!("a room member event had no id");
372+
debug!("a room member event had no id");
339373
}
340374
Err(err) => {
341-
warn!("a room member event id couldn't be decoded: {err}");
375+
debug!("a room member event id couldn't be decoded: {err}");
342376
}
343377
}
378+
379+
// Try to match the event by membership and state_key for the current user.
380+
if deserialized.content.membership == MembershipState::Invite
381+
&& deserialized.state_key == user_id
382+
{
383+
debug!("found an invite event for the current user");
384+
// This could be it! There might be several of these following each other, so
385+
// assume it's the latest one (in sync ordering), and override a previous one if
386+
// present.
387+
*handler_raw_invite.lock().unwrap() = Some(RawNotificationEvent::Invite(raw));
388+
} else {
389+
debug!("not an invite event, or not for the current user");
390+
}
344391
});
345392

346393
// Room power levels are necessary to build the push context.
@@ -394,7 +441,7 @@ impl NotificationClient {
394441
break;
395442
}
396443

397-
if notification.lock().unwrap().is_some() {
444+
if raw_notification.lock().unwrap().is_some() || raw_invite.lock().unwrap().is_some() {
398445
// We got the event.
399446
break;
400447
}
@@ -409,7 +456,24 @@ impl NotificationClient {
409456
self.client.remove_event_handler(stripped_member_handler);
410457
self.client.remove_event_handler(timeline_event_handler);
411458

412-
let maybe_event = notification.lock().unwrap().take();
459+
let mut maybe_event = raw_notification.lock().unwrap().take();
460+
461+
if maybe_event.is_none() {
462+
trace!("we didn't have a non-invite event, looking for invited room now");
463+
if let Some(room) = self.client.get_room(room_id) {
464+
if room.state() == RoomState::Invited {
465+
maybe_event = raw_invite.lock().unwrap().take();
466+
} else {
467+
debug!("the room isn't in the invited state");
468+
}
469+
} else {
470+
debug!("the room isn't an invite");
471+
}
472+
}
473+
474+
let found = if maybe_event.is_some() { "" } else { "not " };
475+
trace!("the notification event has been {found}found");
476+
413477
Ok(maybe_event)
414478
}
415479

0 commit comments

Comments
 (0)