@@ -29,7 +29,10 @@ use ruma::{
29
29
assign,
30
30
directory:: RoomTypeFilter ,
31
31
events:: {
32
- room:: { member:: StrippedRoomMemberEvent , message:: SyncRoomMessageEvent } ,
32
+ room:: {
33
+ member:: { MembershipState , StrippedRoomMemberEvent } ,
34
+ message:: SyncRoomMessageEvent ,
35
+ } ,
33
36
AnyFullStateEventContent , AnyStateEvent , AnySyncMessageLikeEvent , AnySyncTimelineEvent ,
34
37
FullStateEventContent , StateEventType , TimelineEventType ,
35
38
} ,
@@ -280,9 +283,21 @@ impl NotificationClient {
280
283
/// Try to run a sliding sync (without encryption) to retrieve the event
281
284
/// from the notification.
282
285
///
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.
286
301
#[ instrument( skip_all) ]
287
302
async fn try_sliding_sync (
288
303
& self ,
@@ -297,9 +312,9 @@ impl NotificationClient {
297
312
// notification, so we can figure out the full event and associated
298
313
// information.
299
314
300
- let notification = Arc :: new ( Mutex :: new ( None ) ) ;
315
+ let raw_notification = Arc :: new ( Mutex :: new ( None ) ) ;
301
316
302
- let cloned_notif = notification . clone ( ) ;
317
+ let handler_raw_notification = raw_notification . clone ( ) ;
303
318
let target_event_id = event_id. to_owned ( ) ;
304
319
305
320
let timeline_event_handler =
@@ -309,7 +324,7 @@ impl NotificationClient {
309
324
if event_id == target_event_id {
310
325
// found it! There shouldn't be a previous event before, but if there
311
326
// is, that should be ok to just replace it.
312
- * cloned_notif . lock ( ) . unwrap ( ) =
327
+ * handler_raw_notification . lock ( ) . unwrap ( ) =
313
328
Some ( RawNotificationEvent :: Timeline ( raw) ) ;
314
329
}
315
330
}
@@ -322,25 +337,57 @@ impl NotificationClient {
322
337
}
323
338
} ) ;
324
339
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
+
326
343
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 ( ) ;
327
347
let stripped_member_handler =
328
348
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.
329
361
match raw. get_field :: < OwnedEventId > ( "event_id" ) {
330
362
Ok ( Some ( event_id) ) => {
331
363
if event_id == target_event_id {
332
364
// found it! There shouldn't be a previous event before, but if there
333
365
// 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 ;
335
369
}
336
370
}
337
371
Ok ( None ) => {
338
- warn ! ( "a room member event had no id" ) ;
372
+ debug ! ( "a room member event had no id" ) ;
339
373
}
340
374
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}" ) ;
342
376
}
343
377
}
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
+ }
344
391
} ) ;
345
392
346
393
// Room power levels are necessary to build the push context.
@@ -394,7 +441,7 @@ impl NotificationClient {
394
441
break ;
395
442
}
396
443
397
- if notification . lock ( ) . unwrap ( ) . is_some ( ) {
444
+ if raw_notification . lock ( ) . unwrap ( ) . is_some ( ) || raw_invite . lock ( ) . unwrap ( ) . is_some ( ) {
398
445
// We got the event.
399
446
break ;
400
447
}
@@ -409,7 +456,24 @@ impl NotificationClient {
409
456
self . client . remove_event_handler ( stripped_member_handler) ;
410
457
self . client . remove_event_handler ( timeline_event_handler) ;
411
458
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
+
413
477
Ok ( maybe_event)
414
478
}
415
479
0 commit comments