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