14
14
15
15
use std:: sync:: { Arc , RwLock as SyncRwLock } ;
16
16
17
+ use dashmap:: DashSet ;
18
+ use futures_channel:: mpsc;
19
+ use futures_core:: stream:: Stream ;
17
20
use futures_util:: stream:: { self , StreamExt } ;
21
+ use matrix_sdk_common:: locks:: Mutex ;
18
22
use ruma:: {
19
23
api:: client:: r0:: sync:: sync_events:: RoomSummary as RumaSummary ,
20
24
events:: {
@@ -34,12 +38,13 @@ use ruma::{
34
38
EventId , MxcUri , RoomAliasId , RoomId , UserId ,
35
39
} ;
36
40
use serde:: { Deserialize , Serialize } ;
37
- use tracing:: debug;
41
+ use tracing:: { debug, warn } ;
38
42
39
43
use super :: { BaseRoomInfo , RoomMember } ;
40
44
use crate :: {
41
- deserialized_responses:: UnreadNotificationsCount ,
45
+ deserialized_responses:: { SyncRoomEvent , TimelineSlice , UnreadNotificationsCount } ,
42
46
store:: { Result as StoreResult , StateStore } ,
47
+ timeline_stream:: { TimelineStreamBackward , TimelineStreamError , TimelineStreamForward } ,
43
48
} ;
44
49
45
50
/// The underlying room data structure collecting state for joined, left and
@@ -50,6 +55,8 @@ pub struct Room {
50
55
own_user_id : Arc < UserId > ,
51
56
inner : Arc < SyncRwLock < RoomInfo > > ,
52
57
store : Arc < dyn StateStore > ,
58
+ forward_timeline_streams : Arc < Mutex < Vec < mpsc:: Sender < TimelineSlice > > > > ,
59
+ backward_timeline_streams : Arc < Mutex < Vec < mpsc:: Sender < TimelineSlice > > > > ,
53
60
}
54
61
55
62
/// The room summary containing member counts and members that should be used to
@@ -107,6 +114,8 @@ impl Room {
107
114
room_id : room_info. room_id . clone ( ) ,
108
115
store,
109
116
inner : Arc :: new ( SyncRwLock :: new ( room_info) ) ,
117
+ forward_timeline_streams : Default :: default ( ) ,
118
+ backward_timeline_streams : Default :: default ( ) ,
110
119
}
111
120
}
112
121
@@ -467,6 +476,112 @@ impl Room {
467
476
) -> StoreResult < Vec < ( Box < UserId > , Receipt ) > > {
468
477
self . store . get_event_room_receipt_events ( self . room_id ( ) , ReceiptType :: Read , event_id) . await
469
478
}
479
+
480
+ /// Get two stream into the timeline.
481
+ /// First one is forward in time and the second one is backward in time.
482
+ pub async fn timeline (
483
+ & self ,
484
+ ) -> StoreResult < (
485
+ impl Stream < Item = SyncRoomEvent > ,
486
+ impl Stream < Item = Result < SyncRoomEvent , TimelineStreamError > > ,
487
+ ) > {
488
+ // We need to hold the lock while we create the stream so that we don't lose new
489
+ // sync responses
490
+ let mut forward_timeline_streams = self . forward_timeline_streams . lock ( ) . await ;
491
+ let mut backward_timeline_streams = self . backward_timeline_streams . lock ( ) . await ;
492
+ let sync_token = self . store . get_sync_token ( ) . await ?;
493
+ let event_ids = Arc :: new ( DashSet :: new ( ) ) ;
494
+
495
+ let ( backward_stream, backward_sender) = if let Some ( ( stored_events, end_token) ) =
496
+ self . store . room_timeline ( & self . room_id ) . await ?
497
+ {
498
+ TimelineStreamBackward :: new ( event_ids. clone ( ) , end_token, Some ( stored_events) )
499
+ } else {
500
+ TimelineStreamBackward :: new ( event_ids. clone ( ) , Some ( sync_token. clone ( ) . unwrap ( ) ) , None )
501
+ } ;
502
+
503
+ backward_timeline_streams. push ( backward_sender) ;
504
+
505
+ let ( forward_stream, forward_sender) = TimelineStreamForward :: new ( event_ids) ;
506
+ forward_timeline_streams. push ( forward_sender) ;
507
+
508
+ Ok ( ( forward_stream, backward_stream) )
509
+ }
510
+
511
+ /// Create a stream that returns all events of the room's timeline forward
512
+ /// in time.
513
+ ///
514
+ /// If you need also a backward stream you should use
515
+ /// [`timeline`][`crate::Room::timeline`]
516
+ pub async fn timeline_forward ( & self ) -> StoreResult < impl Stream < Item = SyncRoomEvent > > {
517
+ let mut forward_timeline_streams = self . forward_timeline_streams . lock ( ) . await ;
518
+ let event_ids = Arc :: new ( DashSet :: new ( ) ) ;
519
+
520
+ let ( forward_stream, forward_sender) = TimelineStreamForward :: new ( event_ids) ;
521
+ forward_timeline_streams. push ( forward_sender) ;
522
+
523
+ Ok ( forward_stream)
524
+ }
525
+
526
+ /// Create a stream that returns all events of the room's timeline backward
527
+ /// in time.
528
+ ///
529
+ /// If you need also a forward stream you should use
530
+ /// [`timeline`][`crate::Room::timeline`]
531
+ pub async fn timeline_backward (
532
+ & self ,
533
+ ) -> StoreResult < impl Stream < Item = Result < SyncRoomEvent , TimelineStreamError > > > {
534
+ let mut backward_timeline_streams = self . backward_timeline_streams . lock ( ) . await ;
535
+ let sync_token = self . store . get_sync_token ( ) . await ?;
536
+ let event_ids = Arc :: new ( DashSet :: new ( ) ) ;
537
+
538
+ let ( backward_stream, backward_sender) = if let Some ( ( stored_events, end_token) ) =
539
+ self . store . room_timeline ( & self . room_id ) . await ?
540
+ {
541
+ TimelineStreamBackward :: new ( event_ids. clone ( ) , end_token, Some ( stored_events) )
542
+ } else {
543
+ TimelineStreamBackward :: new ( event_ids. clone ( ) , Some ( sync_token. clone ( ) . unwrap ( ) ) , None )
544
+ } ;
545
+
546
+ backward_timeline_streams. push ( backward_sender) ;
547
+
548
+ Ok ( backward_stream)
549
+ }
550
+
551
+ /// Add a new timeline slice to the timeline streams.
552
+ pub async fn add_timeline_slice ( & self , timeline : & TimelineSlice ) {
553
+ if timeline. sync {
554
+ let mut streams = self . forward_timeline_streams . lock ( ) . await ;
555
+ let mut remaining_streams = Vec :: with_capacity ( streams. len ( ) ) ;
556
+ while let Some ( mut forward) = streams. pop ( ) {
557
+ if !forward. is_closed ( ) {
558
+ if let Err ( error) = forward. try_send ( timeline. clone ( ) ) {
559
+ if error. is_full ( ) {
560
+ warn ! ( "Drop timeline slice because the limit of the buffer for the forward stream is reached" ) ;
561
+ }
562
+ } else {
563
+ remaining_streams. push ( forward) ;
564
+ }
565
+ }
566
+ }
567
+ * streams = remaining_streams;
568
+ } else {
569
+ let mut streams = self . backward_timeline_streams . lock ( ) . await ;
570
+ let mut remaining_streams = Vec :: with_capacity ( streams. len ( ) ) ;
571
+ while let Some ( mut backward) = streams. pop ( ) {
572
+ if !backward. is_closed ( ) {
573
+ if let Err ( error) = backward. try_send ( timeline. clone ( ) ) {
574
+ if error. is_full ( ) {
575
+ warn ! ( "Drop timeline slice because the limit of the buffer for the backward stream is reached" ) ;
576
+ }
577
+ } else {
578
+ remaining_streams. push ( backward) ;
579
+ }
580
+ }
581
+ }
582
+ * streams = remaining_streams;
583
+ }
584
+ }
470
585
}
471
586
472
587
/// The underlying pure data structure for joined and left rooms.
0 commit comments