1mod error;
50mod latest_event;
51mod room_latest_events;
52
53use std::{
54 collections::HashMap,
55 ops::{ControlFlow, DerefMut, Not},
56 sync::Arc,
57};
58
59pub use error::LatestEventsError;
60use eyeball::{AsyncLock, Subscriber};
61pub(crate) use latest_event::filter_timeline_event;
62use latest_event::{LatestEvent, With};
63pub use latest_event::{LatestEventValue, LocalLatestEventValue, RemoteLatestEventValue};
64use matrix_sdk_base::{RoomInfoNotableUpdate, RoomInfoNotableUpdateReasons, timer};
65use matrix_sdk_common::executor::{AbortOnDrop, JoinHandleExt as _, spawn};
66use room_latest_events::{RoomLatestEvents, RoomLatestEventsWriteGuard};
67use ruma::{EventId, OwnedRoomId, RoomId};
68use tokio::{
69 select,
70 sync::{RwLock, RwLockReadGuard, RwLockWriteGuard, broadcast, mpsc},
71};
72use tracing::{info, warn};
73
74use crate::{
75 client::WeakClient,
76 event_cache::{EventCache, RoomEventCacheGenericUpdate},
77 room::WeakRoom,
78 send_queue::{RoomSendQueueUpdate, SendQueue, SendQueueUpdate},
79};
80
81#[derive(Clone, Debug)]
83pub struct LatestEvents {
84 state: Arc<LatestEventsState>,
85}
86
87#[derive(Debug)]
89struct LatestEventsState {
90 registered_rooms: Arc<RegisteredRooms>,
92
93 _listen_task_handle: AbortOnDrop<()>,
95
96 _computation_task_handle: AbortOnDrop<()>,
98}
99
100impl LatestEvents {
101 pub(crate) fn new(
103 weak_client: WeakClient,
104 event_cache: EventCache,
105 send_queue: SendQueue,
106 room_info_updates: broadcast::Receiver<RoomInfoNotableUpdate>,
107 ) -> Self {
108 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
109
110 let registered_rooms =
111 Arc::new(RegisteredRooms::new(weak_client, &event_cache, &latest_event_queue_sender));
112
113 let send_queue_generic_updates_subscriber = send_queue.subscribe();
121 let listen_task_handle = spawn(listen_to_updates_task(
122 registered_rooms.clone(),
123 event_cache,
124 send_queue_generic_updates_subscriber,
125 room_info_updates,
126 latest_event_queue_sender,
127 ))
128 .abort_on_drop();
129
130 let computation_task_handle = spawn(compute_latest_events_task(
132 registered_rooms.clone(),
133 latest_event_queue_receiver,
134 ))
135 .abort_on_drop();
136
137 Self {
138 state: Arc::new(LatestEventsState {
139 registered_rooms,
140 _listen_task_handle: listen_task_handle,
141 _computation_task_handle: computation_task_handle,
142 }),
143 }
144 }
145
146 pub async fn listen_to_room(&self, room_id: &RoomId) -> Result<bool, LatestEventsError> {
150 Ok(self.state.registered_rooms.for_room(room_id).await?.is_some())
151 }
152
153 #[cfg(test)]
157 pub async fn is_listening_to_room(&self, room_id: &RoomId) -> bool {
158 self.state.registered_rooms.rooms.read().await.contains_key(room_id)
159 }
160
161 pub async fn listen_and_subscribe_to_room(
167 &self,
168 room_id: &RoomId,
169 ) -> Result<Option<Subscriber<LatestEventValue, AsyncLock>>, LatestEventsError> {
170 let Some(room_latest_events) = self.state.registered_rooms.for_room(room_id).await? else {
171 return Ok(None);
172 };
173
174 let room_latest_events = room_latest_events.read().await;
175 let latest_event = room_latest_events.for_room();
176
177 Ok(Some(latest_event.subscribe().await))
178 }
179
180 pub async fn listen_to_thread(
185 &self,
186 room_id: &RoomId,
187 thread_id: &EventId,
188 ) -> Result<bool, LatestEventsError> {
189 Ok(self.state.registered_rooms.for_thread(room_id, thread_id).await?.is_some())
190 }
191
192 pub async fn listen_and_subscribe_to_thread(
198 &self,
199 room_id: &RoomId,
200 thread_id: &EventId,
201 ) -> Result<Option<Subscriber<LatestEventValue, AsyncLock>>, LatestEventsError> {
202 let Some(room_latest_events) =
203 self.state.registered_rooms.for_thread(room_id, thread_id).await?
204 else {
205 return Ok(None);
206 };
207
208 let room_latest_events = room_latest_events.read().await;
209 let latest_event = room_latest_events
210 .for_thread(thread_id)
211 .expect("The `LatestEvent` for the thread must have been created");
212
213 Ok(Some(latest_event.subscribe().await))
214 }
215
216 pub async fn forget_room(&self, room_id: &RoomId) {
223 self.state.registered_rooms.forget_room(room_id).await;
224 }
225
226 pub async fn forget_thread(&self, room_id: &RoomId, thread_id: &EventId) {
234 self.state.registered_rooms.forget_thread(room_id, thread_id).await;
235 }
236}
237
238#[derive(Debug)]
239struct RegisteredRooms {
240 rooms: RwLock<HashMap<OwnedRoomId, RoomLatestEvents>>,
242
243 weak_client: WeakClient,
245
246 event_cache: EventCache,
248
249 latest_event_queue_sender: mpsc::UnboundedSender<LatestEventQueueUpdate>,
254}
255
256impl RegisteredRooms {
257 fn new(
258 weak_client: WeakClient,
259 event_cache: &EventCache,
260 latest_event_queue_sender: &mpsc::UnboundedSender<LatestEventQueueUpdate>,
261 ) -> Self {
262 Self {
263 rooms: RwLock::new(HashMap::default()),
264 weak_client,
265 event_cache: event_cache.clone(),
266 latest_event_queue_sender: latest_event_queue_sender.clone(),
267 }
268 }
269
270 async fn room_latest_event(
277 &self,
278 room_id: &RoomId,
279 thread_id: Option<&EventId>,
280 ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
281 fn create_and_insert_room_latest_events(
282 room_id: &RoomId,
283 rooms: &mut HashMap<OwnedRoomId, RoomLatestEvents>,
284 weak_client: &WeakClient,
285 event_cache: &EventCache,
286 latest_event_queue_sender: &mpsc::UnboundedSender<LatestEventQueueUpdate>,
287 ) {
288 let (room_latest_events, is_latest_event_value_none) =
289 With::unzip(RoomLatestEvents::new(
290 WeakRoom::new(weak_client.clone(), room_id.to_owned()),
291 event_cache,
292 ));
293
294 rooms.insert(room_id.to_owned(), room_latest_events);
296
297 if is_latest_event_value_none {
304 let _ = latest_event_queue_sender
305 .send(LatestEventQueueUpdate::EventCache { room_id: room_id.to_owned() });
306 }
307 }
308
309 Ok(match thread_id {
310 Some(thread_id) => {
316 let mut rooms = self.rooms.write().await;
317
318 if rooms.contains_key(room_id).not() {
321 create_and_insert_room_latest_events(
322 room_id,
323 rooms.deref_mut(),
324 &self.weak_client,
325 &self.event_cache,
326 &self.latest_event_queue_sender,
327 );
328 }
329
330 if let Some(room_latest_event) = rooms.get(room_id) {
331 let mut room_latest_event = room_latest_event.write().await;
332
333 if room_latest_event.has_thread(thread_id).not() {
336 room_latest_event.create_and_insert_latest_event_for_thread(thread_id);
337 }
338 }
339
340 RwLockWriteGuard::try_downgrade_map(rooms, |rooms| rooms.get(room_id)).ok()
341 }
342
343 None => {
346 match RwLockReadGuard::try_map(self.rooms.read().await, |rooms| rooms.get(room_id))
347 .ok()
348 {
349 value @ Some(_) => value,
350 None => {
351 let _timer = timer!(
352 tracing::Level::DEBUG,
353 format!("Creating `RoomLatestEvents` for {room_id:?}"),
354 );
355
356 let mut rooms = self.rooms.write().await;
357
358 if rooms.contains_key(room_id).not() {
359 create_and_insert_room_latest_events(
360 room_id,
361 rooms.deref_mut(),
362 &self.weak_client,
363 &self.event_cache,
364 &self.latest_event_queue_sender,
365 );
366 }
367
368 RwLockWriteGuard::try_downgrade_map(rooms, |rooms| rooms.get(room_id)).ok()
369 }
370 }
371 }
372 })
373 }
374
375 pub async fn for_room(
379 &self,
380 room_id: &RoomId,
381 ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
382 self.room_latest_event(room_id, None).await
383 }
384
385 pub async fn for_thread(
389 &self,
390 room_id: &RoomId,
391 thread_id: &EventId,
392 ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
393 self.room_latest_event(room_id, Some(thread_id)).await
394 }
395
396 pub async fn forget_room(&self, room_id: &RoomId) {
403 {
404 let mut rooms = self.rooms.write().await;
405
406 rooms.remove(room_id);
408 }
409 }
410
411 pub async fn forget_thread(&self, room_id: &RoomId, thread_id: &EventId) {
419 let rooms = self.rooms.read().await;
420
421 if let Some(room_latest_event) = rooms.get(room_id) {
423 let mut room_latest_event = room_latest_event.write().await;
424
425 drop(rooms);
427
428 room_latest_event.forget_thread(thread_id);
429 }
430 }
431}
432
433#[derive(Debug)]
436enum LatestEventQueueUpdate {
437 EventCache {
439 room_id: OwnedRoomId,
441 },
442
443 SendQueue {
445 room_id: OwnedRoomId,
447
448 update: RoomSendQueueUpdate,
450 },
451
452 RoomInfo {
456 room_id: OwnedRoomId,
458
459 reasons: RoomInfoNotableUpdateReasons,
461 },
462}
463
464async fn listen_to_updates_task(
473 registered_rooms: Arc<RegisteredRooms>,
474 event_cache: EventCache,
475 mut send_queue_generic_updates_subscriber: broadcast::Receiver<SendQueueUpdate>,
476 room_info_updates: broadcast::Receiver<RoomInfoNotableUpdate>,
477 latest_event_queue_sender: mpsc::UnboundedSender<LatestEventQueueUpdate>,
478) {
479 let mut event_cache_generic_updates_subscriber =
480 event_cache.subscribe_to_room_generic_updates();
481 let mut room_info_updates_subscriber = room_info_updates.resubscribe();
482
483 loop {
484 if listen_to_updates(
485 ®istered_rooms.rooms,
486 &mut event_cache_generic_updates_subscriber,
487 &mut send_queue_generic_updates_subscriber,
488 &mut room_info_updates_subscriber,
489 &latest_event_queue_sender,
490 )
491 .await
492 .is_break()
493 {
494 warn!("`listen_to_updates_task` has stopped");
495
496 break;
497 }
498 }
499}
500
501async fn listen_to_updates(
506 registered_rooms: &RwLock<HashMap<OwnedRoomId, RoomLatestEvents>>,
507 event_cache_generic_updates_subscriber: &mut broadcast::Receiver<RoomEventCacheGenericUpdate>,
508 send_queue_generic_updates_subscriber: &mut broadcast::Receiver<SendQueueUpdate>,
509 room_info_updates_subscriber: &mut broadcast::Receiver<RoomInfoNotableUpdate>,
510 latest_event_queue_sender: &mpsc::UnboundedSender<LatestEventQueueUpdate>,
511) -> ControlFlow<()> {
512 select! {
513 room_event_cache_generic_update = event_cache_generic_updates_subscriber.recv() => {
514 if let Ok(RoomEventCacheGenericUpdate { room_id }) = room_event_cache_generic_update {
515 if registered_rooms.read().await.contains_key(&room_id) {
516 let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::EventCache {
517 room_id
518 });
519 }
520 } else {
521 warn!("`event_cache_generic_updates` channel has been closed");
522
523 return ControlFlow::Break(());
524 }
525 }
526
527 send_queue_generic_update = send_queue_generic_updates_subscriber.recv() => {
528 if let Ok(SendQueueUpdate { room_id, update }) = send_queue_generic_update {
529 if registered_rooms.read().await.contains_key(&room_id) {
530 let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::SendQueue {
531 room_id,
532 update
533 });
534 }
535 } else {
536 warn!("`send_queue_generic_updates` channel has been closed");
537
538 return ControlFlow::Break(());
539 }
540 }
541
542 room_info_update = room_info_updates_subscriber.recv() => {
543 if let Ok(RoomInfoNotableUpdate { room_id, reasons }) = room_info_update {
544 if
546 reasons == RoomInfoNotableUpdateReasons::LATEST_EVENT ||
549
550 !reasons.contains(RoomInfoNotableUpdateReasons::MEMBERSHIP)
554 {
555 return ControlFlow::Continue(())
556 }
557
558 if registered_rooms.read().await.contains_key(&room_id) {
559 let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::RoomInfo {
560 room_id,
561 reasons,
562 });
563 }
564 } else {
565 warn!("`room_info_updates` channel has been closed");
566
567 return ControlFlow::Break(());
568 }
569 }
570 }
571
572 ControlFlow::Continue(())
573}
574
575async fn compute_latest_events_task(
580 registered_rooms: Arc<RegisteredRooms>,
581 mut latest_event_queue_receiver: mpsc::UnboundedReceiver<LatestEventQueueUpdate>,
582) {
583 const BUFFER_SIZE: usize = 16;
584
585 let mut buffer = Vec::with_capacity(BUFFER_SIZE);
586
587 while latest_event_queue_receiver.recv_many(&mut buffer, BUFFER_SIZE).await > 0 {
588 compute_latest_events(®istered_rooms, &buffer).await;
589 buffer.clear();
590 }
591
592 warn!("`compute_latest_events_task` has stopped");
593}
594
595async fn compute_latest_events(
596 registered_rooms: &RegisteredRooms,
597 latest_event_queue_updates: &[LatestEventQueueUpdate],
598) {
599 async fn room_latest_events_write_guard(
600 registered_rooms: &RegisteredRooms,
601 room_id: &OwnedRoomId,
602 ) -> ControlFlow<RoomLatestEventsWriteGuard, ()> {
603 let rooms = registered_rooms.rooms.read().await;
604
605 if let Some(room_latest_events) = rooms.get(room_id) {
606 let room_latest_events = room_latest_events.write().await;
607
608 drop(rooms);
611
612 ControlFlow::Break(room_latest_events)
613 } else {
614 info!(?room_id, "Failed to find the room");
615
616 ControlFlow::Continue(())
617 }
618 }
619
620 for latest_event_queue_update in latest_event_queue_updates {
621 match latest_event_queue_update {
622 LatestEventQueueUpdate::EventCache { room_id } => {
623 let ControlFlow::Break(mut room_latest_events) =
624 room_latest_events_write_guard(registered_rooms, room_id).await
625 else {
626 continue;
627 };
628
629 room_latest_events.update_with_event_cache().await;
630 }
631
632 LatestEventQueueUpdate::SendQueue { room_id, update } => {
633 let ControlFlow::Break(mut room_latest_events) =
634 room_latest_events_write_guard(registered_rooms, room_id).await
635 else {
636 continue;
637 };
638
639 room_latest_events.update_with_send_queue(update).await;
640 }
641
642 LatestEventQueueUpdate::RoomInfo { room_id, reasons } => {
643 let ControlFlow::Break(mut room_latest_events) =
644 room_latest_events_write_guard(registered_rooms, room_id).await
645 else {
646 continue;
647 };
648
649 room_latest_events.update_with_room_info(*reasons).await;
650 }
651 }
652 }
653}
654
655#[cfg(test)]
656fn local_room_message(body: &str) -> LocalLatestEventValue {
657 use matrix_sdk_base::store::SerializableEventContent;
658 use ruma::{
659 MilliSecondsSinceUnixEpoch,
660 events::{AnyMessageLikeEventContent, room::message::RoomMessageEventContent},
661 };
662
663 LocalLatestEventValue {
664 timestamp: MilliSecondsSinceUnixEpoch::now(),
665 content: SerializableEventContent::new(&AnyMessageLikeEventContent::RoomMessage(
666 RoomMessageEventContent::text_plain(body),
667 ))
668 .unwrap(),
669 }
670}
671
672#[cfg(all(test, not(target_family = "wasm")))]
673mod tests {
674 use std::{collections::HashMap, ops::Not, time::Duration};
675
676 use assert_matches::assert_matches;
677 use matrix_sdk_base::{
678 RoomState,
679 cross_process_lock::CrossProcessLockConfig,
680 deserialized_responses::TimelineEventKind,
681 event_cache::store::{EventCacheStore, MemoryStore},
682 linked_chunk::{ChunkIdentifier, LinkedChunkId, Position, Update},
683 store::StoreConfig,
684 };
685 use matrix_sdk_test::{
686 InvitedRoomBuilder, JoinedRoomBuilder, async_test, event_factory::EventFactory,
687 };
688 use ruma::{
689 MilliSecondsSinceUnixEpoch, OwnedTransactionId, event_id,
690 events::{
691 AnySyncMessageLikeEvent, AnySyncStateEvent, AnySyncTimelineEvent, SyncMessageLikeEvent,
692 room::member::{MembershipState, SyncRoomMemberEvent},
693 },
694 owned_event_id, owned_room_id, room_id, user_id,
695 };
696 use stream_assert::assert_pending;
697 use tokio::{
698 task::yield_now,
699 time::{sleep, timeout},
700 };
701
702 use super::{
703 LatestEventValue, RegisteredRooms, RemoteLatestEventValue, RoomEventCacheGenericUpdate,
704 RoomInfoNotableUpdate, RoomInfoNotableUpdateReasons, RoomLatestEvents, RoomSendQueueUpdate,
705 RwLock, SendQueueUpdate, WeakRoom, With, broadcast, listen_to_updates, mpsc,
706 };
707 use crate::{
708 latest_events::{LatestEventQueueUpdate, local_room_message},
709 test_utils::{client::MockClientBuilder, mocks::MatrixMockServer},
710 };
711
712 #[async_test]
713 async fn test_latest_events_are_lazy() {
714 let room_id_0 = room_id!("!r0");
715 let room_id_1 = room_id!("!r1");
716 let room_id_2 = room_id!("!r2");
717 let thread_id_1_0 = event_id!("$ev1.0");
718 let thread_id_2_0 = event_id!("$ev2.0");
719
720 let server = MatrixMockServer::new().await;
721 let client = server.client_builder().build().await;
722
723 client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
724 client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
725 client.base_client().get_or_create_room(room_id_2, RoomState::Joined);
726
727 let latest_events = client.latest_events().await.unwrap();
728
729 assert!(latest_events.state.registered_rooms.rooms.read().await.is_empty());
731
732 assert!(latest_events.listen_to_room(room_id_0).await.unwrap());
734 assert!(latest_events.listen_to_room(room_id_1).await.unwrap());
735
736 {
737 let rooms = latest_events.state.registered_rooms.rooms.read().await;
738 assert_eq!(rooms.len(), 2);
740 assert!(rooms.contains_key(room_id_0));
742 assert!(rooms.contains_key(room_id_1));
743
744 assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
746 assert!(rooms.get(room_id_1).unwrap().read().await.per_thread().is_empty());
748 }
749
750 assert!(latest_events.listen_to_thread(room_id_1, thread_id_1_0).await.unwrap());
752 assert!(latest_events.listen_to_thread(room_id_2, thread_id_2_0).await.unwrap());
753
754 {
755 let rooms = latest_events.state.registered_rooms.rooms.read().await;
756 assert_eq!(rooms.len(), 3);
758 assert!(rooms.contains_key(room_id_0));
760 assert!(rooms.contains_key(room_id_1));
761 assert!(rooms.contains_key(room_id_2));
762
763 assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
765 let room_1 = rooms.get(room_id_1).unwrap().read().await;
767 assert_eq!(room_1.per_thread().len(), 1);
768 assert!(room_1.per_thread().contains_key(thread_id_1_0));
770 let room_2 = rooms.get(room_id_2).unwrap().read().await;
772 assert_eq!(room_2.per_thread().len(), 1);
773 assert!(room_2.per_thread().contains_key(thread_id_2_0));
775 }
776 }
777
778 #[async_test]
779 async fn test_forget_room() {
780 let room_id_0 = room_id!("!r0");
781 let room_id_1 = room_id!("!r1");
782
783 let server = MatrixMockServer::new().await;
784 let client = server.client_builder().build().await;
785
786 client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
787 client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
788
789 let latest_events = client.latest_events().await.unwrap();
790
791 assert!(latest_events.listen_to_room(room_id_0).await.unwrap());
793
794 {
795 let rooms = latest_events.state.registered_rooms.rooms.read().await;
796 assert_eq!(rooms.len(), 1);
798 assert!(rooms.contains_key(room_id_0));
800
801 assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
803 }
804
805 latest_events.forget_room(room_id_0).await;
807
808 {
809 let rooms = latest_events.state.registered_rooms.rooms.read().await;
810 assert!(rooms.is_empty());
812 }
813 }
814
815 #[async_test]
816 async fn test_forget_thread() {
817 let room_id_0 = room_id!("!r0");
818 let room_id_1 = room_id!("!r1");
819 let thread_id_0_0 = event_id!("$ev0.0");
820
821 let server = MatrixMockServer::new().await;
822 let client = server.client_builder().build().await;
823
824 client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
825 client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
826
827 let latest_events = client.latest_events().await.unwrap();
828
829 assert!(latest_events.listen_to_thread(room_id_0, thread_id_0_0).await.unwrap());
831
832 {
833 let rooms = latest_events.state.registered_rooms.rooms.read().await;
834 assert_eq!(rooms.len(), 1);
836 assert!(rooms.contains_key(room_id_0));
838
839 let room_0 = rooms.get(room_id_0).unwrap().read().await;
841 assert_eq!(room_0.per_thread().len(), 1);
842 assert!(room_0.per_thread().contains_key(thread_id_0_0));
844 }
845
846 latest_events.forget_thread(room_id_0, thread_id_0_0).await;
848
849 {
850 let rooms = latest_events.state.registered_rooms.rooms.read().await;
851 assert_eq!(rooms.len(), 1);
853 assert!(rooms.contains_key(room_id_0));
855
856 assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
858 }
859 }
860
861 #[async_test]
862 async fn test_inputs_task_can_listen_to_room_event_cache() {
863 let room_id = owned_room_id!("!r0");
864
865 let server = MatrixMockServer::new().await;
866 let client = server.client_builder().build().await;
867 let weak_client = client.downgrade();
868 let weak_room = WeakRoom::new(weak_client, room_id.clone());
869
870 let event_cache = client.event_cache().unwrap();
871
872 let registered_rooms = RwLock::new(HashMap::new());
873 let (room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
874 broadcast::channel(1);
875 let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
876 broadcast::channel(1);
877 let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
878 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
879
880 {
882 room_event_cache_generic_update_sender
883 .send(RoomEventCacheGenericUpdate { room_id: room_id.clone() })
884 .unwrap();
885
886 assert!(
888 listen_to_updates(
889 ®istered_rooms,
890 &mut room_event_cache_generic_update_receiver,
891 &mut send_queue_generic_update_receiver,
892 &mut room_info_update_receiver,
893 &latest_event_queue_sender,
894 )
895 .await
896 .is_continue()
897 );
898
899 assert!(latest_event_queue_receiver.is_empty());
901 }
902
903 {
906 registered_rooms.write().await.insert(
907 room_id.clone(),
908 With::inner(RoomLatestEvents::new(weak_room, event_cache)),
909 );
910 room_event_cache_generic_update_sender
911 .send(RoomEventCacheGenericUpdate { room_id: room_id.clone() })
912 .unwrap();
913
914 assert!(
915 listen_to_updates(
916 ®istered_rooms,
917 &mut room_event_cache_generic_update_receiver,
918 &mut send_queue_generic_update_receiver,
919 &mut room_info_update_receiver,
920 &latest_event_queue_sender,
921 )
922 .await
923 .is_continue()
924 );
925
926 assert!(latest_event_queue_receiver.is_empty().not());
928 }
929 }
930
931 #[async_test]
932 async fn test_inputs_task_can_listen_to_send_queue() {
933 let room_id = owned_room_id!("!r0");
934
935 let server = MatrixMockServer::new().await;
936 let client = server.client_builder().build().await;
937 let weak_client = client.downgrade();
938 let weak_room = WeakRoom::new(weak_client, room_id.clone());
939
940 let event_cache = client.event_cache().unwrap();
941
942 let registered_rooms = RwLock::new(HashMap::new());
943
944 let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
945 broadcast::channel(1);
946 let (send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
947 broadcast::channel(1);
948 let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
949 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
950
951 {
953 send_queue_generic_update_sender
954 .send(SendQueueUpdate {
955 room_id: room_id.clone(),
956 update: RoomSendQueueUpdate::SentEvent {
957 transaction_id: OwnedTransactionId::from("txnid0"),
958 event_id: owned_event_id!("$ev0"),
959 },
960 })
961 .unwrap();
962
963 assert!(
965 listen_to_updates(
966 ®istered_rooms,
967 &mut room_event_cache_generic_update_receiver,
968 &mut send_queue_generic_update_receiver,
969 &mut room_info_update_receiver,
970 &latest_event_queue_sender,
971 )
972 .await
973 .is_continue()
974 );
975
976 assert!(latest_event_queue_receiver.is_empty());
978 }
979
980 {
983 registered_rooms.write().await.insert(
984 room_id.clone(),
985 With::inner(RoomLatestEvents::new(weak_room, event_cache)),
986 );
987 send_queue_generic_update_sender
988 .send(SendQueueUpdate {
989 room_id: room_id.clone(),
990 update: RoomSendQueueUpdate::SentEvent {
991 transaction_id: OwnedTransactionId::from("txnid1"),
992 event_id: owned_event_id!("$ev1"),
993 },
994 })
995 .unwrap();
996
997 assert!(
998 listen_to_updates(
999 ®istered_rooms,
1000 &mut room_event_cache_generic_update_receiver,
1001 &mut send_queue_generic_update_receiver,
1002 &mut room_info_update_receiver,
1003 &latest_event_queue_sender,
1004 )
1005 .await
1006 .is_continue()
1007 );
1008
1009 assert!(latest_event_queue_receiver.is_empty().not());
1011 }
1012 }
1013
1014 #[async_test]
1015 async fn test_inputs_task_can_listen_to_room_info() {
1016 let room_id = owned_room_id!("!r0");
1017
1018 let server = MatrixMockServer::new().await;
1019 let client = server.client_builder().build().await;
1020 let weak_client = client.downgrade();
1021 let weak_room = WeakRoom::new(weak_client, room_id.clone());
1022
1023 let event_cache = client.event_cache().unwrap();
1024
1025 let registered_rooms = RwLock::new(HashMap::new());
1026
1027 let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1028 broadcast::channel(1);
1029 let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1030 broadcast::channel(1);
1031 let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1032 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1033
1034 {
1036 room_info_update_sender
1037 .send(RoomInfoNotableUpdate {
1038 room_id: room_id.clone(),
1039 reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1040 })
1041 .unwrap();
1042
1043 assert!(
1045 listen_to_updates(
1046 ®istered_rooms,
1047 &mut room_event_cache_generic_update_receiver,
1048 &mut send_queue_generic_update_receiver,
1049 &mut room_info_update_receiver,
1050 &latest_event_queue_sender,
1051 )
1052 .await
1053 .is_continue()
1054 );
1055
1056 assert!(latest_event_queue_receiver.is_empty());
1058 }
1059
1060 {
1063 registered_rooms.write().await.insert(
1064 room_id.clone(),
1065 With::inner(RoomLatestEvents::new(weak_room, event_cache)),
1066 );
1067 room_info_update_sender
1068 .send(RoomInfoNotableUpdate {
1069 room_id: room_id.clone(),
1070 reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1071 })
1072 .unwrap();
1073
1074 assert!(
1075 listen_to_updates(
1076 ®istered_rooms,
1077 &mut room_event_cache_generic_update_receiver,
1078 &mut send_queue_generic_update_receiver,
1079 &mut room_info_update_receiver,
1080 &latest_event_queue_sender,
1081 )
1082 .await
1083 .is_continue()
1084 );
1085
1086 assert!(latest_event_queue_receiver.is_empty().not());
1088 }
1089 }
1090
1091 #[async_test]
1092 async fn test_inputs_task_can_listen_to_specific_room_info_update_reasons() {
1093 let room_id = owned_room_id!("!r0");
1094
1095 let server = MatrixMockServer::new().await;
1096 let client = server.client_builder().build().await;
1097 let weak_client = client.downgrade();
1098 let weak_room = WeakRoom::new(weak_client, room_id.clone());
1099
1100 let event_cache = client.event_cache().unwrap();
1101
1102 let registered_rooms = RwLock::new(HashMap::new());
1103
1104 let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1105 broadcast::channel(1);
1106 let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1107 broadcast::channel(1);
1108 let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1109 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1110
1111 registered_rooms
1112 .write()
1113 .await
1114 .insert(room_id.clone(), With::inner(RoomLatestEvents::new(weak_room, event_cache)));
1115
1116 for reason in {
1121 let mut all = RoomInfoNotableUpdateReasons::all();
1122 all.remove(RoomInfoNotableUpdateReasons::MEMBERSHIP);
1123
1124 all.iter()
1125 } {
1126 room_info_update_sender
1127 .send(RoomInfoNotableUpdate { room_id: room_id.clone(), reasons: reason })
1128 .unwrap();
1129
1130 assert!(
1131 listen_to_updates(
1132 ®istered_rooms,
1133 &mut room_event_cache_generic_update_receiver,
1134 &mut send_queue_generic_update_receiver,
1135 &mut room_info_update_receiver,
1136 &latest_event_queue_sender,
1137 )
1138 .await
1139 .is_continue()
1140 );
1141
1142 assert!(latest_event_queue_receiver.is_empty());
1144 }
1145
1146 {
1148 room_info_update_sender
1149 .send(RoomInfoNotableUpdate {
1150 room_id: room_id.clone(),
1151 reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1152 })
1153 .unwrap();
1154
1155 assert!(
1156 listen_to_updates(
1157 ®istered_rooms,
1158 &mut room_event_cache_generic_update_receiver,
1159 &mut send_queue_generic_update_receiver,
1160 &mut room_info_update_receiver,
1161 &latest_event_queue_sender,
1162 )
1163 .await
1164 .is_continue()
1165 );
1166
1167 assert!(latest_event_queue_receiver.is_empty().not());
1169 }
1170 }
1171
1172 #[async_test]
1173 async fn test_inputs_task_stops_when_event_cache_channel_is_closed() {
1174 let registered_rooms = RwLock::new(HashMap::new());
1175 let (room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1176 broadcast::channel(1);
1177 let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1178 broadcast::channel(1);
1179 let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1180 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1181
1182 drop(room_event_cache_generic_update_sender);
1184
1185 assert!(
1187 listen_to_updates(
1188 ®istered_rooms,
1189 &mut room_event_cache_generic_update_receiver,
1190 &mut send_queue_generic_update_receiver,
1191 &mut room_info_update_receiver,
1192 &latest_event_queue_sender,
1193 )
1194 .await
1195 .is_break()
1197 );
1198
1199 assert!(latest_event_queue_receiver.is_empty());
1200 }
1201
1202 #[async_test]
1203 async fn test_inputs_task_stops_when_send_queue_channel_is_closed() {
1204 let registered_rooms = RwLock::new(HashMap::new());
1205 let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1206 broadcast::channel(1);
1207 let (send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1208 broadcast::channel(1);
1209 let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1210 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1211
1212 drop(send_queue_generic_update_sender);
1214
1215 assert!(
1217 listen_to_updates(
1218 ®istered_rooms,
1219 &mut room_event_cache_generic_update_receiver,
1220 &mut send_queue_generic_update_receiver,
1221 &mut room_info_update_receiver,
1222 &latest_event_queue_sender,
1223 )
1224 .await
1225 .is_break()
1227 );
1228
1229 assert!(latest_event_queue_receiver.is_empty());
1230 }
1231
1232 #[async_test]
1233 async fn test_inputs_task_stops_when_room_info_updates_are_closed() {
1234 let registered_rooms = RwLock::new(HashMap::new());
1235 let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1236 broadcast::channel(1);
1237 let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1238 broadcast::channel(1);
1239 let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1240 let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1241
1242 drop(room_info_update_sender);
1244
1245 assert!(
1247 listen_to_updates(
1248 ®istered_rooms,
1249 &mut room_event_cache_generic_update_receiver,
1250 &mut send_queue_generic_update_receiver,
1251 &mut room_info_update_receiver,
1252 &latest_event_queue_sender,
1253 )
1254 .await
1255 .is_break()
1257 );
1258
1259 assert!(latest_event_queue_receiver.is_empty());
1260 }
1261
1262 #[async_test]
1263 async fn test_latest_event_value_is_updated_via_event_cache() {
1264 let room_id = owned_room_id!("!r0");
1265 let user_id = user_id!("@mnt_io:matrix.org");
1266 let event_factory = EventFactory::new().sender(user_id).room(&room_id);
1267 let event_id_0 = event_id!("$ev0");
1268
1269 let server = MatrixMockServer::new().await;
1270 let client = server.client_builder().build().await;
1271
1272 client.base_client().get_or_create_room(&room_id, RoomState::Joined);
1274
1275 let latest_events = client.latest_events().await.unwrap();
1276
1277 let mut latest_event_stream =
1279 latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1280
1281 assert_pending!(latest_event_stream);
1283
1284 server
1286 .sync_room(
1287 &client,
1288 JoinedRoomBuilder::new(&room_id)
1289 .add_timeline_event(event_factory.text_msg("raclette !").event_id(event_id_0)),
1290 )
1291 .await;
1292
1293 assert_matches!(
1298 latest_event_stream.next().await,
1299 Some(LatestEventValue::Remote(RemoteLatestEventValue { kind: TimelineEventKind::PlainText { event }, .. })) => {
1300 assert_matches!(
1301 event.deserialize().unwrap(),
1302 AnySyncTimelineEvent::MessageLike(
1303 AnySyncMessageLikeEvent::RoomMessage(
1304 SyncMessageLikeEvent::Original(message_content)
1305 )
1306 ) => {
1307 assert_eq!(message_content.content.body(), "raclette !");
1308 }
1309 );
1310 }
1311 );
1312
1313 assert_pending!(latest_event_stream);
1314 }
1315
1316 #[async_test]
1317 async fn test_latest_event_value_is_initialized_by_the_event_cache_lazily() {
1318 let room_id = owned_room_id!("!r0");
1319 let user_id = user_id!("@mnt_io:matrix.org");
1320 let event_factory = EventFactory::new().sender(user_id).room(&room_id);
1321 let event_id_0 = event_id!("$ev0");
1322
1323 let event_cache_store = MemoryStore::new();
1325 event_cache_store
1326 .handle_linked_chunk_updates(
1327 LinkedChunkId::Room(&room_id),
1328 vec![
1329 Update::NewItemsChunk {
1330 previous: None,
1331 new: ChunkIdentifier::new(0),
1332 next: None,
1333 },
1334 Update::PushItems {
1335 at: Position::new(ChunkIdentifier::new(0), 0),
1336 items: vec![event_factory.text_msg("hello").event_id(event_id_0).into()],
1337 },
1338 ],
1339 )
1340 .await
1341 .unwrap();
1342
1343 let client = MockClientBuilder::new(None)
1344 .on_builder(move |builder| {
1345 builder.store_config(
1346 StoreConfig::new(CrossProcessLockConfig::MultiProcess {
1347 holder_name: "foo".to_owned(),
1348 })
1349 .event_cache_store(event_cache_store),
1350 )
1351 })
1352 .build()
1353 .await;
1354
1355 client.base_client().get_or_create_room(&room_id, RoomState::Joined);
1357
1358 let latest_events = client.latest_events().await.unwrap();
1359
1360 let mut latest_event_stream =
1361 latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1362
1363 yield_now().await;
1369 assert_matches!(latest_event_stream.next_now().await, LatestEventValue::Remote(_));
1370
1371 assert_pending!(latest_event_stream);
1372 }
1373
1374 #[async_test]
1382 async fn test_latest_event_value_is_initialized_by_the_event_cache_lazily_inner() {
1383 let room_id_0 = owned_room_id!("!r0");
1384 let room_id_1 = owned_room_id!("!r1");
1385
1386 let server = MatrixMockServer::new().await;
1387 let client = server.client_builder().build().await;
1388
1389 let room_0 = client.base_client().get_or_create_room(&room_id_0, RoomState::Joined);
1391 let room_1 = client.base_client().get_or_create_room(&room_id_1, RoomState::Joined);
1392
1393 let mut room_info_1 = room_0.clone_info();
1396 room_info_1.set_latest_event(LatestEventValue::LocalIsSending(local_room_message("foo")));
1397 room_1.update_room_info(|_| (room_info_1, Default::default())).await;
1398
1399 let weak_client = client.downgrade();
1400
1401 let event_cache = client.event_cache().unwrap();
1402
1403 let (latest_event_queue_sender, mut latest_event_queue_receiver) =
1404 mpsc::unbounded_channel();
1405
1406 let registered_rooms =
1407 RegisteredRooms::new(weak_client, event_cache, &latest_event_queue_sender);
1408
1409 {
1412 let room_latest_events = registered_rooms.for_room(&room_id_0).await.unwrap().unwrap();
1413 assert_matches!(
1414 room_latest_events.read().await.for_room().get().await,
1415 LatestEventValue::None
1416 );
1417 assert_matches!(
1418 latest_event_queue_receiver.recv().await,
1419 Some(LatestEventQueueUpdate::EventCache { room_id }) => {
1420 assert_eq!(room_id, room_id_0);
1421 }
1422 );
1423 assert!(latest_event_queue_receiver.is_empty());
1424 }
1425
1426 {
1429 let room_latest_events = registered_rooms.for_room(&room_id_1).await.unwrap().unwrap();
1430 assert_matches!(
1431 room_latest_events.read().await.for_room().get().await,
1432 LatestEventValue::LocalIsSending(_)
1433 );
1434 assert!(latest_event_queue_receiver.is_empty());
1435 }
1436 }
1437
1438 #[async_test]
1439 async fn test_latest_event_value_is_updated_via_room_infos_for_invites() {
1440 let room_id = owned_room_id!("!r0");
1441 let event_factory = EventFactory::new().room(&room_id);
1442 let event_id_0 = event_id!("$ev0");
1443 let event_id_1 = event_id!("$ev1");
1444
1445 let server = MatrixMockServer::new().await;
1446 let client = server.client_builder().build().await;
1447 let own_user_id = client.user_id().unwrap();
1448 let other_user_id = user_id!("@other:servername");
1449
1450 let latest_events = client.latest_events().await.unwrap();
1451
1452 let mut latest_event_stream =
1454 latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1455
1456 assert_pending!(latest_event_stream);
1458
1459 let now = MilliSecondsSinceUnixEpoch::now().get();
1460
1461 {
1463 server
1464 .sync_room(
1465 &client,
1466 InvitedRoomBuilder::new(&room_id).add_state_event(
1467 event_factory
1468 .member(other_user_id)
1469 .invited(own_user_id)
1470 .event_id(event_id_0),
1471 ),
1472 )
1473 .await;
1474
1475 assert_matches!(
1480 latest_event_stream.next().await,
1481 Some(LatestEventValue::RemoteInvite { event_id, timestamp, inviter }) => {
1482 assert!(event_id.is_none());
1484 assert!(timestamp.get() >= now);
1486 assert_eq!(inviter.as_deref(), Some(other_user_id));
1487 }
1488 );
1489
1490 assert_pending!(latest_event_stream);
1491 };
1492
1493 {
1495 server
1496 .sync_room(
1497 &client,
1498 InvitedRoomBuilder::new(&room_id).add_state_event(
1499 event_factory
1500 .member(other_user_id)
1501 .invited(own_user_id)
1502 .event_id(event_id_0),
1503 ),
1504 )
1505 .await;
1506
1507 assert!(timeout(Duration::from_secs(1), latest_event_stream.next()).await.is_err());
1513
1514 assert_pending!(latest_event_stream);
1515 }
1516
1517 {
1519 let now = u64::from(now) + 10; server
1521 .sync_room(
1522 &client,
1523 JoinedRoomBuilder::new(&room_id).add_timeline_event(
1524 event_factory
1525 .member(own_user_id)
1526 .membership(MembershipState::Join)
1527 .event_id(event_id_1)
1528 .server_ts(now),
1529 ),
1530 )
1531 .await;
1532
1533 assert_matches!(
1538 latest_event_stream.next().await,
1539 Some(LatestEventValue::Remote(RemoteLatestEventValue { kind: TimelineEventKind::PlainText { event }, .. })) => {
1540 assert_matches!(
1541 event.deserialize().unwrap(),
1542 AnySyncTimelineEvent::State(
1543 AnySyncStateEvent::RoomMember(
1544 SyncRoomMemberEvent::Original(event)
1545 )
1546 ) => {
1547 assert_eq!(event.event_id, event_id_1);
1548 assert_eq!(event.content.membership, MembershipState::Join);
1549 assert_eq!(event.sender, own_user_id);
1550 assert_eq!(event.state_key, own_user_id);
1551 assert_eq!(u64::from(event.origin_server_ts.get()), now);
1552 }
1553 );
1554 }
1555 );
1556
1557 assert_pending!(latest_event_stream);
1558 }
1559 }
1560
1561 #[async_test]
1564 async fn test_client_can_drop_latest_events_tasks() {
1565 let room_id = room_id!("!r0");
1566
1567 let server = MatrixMockServer::new().await;
1568 let client = server.client_builder().build().await;
1569
1570 let room = server.sync_joined_room(&client, room_id).await;
1572 assert!(client.latest_events().await.unwrap().is_listening_to_room(room_id).await);
1573
1574 drop(room);
1576
1577 yield_now().await;
1579
1580 let weak_client = client.downgrade();
1582
1583 drop(client);
1585
1586 sleep(Duration::from_secs(2)).await;
1588
1589 assert_eq!(weak_client.strong_count(), 0);
1591 }
1592}