@@ -51,14 +51,19 @@ use super::{
51
51
} ;
52
52
use crate :: {
53
53
client:: WeakClient ,
54
- event_cache:: EventCacheError ,
54
+ event_cache:: {
55
+ room:: threads:: {
56
+ push_context_for_threads_subscriptions, subscribe_to_new_threads, ThreadPushContext ,
57
+ } ,
58
+ EventCacheError ,
59
+ } ,
55
60
room:: { IncludeRelations , RelationsOptions , WeakRoom } ,
56
61
} ;
57
62
58
63
pub ( super ) mod events;
59
- mod threads;
64
+ pub ( super ) mod threads;
60
65
61
- pub use threads:: ThreadEventCacheUpdate ;
66
+ pub use threads:: { should_subscribe_thread , ThreadEventCacheUpdate } ;
62
67
63
68
/// A subset of an event cache, for a room.
64
69
///
@@ -276,14 +281,22 @@ impl RoomEventCache {
276
281
result. chunk . push ( root_event) ;
277
282
}
278
283
284
+ let push_context = push_context_for_threads_subscriptions ( & room) . await ;
285
+
279
286
let mut state = self . inner . state . write ( ) . await ;
280
287
281
- if let Some ( outcome) = state. finish_thread_network_pagination (
282
- thread_root. clone ( ) ,
283
- prev_token,
284
- result. next_batch_token ,
285
- result. chunk ,
286
- ) {
288
+ if let Some ( ( outcome, thread_subscriptions) ) = state
289
+ . finish_thread_network_pagination (
290
+ push_context,
291
+ thread_root. clone ( ) ,
292
+ prev_token,
293
+ result. next_batch_token ,
294
+ result. chunk ,
295
+ )
296
+ . await
297
+ {
298
+ subscribe_to_new_threads ( & room, thread_subscriptions) . await ;
299
+
287
300
return Ok ( outcome. reached_start ) ;
288
301
}
289
302
@@ -539,11 +552,22 @@ impl RoomEventCacheInner {
539
552
return Ok ( ( ) ) ;
540
553
}
541
554
555
+ let room = self . weak_room . get ( ) ;
556
+ let push_context = if let Some ( room) = & room {
557
+ push_context_for_threads_subscriptions ( & room) . await
558
+ } else {
559
+ ThreadPushContext :: default ( )
560
+ } ;
561
+
542
562
// Add all the events to the backend.
543
563
trace ! ( "adding new events" ) ;
544
564
545
- let ( stored_prev_batch_token, timeline_event_diffs) =
546
- self . state . write ( ) . await . handle_sync ( timeline) . await ?;
565
+ let ( stored_prev_batch_token, timeline_event_diffs, new_thread_subs) =
566
+ self . state . write ( ) . await . handle_sync ( push_context, timeline) . await ?;
567
+
568
+ if let Some ( room) = room {
569
+ subscribe_to_new_threads ( & room, new_thread_subs) . await ;
570
+ }
547
571
548
572
// Now that all events have been added, we can trigger the
549
573
// `pagination_token_notifier`.
@@ -648,7 +672,11 @@ mod private {
648
672
sort_positions_descending, EventLocation , LoadMoreEventsBackwardsOutcome ,
649
673
} ;
650
674
use crate :: event_cache:: {
651
- deduplicator:: filter_duplicate_events, room:: threads:: ThreadEventCache ,
675
+ deduplicator:: filter_duplicate_events,
676
+ room:: threads:: {
677
+ should_subscribe_thread, AutomaticThreadSubscriptions , ThreadEventCache ,
678
+ ThreadPushContext ,
679
+ } ,
652
680
BackPaginationOutcome , RoomPaginationStatus , ThreadEventCacheUpdate ,
653
681
} ;
654
682
@@ -1438,11 +1466,14 @@ mod private {
1438
1466
/// linked chunk.
1439
1467
///
1440
1468
/// Flushes updates to disk first.
1469
+ ///
1470
+ /// Returns new thread subscriptions, if any.
1441
1471
async fn post_process_new_events (
1442
1472
& mut self ,
1473
+ push_context : ThreadPushContext ,
1443
1474
events : Vec < Event > ,
1444
1475
is_sync : bool ,
1445
- ) -> Result < ( ) , EventCacheError > {
1476
+ ) -> Result < AutomaticThreadSubscriptions , EventCacheError > {
1446
1477
// Update the store before doing the post-processing.
1447
1478
self . propagate_changes ( ) . await ?;
1448
1479
@@ -1454,7 +1485,7 @@ mod private {
1454
1485
if let Some ( thread_root) = extract_thread_root ( event. raw ( ) ) {
1455
1486
new_events_by_thread. entry ( thread_root) . or_default ( ) . push ( event. clone ( ) ) ;
1456
1487
} else if let Some ( event_id) = event. event_id ( ) {
1457
- // If we spot the root of a thread, add it to its linked chunk, in sync mode .
1488
+ // If we spot the root of a thread, add it to its linked chunk.
1458
1489
if self . threads . contains_key ( & event_id) {
1459
1490
new_events_by_thread. entry ( event_id) . or_default ( ) . push ( event. clone ( ) ) ;
1460
1491
}
@@ -1466,9 +1497,10 @@ mod private {
1466
1497
}
1467
1498
}
1468
1499
1469
- self . update_threads ( new_events_by_thread, is_sync) . await ?;
1500
+ let new_thread_subs =
1501
+ self . update_threads ( push_context, new_events_by_thread, is_sync) . await ?;
1470
1502
1471
- Ok ( ( ) )
1503
+ Ok ( new_thread_subs )
1472
1504
}
1473
1505
1474
1506
fn get_or_reload_thread ( & mut self , root_event_id : OwnedEventId ) -> & mut ThreadEventCache {
@@ -1479,15 +1511,34 @@ mod private {
1479
1511
. or_insert_with ( || ThreadEventCache :: new ( root_event_id) )
1480
1512
}
1481
1513
1514
+ /// Updates the threads' states according to new events:
1515
+ ///
1516
+ /// - updates the in-memory thread cache with new events,
1517
+ /// - updates the thread summary in the thread root (in the main room's
1518
+ /// linked chunk),
1519
+ /// - returns the threads to automatically subscribe to
1482
1520
#[ instrument( skip_all) ]
1483
1521
async fn update_threads (
1484
1522
& mut self ,
1523
+ push_context : ThreadPushContext ,
1485
1524
new_events_by_thread : BTreeMap < OwnedEventId , Vec < Event > > ,
1486
1525
is_sync : bool ,
1487
- ) -> Result < ( ) , EventCacheError > {
1526
+ ) -> Result < AutomaticThreadSubscriptions , EventCacheError > {
1527
+ let mut thread_subscriptions = AutomaticThreadSubscriptions :: default ( ) ;
1528
+
1488
1529
for ( thread_root, new_events) in new_events_by_thread {
1489
1530
let thread_cache = self . get_or_reload_thread ( thread_root. clone ( ) ) ;
1490
1531
1532
+ // Compute the needed thread subscriptions.
1533
+ // We want to subscribe up to the most recent event that mentions us. Events are
1534
+ // in topological order, so start in reverse, and break at the
1535
+ // first event that mentions us.
1536
+ if let Some ( subscribe_to_event_id) =
1537
+ should_subscribe_thread ( & push_context, new_events. iter ( ) ) . await
1538
+ {
1539
+ thread_subscriptions. 0 . insert ( thread_root. clone ( ) , subscribe_to_event_id) ;
1540
+ }
1541
+
1491
1542
// If we're not in sync mode, we're receiving events from a room pagination: as
1492
1543
// we don't know where they should be put in a thread linked
1493
1544
// chunk, we don't try to be smart and include them. That's for
@@ -1547,7 +1598,7 @@ mod private {
1547
1598
self . replace_event_at ( location, target_event) . await ?;
1548
1599
}
1549
1600
1550
- Ok ( ( ) )
1601
+ Ok ( thread_subscriptions )
1551
1602
}
1552
1603
1553
1604
/// Replaces a single event, be it saved in memory or in the store.
@@ -1687,8 +1738,10 @@ mod private {
1687
1738
#[ must_use = "Propagate `VectorDiff` updates via `RoomEventCacheUpdate`" ]
1688
1739
pub async fn handle_sync (
1689
1740
& mut self ,
1741
+ push_context : ThreadPushContext ,
1690
1742
mut timeline : Timeline ,
1691
- ) -> Result < ( bool , Vec < VectorDiff < Event > > ) , EventCacheError > {
1743
+ ) -> Result < ( bool , Vec < VectorDiff < Event > > , AutomaticThreadSubscriptions ) , EventCacheError >
1744
+ {
1692
1745
let mut prev_batch = timeline. prev_batch . take ( ) ;
1693
1746
1694
1747
let DeduplicationOutcome {
@@ -1759,7 +1812,7 @@ mod private {
1759
1812
if all_duplicates {
1760
1813
// No new events and no gap (per the previous check), thus no need to change the
1761
1814
// room state. We're done!
1762
- return Ok ( ( false , Vec :: new ( ) ) ) ;
1815
+ return Ok ( ( false , Vec :: new ( ) , Default :: default ( ) ) ) ;
1763
1816
}
1764
1817
1765
1818
let has_new_gap = prev_batch. is_some ( ) ;
@@ -1780,7 +1833,7 @@ mod private {
1780
1833
self . room_linked_chunk
1781
1834
. push_live_events ( prev_batch. map ( |prev_token| Gap { prev_token } ) , & events) ;
1782
1835
1783
- self . post_process_new_events ( events, true ) . await ?;
1836
+ let new_thread_subs = self . post_process_new_events ( push_context , events, true ) . await ?;
1784
1837
1785
1838
if timeline. limited && has_new_gap {
1786
1839
// If there was a previous batch token for a limited timeline, unload the chunks
@@ -1794,7 +1847,7 @@ mod private {
1794
1847
1795
1848
let timeline_event_diffs = self . room_linked_chunk . updates_as_vector_diffs ( ) ;
1796
1849
1797
- Ok ( ( has_new_gap, timeline_event_diffs) )
1850
+ Ok ( ( has_new_gap, timeline_event_diffs, new_thread_subs ) )
1798
1851
}
1799
1852
1800
1853
/// Handle the result of a single back-pagination request.
@@ -1807,11 +1860,14 @@ mod private {
1807
1860
#[ must_use = "Propagate `VectorDiff` updates via `RoomEventCacheUpdate`" ]
1808
1861
pub async fn handle_backpagination (
1809
1862
& mut self ,
1863
+ push_context : ThreadPushContext ,
1810
1864
events : Vec < Event > ,
1811
1865
mut new_token : Option < String > ,
1812
1866
prev_token : Option < String > ,
1813
- ) -> Result < Option < ( BackPaginationOutcome , Vec < VectorDiff < Event > > ) > , EventCacheError >
1814
- {
1867
+ ) -> Result <
1868
+ Option < ( BackPaginationOutcome , Vec < VectorDiff < Event > > , AutomaticThreadSubscriptions ) > ,
1869
+ EventCacheError ,
1870
+ > {
1815
1871
// Check that the previous token still exists; otherwise it's a sign that the
1816
1872
// room's timeline has been cleared.
1817
1873
let prev_gap_id = if let Some ( token) = prev_token {
@@ -1884,11 +1940,16 @@ mod private {
1884
1940
) ;
1885
1941
1886
1942
// Note: this flushes updates to the store.
1887
- self . post_process_new_events ( topo_ordered_events, false ) . await ?;
1943
+ let new_thread_subs =
1944
+ self . post_process_new_events ( push_context, topo_ordered_events, false ) . await ?;
1888
1945
1889
1946
let event_diffs = self . room_linked_chunk . updates_as_vector_diffs ( ) ;
1890
1947
1891
- Ok ( Some ( ( BackPaginationOutcome { events, reached_start } , event_diffs) ) )
1948
+ Ok ( Some ( (
1949
+ BackPaginationOutcome { events, reached_start } ,
1950
+ event_diffs,
1951
+ new_thread_subs,
1952
+ ) ) )
1892
1953
}
1893
1954
1894
1955
/// Subscribe to thread for a given root event, and get a (maybe empty)
@@ -1903,14 +1964,17 @@ mod private {
1903
1964
/// Back paginate in the given thread.
1904
1965
///
1905
1966
/// Will always start from the end, unless we previously paginated.
1906
- pub fn finish_thread_network_pagination (
1967
+ pub async fn finish_thread_network_pagination (
1907
1968
& mut self ,
1969
+ push_context : ThreadPushContext ,
1908
1970
root : OwnedEventId ,
1909
1971
prev_token : Option < String > ,
1910
1972
new_token : Option < String > ,
1911
1973
events : Vec < Event > ,
1912
- ) -> Option < BackPaginationOutcome > {
1913
- self . get_or_reload_thread ( root) . finish_network_pagination ( prev_token, new_token, events)
1974
+ ) -> Option < ( BackPaginationOutcome , AutomaticThreadSubscriptions ) > {
1975
+ self . get_or_reload_thread ( root)
1976
+ . finish_network_pagination ( push_context, prev_token, new_token, events)
1977
+ . await
1914
1978
}
1915
1979
1916
1980
pub fn load_more_thread_events_backwards (
0 commit comments