@@ -378,6 +378,7 @@ impl RoomEventCacheInner {
378
378
ambiguity_changes : BTreeMap < OwnedEventId , AmbiguityChange > ,
379
379
) -> Result < ( ) > {
380
380
let mut prev_batch = timeline. prev_batch ;
381
+
381
382
if timeline. events . is_empty ( )
382
383
&& prev_batch. is_none ( )
383
384
&& ephemeral_events. is_empty ( )
@@ -410,6 +411,17 @@ impl RoomEventCacheInner {
410
411
all_duplicates,
411
412
) = state. collect_valid_and_duplicated_events ( timeline. events ) . await ?;
412
413
414
+ // If we only received duplicated events, we don't need to store the gap: if
415
+ // there was a gap, we'd have received an unknown event at the tail of
416
+ // the room's timeline (unless the server reordered sync events since the last
417
+ // time we sync'd).
418
+ if all_duplicates {
419
+ prev_batch = None ;
420
+ }
421
+
422
+ // Handle the thread updates separately.
423
+ let thread_updates = state. handle_live_threads ( & timeline. events , prev_batch. is_some ( ) ) ?;
424
+
413
425
// During a sync, when a duplicated event is found, the old event is removed and
414
426
// the new event is added.
415
427
//
@@ -431,27 +443,20 @@ impl RoomEventCacheInner {
431
443
// events themselves.
432
444
let new_timeline_event_diffs = state
433
445
. with_events_mut ( |room_events| {
434
- // If we only received duplicated events, we don't need to store the gap: if
435
- // there was a gap, we'd have received an unknown event at the tail of
436
- // the room's timeline (unless the server reordered sync events since the last
437
- // time we sync'd).
438
- if !all_duplicates {
439
- if let Some ( prev_token) = & prev_batch {
440
- // As a tiny optimization: remove the last chunk if it's an empty event
441
- // one, as it's not useful to keep it before a gap.
442
- let prev_chunk_to_remove =
443
- room_events. rchunks ( ) . next ( ) . and_then ( |chunk| {
444
- ( chunk. is_items ( ) && chunk. num_items ( ) == 0 )
445
- . then_some ( chunk. identifier ( ) )
446
- } ) ;
447
-
448
- room_events. push_gap ( Gap { prev_token : prev_token. clone ( ) } ) ;
449
-
450
- if let Some ( prev_chunk_to_remove) = prev_chunk_to_remove {
451
- room_events. remove_empty_chunk_at ( prev_chunk_to_remove) . expect (
452
- "we just checked the chunk is there, and it's an empty item chunk" ,
453
- ) ;
454
- }
446
+ if let Some ( prev_token) = & prev_batch {
447
+ // As a tiny optimization: remove the last chunk if it's an empty event
448
+ // one, as it's not useful to keep it before a gap.
449
+ let prev_chunk_to_remove = room_events. rchunks ( ) . next ( ) . and_then ( |chunk| {
450
+ ( chunk. is_items ( ) && chunk. num_items ( ) == 0 )
451
+ . then_some ( chunk. identifier ( ) )
452
+ } ) ;
453
+
454
+ room_events. push_gap ( Gap { prev_token : prev_token. clone ( ) } ) ;
455
+
456
+ if let Some ( prev_chunk_to_remove) = prev_chunk_to_remove {
457
+ room_events. remove_empty_chunk_at ( prev_chunk_to_remove) . expect (
458
+ "we just checked the chunk is there, and it's an empty item chunk" ,
459
+ ) ;
455
460
}
456
461
}
457
462
@@ -496,6 +501,12 @@ impl RoomEventCacheInner {
496
501
} ) ;
497
502
}
498
503
504
+ if !thread_updates. is_empty ( ) {
505
+ let _ = self . sender . send ( RoomEventCacheUpdate :: UpdateThreadSummaries {
506
+ summaries : thread_updates,
507
+ } ) ;
508
+ }
509
+
499
510
if !ephemeral_events. is_empty ( ) {
500
511
let _ = self
501
512
. sender
@@ -539,7 +550,7 @@ pub(super) enum LoadMoreEventsBackwardsOutcome {
539
550
// Use a private module to hide `events` to this parent module.
540
551
mod private {
541
552
use std:: {
542
- collections:: HashSet ,
553
+ collections:: { BTreeMap , HashSet } ,
543
554
sync:: { atomic:: AtomicUsize , Arc } ,
544
555
} ;
545
556
@@ -568,7 +579,9 @@ mod private {
568
579
EventCacheError ,
569
580
} ,
570
581
events:: RoomEvents ,
571
- sort_positions_descending, EventLocation , LoadMoreEventsBackwardsOutcome ,
582
+ sort_positions_descending,
583
+ threads:: { EventCacheThreadError , RoomThreads , ThreadSummary } ,
584
+ EventLocation , LoadMoreEventsBackwardsOutcome ,
572
585
} ;
573
586
use crate :: event_cache:: RoomPaginationStatus ;
574
587
@@ -589,6 +602,9 @@ mod private {
589
602
/// The events of the room.
590
603
events : RoomEvents ,
591
604
605
+ /// All the information about threads from this room.
606
+ threads : RoomThreads ,
607
+
592
608
/// The events deduplicator instance to help finding duplicates.
593
609
deduplicator : Deduplicator ,
594
610
@@ -647,10 +663,13 @@ mod private {
647
663
let events = RoomEvents :: with_initial_linked_chunk ( linked_chunk) ;
648
664
let deduplicator = Deduplicator :: new ( room_id. clone ( ) , store. clone ( ) ) ;
649
665
666
+ let threads = RoomThreads :: new ( ) ;
667
+
650
668
Ok ( Self {
651
669
room : room_id,
652
670
room_version,
653
671
store,
672
+ threads,
654
673
events,
655
674
deduplicator,
656
675
waited_for_initial_prev_token : false ,
@@ -1191,6 +1210,16 @@ mod private {
1191
1210
Ok ( updates_as_vector_diffs)
1192
1211
}
1193
1212
1213
+ /// Handle new events from a sync, for threads.
1214
+ #[ instrument( skip_all, fields( room_id = %self . room) ) ]
1215
+ pub fn handle_live_threads (
1216
+ & mut self ,
1217
+ events : & [ TimelineEvent ] ,
1218
+ is_gappy : bool ,
1219
+ ) -> Result < BTreeMap < OwnedEventId , ThreadSummary > , EventCacheThreadError > {
1220
+ self . threads . handle_live ( events, is_gappy)
1221
+ }
1222
+
1194
1223
/// If the given event is a redaction, try to retrieve the
1195
1224
/// to-be-redacted event in the chunk, and replace it by the
1196
1225
/// redacted form.
0 commit comments