Skip to main content

matrix_sdk/latest_events/
mod.rs

1// Copyright 2025 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! The Latest Events API provides a lazy, reactive and efficient way to compute
16//! the latest event for a room or a thread.
17//!
18//! The latest event represents the last displayable and relevant event a room
19//! or a thread has received. It is usually displayed in a _summary_, e.g.
20//! below the room title in a room list.
21//!
22//! The entry point is [`LatestEvents`]. It is preferable to get a reference to
23//! it from [`Client::latest_events`][crate::Client::latest_events], which
24//! already plugs everything to build it. [`LatestEvents`] is using the
25//! [`EventCache`] and the [`SendQueue`] to respectively get known remote events
26//! (i.e. synced from the server), or local events (i.e. ones being sent).
27//!
28//! ## Laziness
29//!
30//! [`LatestEvents`] is lazy, it means that, despite [`LatestEvents`] is
31//! listening to all [`EventCache`] or [`SendQueue`] updates, it will only do
32//! something if one is expected to get the latest event for a particular room
33//! or a particular thread. Concretely, it means that until
34//! [`LatestEvents::listen_to_room`] is called for a particular room, no latest
35//! event will ever be computed for that room (and similarly with
36//! [`LatestEvents::listen_to_thread`]).
37//!
38//! If one is no longer interested to get the latest event for a particular room
39//! or thread, the [`LatestEvents::forget_room`] and
40//! [`LatestEvents::forget_thread`] methods must be used.
41//!
42//! ## Reactive
43//!
44//! [`LatestEvents`] is designed to be reactive. Using
45//! [`LatestEvents::listen_and_subscribe_to_room`] will provide a
46//! [`Subscriber`], which brings all the tooling to get the current value or the
47//! future values with a stream.
48
49mod 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/// The entry point to fetch the [`LatestEventValue`] for rooms or threads.
82#[derive(Clone, Debug)]
83pub struct LatestEvents {
84    state: Arc<LatestEventsState>,
85}
86
87/// The state of [`LatestEvents`].
88#[derive(Debug)]
89struct LatestEventsState {
90    /// All the registered rooms, i.e. rooms the latest events are computed for.
91    registered_rooms: Arc<RegisteredRooms>,
92
93    /// The task handle of the [`listen_to_updates_task`].
94    _listen_task_handle: AbortOnDrop<()>,
95
96    /// The task handle of the [`compute_latest_events_task`].
97    _computation_task_handle: AbortOnDrop<()>,
98}
99
100impl LatestEvents {
101    /// Create a new [`LatestEvents`].
102    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        // The task listening to the event cache, the send queue, and the room
114        // infos updates.
115        let listen_task_handle = spawn(listen_to_updates_task(
116            registered_rooms.clone(),
117            event_cache,
118            send_queue,
119            room_info_updates,
120            latest_event_queue_sender,
121        ))
122        .abort_on_drop();
123
124        // The task computing the new latest events.
125        let computation_task_handle = spawn(compute_latest_events_task(
126            registered_rooms.clone(),
127            latest_event_queue_receiver,
128        ))
129        .abort_on_drop();
130
131        Self {
132            state: Arc::new(LatestEventsState {
133                registered_rooms,
134                _listen_task_handle: listen_task_handle,
135                _computation_task_handle: computation_task_handle,
136            }),
137        }
138    }
139
140    /// Start listening to updates (if not already) for a particular room.
141    ///
142    /// It returns `true` if the room exists, `false` otherwise.
143    pub async fn listen_to_room(&self, room_id: &RoomId) -> Result<bool, LatestEventsError> {
144        Ok(self.state.registered_rooms.for_room(room_id).await?.is_some())
145    }
146
147    /// Check whether the system listens to a particular room.
148    ///
149    /// Note: It's a test only method.
150    #[cfg(test)]
151    pub async fn is_listening_to_room(&self, room_id: &RoomId) -> bool {
152        self.state.registered_rooms.rooms.read().await.contains_key(room_id)
153    }
154
155    /// Start listening to updates (if not already) for a particular room, and
156    /// return a [`Subscriber`] to get the current and future
157    /// [`LatestEventValue`]s.
158    ///
159    /// It returns `Some` if the room exists, `None` otherwise.
160    pub async fn listen_and_subscribe_to_room(
161        &self,
162        room_id: &RoomId,
163    ) -> Result<Option<Subscriber<LatestEventValue, AsyncLock>>, LatestEventsError> {
164        let Some(room_latest_events) = self.state.registered_rooms.for_room(room_id).await? else {
165            return Ok(None);
166        };
167
168        let room_latest_events = room_latest_events.read().await;
169        let latest_event = room_latest_events.for_room();
170
171        Ok(Some(latest_event.subscribe().await))
172    }
173
174    /// Start listening to updates (if not already) for a particular room and a
175    /// particular thread in this room.
176    ///
177    /// It returns `true` if the room and the thread exists, `false` otherwise.
178    pub async fn listen_to_thread(
179        &self,
180        room_id: &RoomId,
181        thread_id: &EventId,
182    ) -> Result<bool, LatestEventsError> {
183        Ok(self.state.registered_rooms.for_thread(room_id, thread_id).await?.is_some())
184    }
185
186    /// Start listening to updates (if not already) for a particular room and a
187    /// particular thread in this room, and return a [`Subscriber`] to get the
188    /// current and future [`LatestEventValue`]s.
189    ///
190    /// It returns `Some` if the room and the thread exists, `None` otherwise.
191    pub async fn listen_and_subscribe_to_thread(
192        &self,
193        room_id: &RoomId,
194        thread_id: &EventId,
195    ) -> Result<Option<Subscriber<LatestEventValue, AsyncLock>>, LatestEventsError> {
196        let Some(room_latest_events) =
197            self.state.registered_rooms.for_thread(room_id, thread_id).await?
198        else {
199            return Ok(None);
200        };
201
202        let room_latest_events = room_latest_events.read().await;
203        let latest_event = room_latest_events
204            .for_thread(thread_id)
205            .expect("The `LatestEvent` for the thread must have been created");
206
207        Ok(Some(latest_event.subscribe().await))
208    }
209
210    /// Forget a room.
211    ///
212    /// It means that [`LatestEvents`] will stop listening to updates for the
213    /// `LatestEvent`s of the room and all its threads.
214    ///
215    /// If [`LatestEvents`] is not listening for `room_id`, nothing happens.
216    pub async fn forget_room(&self, room_id: &RoomId) {
217        self.state.registered_rooms.forget_room(room_id).await;
218    }
219
220    /// Forget a thread.
221    ///
222    /// It means that [`LatestEvents`] will stop listening to updates for the
223    /// `LatestEvent` of the thread.
224    ///
225    /// If [`LatestEvents`] is not listening for `room_id` or `thread_id`,
226    /// nothing happens.
227    pub async fn forget_thread(&self, room_id: &RoomId, thread_id: &EventId) {
228        self.state.registered_rooms.forget_thread(room_id, thread_id).await;
229    }
230}
231
232#[derive(Debug)]
233struct RegisteredRooms {
234    /// All the registered [`RoomLatestEvents`].
235    rooms: RwLock<HashMap<OwnedRoomId, RoomLatestEvents>>,
236
237    /// The (weak) client.
238    weak_client: WeakClient,
239
240    /// The event cache.
241    event_cache: EventCache,
242
243    /// The sender part of the channel used by [`compute_latest_events_task`].
244    ///
245    /// This is used to _trigger_ a computation of a `LatestEventValue` if the
246    /// restored value is `None`.
247    latest_event_queue_sender: mpsc::UnboundedSender<LatestEventQueueUpdate>,
248}
249
250impl RegisteredRooms {
251    fn new(
252        weak_client: WeakClient,
253        event_cache: &EventCache,
254        latest_event_queue_sender: &mpsc::UnboundedSender<LatestEventQueueUpdate>,
255    ) -> Self {
256        Self {
257            rooms: RwLock::new(HashMap::default()),
258            weak_client,
259            event_cache: event_cache.clone(),
260            latest_event_queue_sender: latest_event_queue_sender.clone(),
261        }
262    }
263
264    /// Get a read lock guard to a [`RoomLatestEvents`] given a room ID and an
265    /// optional thread ID.
266    ///
267    /// The [`RoomLatestEvents`], and the associated [`LatestEvent`], will be
268    /// created if missing. It means that write lock is taken if necessary, but
269    /// it's always downgraded to a read lock at the end.
270    async fn room_latest_event(
271        &self,
272        room_id: &RoomId,
273        thread_id: Option<&EventId>,
274    ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
275        fn create_and_insert_room_latest_events(
276            room_id: &RoomId,
277            rooms: &mut HashMap<OwnedRoomId, RoomLatestEvents>,
278            weak_client: &WeakClient,
279            event_cache: &EventCache,
280            latest_event_queue_sender: &mpsc::UnboundedSender<LatestEventQueueUpdate>,
281        ) {
282            let (room_latest_events, is_latest_event_value_none) =
283                With::unzip(RoomLatestEvents::new(
284                    WeakRoom::new(weak_client.clone(), room_id.to_owned()),
285                    event_cache,
286                ));
287
288            // Insert the new `RoomLatestEvents`.
289            rooms.insert(room_id.to_owned(), room_latest_events);
290
291            // If the `LatestEventValue` restored by `RoomLatestEvents` is of
292            // kind `None`, let's try to re-compute it without waiting on the
293            // Event Cache (so the sync usually) or the Send Queue. Maybe the
294            // system has migrated to a new version and the `LatestEventValue`
295            // has been erased, while it is still possible to compute a correct
296            // value.
297            if is_latest_event_value_none {
298                let _ = latest_event_queue_sender
299                    .send(LatestEventQueueUpdate::EventCache { room_id: room_id.to_owned() });
300            }
301        }
302
303        Ok(match thread_id {
304            // Get the room latest event with the aim of fetching the latest
305            // event for a particular thread.
306            //
307            // We need to take a write lock immediately, in case the thead
308            // latest event doesn't exist.
309            Some(thread_id) => {
310                let mut rooms = self.rooms.write().await;
311
312                // The `RoomLatestEvents` doesn't exist. Let's create and insert
313                // it.
314                if rooms.contains_key(room_id).not() {
315                    create_and_insert_room_latest_events(
316                        room_id,
317                        rooms.deref_mut(),
318                        &self.weak_client,
319                        &self.event_cache,
320                        &self.latest_event_queue_sender,
321                    );
322                }
323
324                if let Some(room_latest_event) = rooms.get(room_id) {
325                    let mut room_latest_event = room_latest_event.write().await;
326
327                    // In `RoomLatestEvents`, the `LatestEvent` for this thread
328                    // doesn't exist. Let's create and insert it.
329                    if room_latest_event.has_thread(thread_id).not() {
330                        room_latest_event.create_and_insert_latest_event_for_thread(thread_id);
331                    }
332                }
333
334                RwLockWriteGuard::try_downgrade_map(rooms, |rooms| rooms.get(room_id)).ok()
335            }
336
337            // Get the room latest event with the aim of fetching the latest
338            // event for a particular room.
339            None => {
340                match RwLockReadGuard::try_map(self.rooms.read().await, |rooms| rooms.get(room_id))
341                    .ok()
342                {
343                    value @ Some(_) => value,
344                    None => {
345                        let _timer = timer!(
346                            tracing::Level::DEBUG,
347                            format!("Creating `RoomLatestEvents` for {room_id:?}"),
348                        );
349
350                        let mut rooms = self.rooms.write().await;
351
352                        if rooms.contains_key(room_id).not() {
353                            create_and_insert_room_latest_events(
354                                room_id,
355                                rooms.deref_mut(),
356                                &self.weak_client,
357                                &self.event_cache,
358                                &self.latest_event_queue_sender,
359                            );
360                        }
361
362                        RwLockWriteGuard::try_downgrade_map(rooms, |rooms| rooms.get(room_id)).ok()
363                    }
364                }
365            }
366        })
367    }
368
369    /// Start listening to updates (if not already) for a particular room.
370    ///
371    /// It returns `None` if the room doesn't exist.
372    pub async fn for_room(
373        &self,
374        room_id: &RoomId,
375    ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
376        self.room_latest_event(room_id, None).await
377    }
378
379    /// Start listening to updates (if not already) for a particular room.
380    ///
381    /// It returns `None` if the room or the thread doesn't exist.
382    pub async fn for_thread(
383        &self,
384        room_id: &RoomId,
385        thread_id: &EventId,
386    ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
387        self.room_latest_event(room_id, Some(thread_id)).await
388    }
389
390    /// Forget a room.
391    ///
392    /// It means that [`LatestEvents`] will stop listening to updates for the
393    /// `LatestEvent`s of the room and all its threads.
394    ///
395    /// If [`LatestEvents`] is not listening for `room_id`, nothing happens.
396    pub async fn forget_room(&self, room_id: &RoomId) {
397        {
398            let mut rooms = self.rooms.write().await;
399
400            // Remove the whole `RoomLatestEvents`.
401            rooms.remove(room_id);
402        }
403    }
404
405    /// Forget a thread.
406    ///
407    /// It means that [`LatestEvents`] will stop listening to updates for the
408    /// `LatestEvent` of the thread.
409    ///
410    /// If [`LatestEvents`] is not listening for `room_id` or `thread_id`,
411    /// nothing happens.
412    pub async fn forget_thread(&self, room_id: &RoomId, thread_id: &EventId) {
413        let rooms = self.rooms.read().await;
414
415        // If the `RoomLatestEvents`, remove the `LatestEvent` in `per_thread`.
416        if let Some(room_latest_event) = rooms.get(room_id) {
417            let mut room_latest_event = room_latest_event.write().await;
418
419            // Release the lock on `self.rooms`.
420            drop(rooms);
421
422            room_latest_event.forget_thread(thread_id);
423        }
424    }
425}
426
427/// Represents the kind of updates the [`compute_latest_events_task`] will have
428/// to deal with.
429#[derive(Debug)]
430enum LatestEventQueueUpdate {
431    /// An update from the [`EventCache`] happened.
432    EventCache {
433        /// The ID of the room that has triggered the update.
434        room_id: OwnedRoomId,
435    },
436
437    /// An update from the [`SendQueue`] happened.
438    SendQueue {
439        /// The ID of the room that has triggered the update.
440        room_id: OwnedRoomId,
441
442        /// The update itself.
443        update: RoomSendQueueUpdate,
444    },
445
446    /// An update from the [`RoomInfo`] happened.
447    ///
448    /// [`RoomInfo`]: crate::RoomInfo
449    RoomInfo {
450        /// The ID of the room that has triggered the update.
451        room_id: OwnedRoomId,
452
453        /// The notable update reasons.
454        reasons: RoomInfoNotableUpdateReasons,
455    },
456}
457
458/// The task responsible to listen to the [`EventCache`], the [`SendQueue`] and
459/// the [`RoomInfoNotableUpdate`].
460///
461/// When an update is received and is considered relevant, a message is sent to
462/// the [`compute_latest_events_task`] to compute a new [`LatestEvent`].
463///
464/// When an update is considered relevant, a message is sent over the
465/// `latest_event_queue_sender` channel. See [`compute_latest_events_task`].
466async fn listen_to_updates_task(
467    registered_rooms: Arc<RegisteredRooms>,
468    event_cache: EventCache,
469    send_queue: SendQueue,
470    room_info_updates: broadcast::Receiver<RoomInfoNotableUpdate>,
471    latest_event_queue_sender: mpsc::UnboundedSender<LatestEventQueueUpdate>,
472) {
473    let mut event_cache_generic_updates_subscriber =
474        event_cache.subscribe_to_room_generic_updates();
475    let mut send_queue_generic_updates_subscriber = send_queue.subscribe();
476    let mut room_info_updates_subscriber = room_info_updates.resubscribe();
477
478    loop {
479        if listen_to_updates(
480            &registered_rooms.rooms,
481            &mut event_cache_generic_updates_subscriber,
482            &mut send_queue_generic_updates_subscriber,
483            &mut room_info_updates_subscriber,
484            &latest_event_queue_sender,
485        )
486        .await
487        .is_break()
488        {
489            warn!("`listen_to_updates_task` has stopped");
490
491            break;
492        }
493    }
494}
495
496/// The core of [`listen_to_updates_task`].
497///
498/// Having this function detached from its task is helpful for testing and for
499/// state isolation.
500async fn listen_to_updates(
501    registered_rooms: &RwLock<HashMap<OwnedRoomId, RoomLatestEvents>>,
502    event_cache_generic_updates_subscriber: &mut broadcast::Receiver<RoomEventCacheGenericUpdate>,
503    send_queue_generic_updates_subscriber: &mut broadcast::Receiver<SendQueueUpdate>,
504    room_info_updates_subscriber: &mut broadcast::Receiver<RoomInfoNotableUpdate>,
505    latest_event_queue_sender: &mpsc::UnboundedSender<LatestEventQueueUpdate>,
506) -> ControlFlow<()> {
507    select! {
508        room_event_cache_generic_update = event_cache_generic_updates_subscriber.recv() => {
509            if let Ok(RoomEventCacheGenericUpdate { room_id }) = room_event_cache_generic_update {
510                if registered_rooms.read().await.contains_key(&room_id) {
511                    let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::EventCache {
512                        room_id
513                    });
514                }
515            } else {
516                warn!("`event_cache_generic_updates` channel has been closed");
517
518                return ControlFlow::Break(());
519            }
520        }
521
522        send_queue_generic_update = send_queue_generic_updates_subscriber.recv() => {
523            if let Ok(SendQueueUpdate { room_id, update }) = send_queue_generic_update {
524                if registered_rooms.read().await.contains_key(&room_id) {
525                    let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::SendQueue {
526                        room_id,
527                        update
528                    });
529                }
530            } else {
531                warn!("`send_queue_generic_updates` channel has been closed");
532
533                return ControlFlow::Break(());
534            }
535        }
536
537        room_info_update = room_info_updates_subscriber.recv() => {
538            if let Ok(RoomInfoNotableUpdate { room_id, reasons }) = room_info_update {
539                // Filter the update reasons we are interested by.
540                if
541                    // Be careful: the `LATEST_EVENT` reason alone must always
542                    // be ignored! Otherwise it can create a loop.
543                    reasons == RoomInfoNotableUpdateReasons::LATEST_EVENT ||
544
545                    // We are interested by `MEMBERSHIP` so that it captures
546                    // when the user is invited, is joining, is knocking, or is
547                    // leaving a room.
548                    !reasons.contains(RoomInfoNotableUpdateReasons::MEMBERSHIP)
549                {
550                    return ControlFlow::Continue(())
551                }
552
553                if registered_rooms.read().await.contains_key(&room_id) {
554                    let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::RoomInfo {
555                        room_id,
556                        reasons,
557                    });
558                }
559            } else {
560                warn!("`room_info_updates` channel has been closed");
561
562                return ControlFlow::Break(());
563            }
564        }
565    }
566
567    ControlFlow::Continue(())
568}
569
570/// The task responsible to compute new [`LatestEvent`] for a particular room or
571/// thread.
572///
573/// The messages are coming from [`listen_to_updates_task`].
574async fn compute_latest_events_task(
575    registered_rooms: Arc<RegisteredRooms>,
576    mut latest_event_queue_receiver: mpsc::UnboundedReceiver<LatestEventQueueUpdate>,
577) {
578    const BUFFER_SIZE: usize = 16;
579
580    let mut buffer = Vec::with_capacity(BUFFER_SIZE);
581
582    while latest_event_queue_receiver.recv_many(&mut buffer, BUFFER_SIZE).await > 0 {
583        compute_latest_events(&registered_rooms, &buffer).await;
584        buffer.clear();
585    }
586
587    warn!("`compute_latest_events_task` has stopped");
588}
589
590async fn compute_latest_events(
591    registered_rooms: &RegisteredRooms,
592    latest_event_queue_updates: &[LatestEventQueueUpdate],
593) {
594    async fn room_latest_events_write_guard(
595        registered_rooms: &RegisteredRooms,
596        room_id: &OwnedRoomId,
597    ) -> ControlFlow<RoomLatestEventsWriteGuard, ()> {
598        let rooms = registered_rooms.rooms.read().await;
599
600        if let Some(room_latest_events) = rooms.get(room_id) {
601            let room_latest_events = room_latest_events.write().await;
602
603            // Release the lock on `registered_rooms`. It is possible because
604            // `room_latest_events` is an owned lock guard.
605            drop(rooms);
606
607            ControlFlow::Break(room_latest_events)
608        } else {
609            info!(?room_id, "Failed to find the room");
610
611            ControlFlow::Continue(())
612        }
613    }
614
615    for latest_event_queue_update in latest_event_queue_updates {
616        match latest_event_queue_update {
617            LatestEventQueueUpdate::EventCache { room_id } => {
618                let ControlFlow::Break(mut room_latest_events) =
619                    room_latest_events_write_guard(registered_rooms, room_id).await
620                else {
621                    continue;
622                };
623
624                room_latest_events.update_with_event_cache().await;
625            }
626
627            LatestEventQueueUpdate::SendQueue { room_id, update } => {
628                let ControlFlow::Break(mut room_latest_events) =
629                    room_latest_events_write_guard(registered_rooms, room_id).await
630                else {
631                    continue;
632                };
633
634                room_latest_events.update_with_send_queue(update).await;
635            }
636
637            LatestEventQueueUpdate::RoomInfo { room_id, reasons } => {
638                let ControlFlow::Break(mut room_latest_events) =
639                    room_latest_events_write_guard(registered_rooms, room_id).await
640                else {
641                    continue;
642                };
643
644                room_latest_events.update_with_room_info(*reasons).await;
645            }
646        }
647    }
648}
649
650#[cfg(test)]
651fn local_room_message(body: &str) -> LocalLatestEventValue {
652    use matrix_sdk_base::store::SerializableEventContent;
653    use ruma::{
654        MilliSecondsSinceUnixEpoch,
655        events::{AnyMessageLikeEventContent, room::message::RoomMessageEventContent},
656    };
657
658    LocalLatestEventValue {
659        timestamp: MilliSecondsSinceUnixEpoch::now(),
660        content: SerializableEventContent::new(&AnyMessageLikeEventContent::RoomMessage(
661            RoomMessageEventContent::text_plain(body),
662        ))
663        .unwrap(),
664    }
665}
666
667#[cfg(all(test, not(target_family = "wasm")))]
668mod tests {
669    use std::{collections::HashMap, ops::Not, time::Duration};
670
671    use assert_matches::assert_matches;
672    use matrix_sdk_base::{
673        RoomState,
674        deserialized_responses::TimelineEventKind,
675        linked_chunk::{ChunkIdentifier, LinkedChunkId, Position, Update},
676    };
677    use matrix_sdk_test::{
678        InvitedRoomBuilder, JoinedRoomBuilder, async_test, event_factory::EventFactory,
679    };
680    use ruma::{
681        MilliSecondsSinceUnixEpoch, OwnedTransactionId, event_id,
682        events::{
683            AnySyncMessageLikeEvent, AnySyncStateEvent, AnySyncTimelineEvent, SyncMessageLikeEvent,
684            room::member::{MembershipState, SyncRoomMemberEvent},
685        },
686        owned_event_id, owned_room_id, room_id, user_id,
687    };
688    use stream_assert::assert_pending;
689    use tokio::{task::yield_now, time::timeout};
690
691    use super::{
692        LatestEventValue, RegisteredRooms, RemoteLatestEventValue, RoomEventCacheGenericUpdate,
693        RoomInfoNotableUpdate, RoomInfoNotableUpdateReasons, RoomLatestEvents, RoomSendQueueUpdate,
694        RwLock, SendQueueUpdate, WeakClient, WeakRoom, With, broadcast, listen_to_updates, mpsc,
695    };
696    use crate::{
697        latest_events::{LatestEventQueueUpdate, local_room_message},
698        test_utils::mocks::MatrixMockServer,
699    };
700
701    #[async_test]
702    async fn test_latest_events_are_lazy() {
703        let room_id_0 = room_id!("!r0");
704        let room_id_1 = room_id!("!r1");
705        let room_id_2 = room_id!("!r2");
706        let thread_id_1_0 = event_id!("$ev1.0");
707        let thread_id_2_0 = event_id!("$ev2.0");
708
709        let server = MatrixMockServer::new().await;
710        let client = server.client_builder().build().await;
711
712        client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
713        client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
714        client.base_client().get_or_create_room(room_id_2, RoomState::Joined);
715
716        client.event_cache().subscribe().unwrap();
717
718        let latest_events = client.latest_events().await;
719
720        // Despites there are many rooms, zero `RoomLatestEvents` are created.
721        assert!(latest_events.state.registered_rooms.rooms.read().await.is_empty());
722
723        // Now let's listen to two rooms.
724        assert!(latest_events.listen_to_room(room_id_0).await.unwrap());
725        assert!(latest_events.listen_to_room(room_id_1).await.unwrap());
726
727        {
728            let rooms = latest_events.state.registered_rooms.rooms.read().await;
729            // There are two rooms…
730            assert_eq!(rooms.len(), 2);
731            // … which are room 0 and room 1.
732            assert!(rooms.contains_key(room_id_0));
733            assert!(rooms.contains_key(room_id_1));
734
735            // Room 0 contains zero thread latest events.
736            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
737            // Room 1 contains zero thread latest events.
738            assert!(rooms.get(room_id_1).unwrap().read().await.per_thread().is_empty());
739        }
740
741        // Now let's listen to one thread respectively for two rooms.
742        assert!(latest_events.listen_to_thread(room_id_1, thread_id_1_0).await.unwrap());
743        assert!(latest_events.listen_to_thread(room_id_2, thread_id_2_0).await.unwrap());
744
745        {
746            let rooms = latest_events.state.registered_rooms.rooms.read().await;
747            // There are now three rooms…
748            assert_eq!(rooms.len(), 3);
749            // … yup, room 2 is now created.
750            assert!(rooms.contains_key(room_id_0));
751            assert!(rooms.contains_key(room_id_1));
752            assert!(rooms.contains_key(room_id_2));
753
754            // Room 0 contains zero thread latest events.
755            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
756            // Room 1 contains one thread latest event…
757            let room_1 = rooms.get(room_id_1).unwrap().read().await;
758            assert_eq!(room_1.per_thread().len(), 1);
759            // … which is thread 1.0.
760            assert!(room_1.per_thread().contains_key(thread_id_1_0));
761            // Room 2 contains one thread latest event…
762            let room_2 = rooms.get(room_id_2).unwrap().read().await;
763            assert_eq!(room_2.per_thread().len(), 1);
764            // … which is thread 2.0.
765            assert!(room_2.per_thread().contains_key(thread_id_2_0));
766        }
767    }
768
769    #[async_test]
770    async fn test_forget_room() {
771        let room_id_0 = room_id!("!r0");
772        let room_id_1 = room_id!("!r1");
773
774        let server = MatrixMockServer::new().await;
775        let client = server.client_builder().build().await;
776
777        client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
778        client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
779
780        client.event_cache().subscribe().unwrap();
781
782        let latest_events = client.latest_events().await;
783
784        // Now let's fetch one room.
785        assert!(latest_events.listen_to_room(room_id_0).await.unwrap());
786
787        {
788            let rooms = latest_events.state.registered_rooms.rooms.read().await;
789            // There are one room…
790            assert_eq!(rooms.len(), 1);
791            // … which is room 0.
792            assert!(rooms.contains_key(room_id_0));
793
794            // Room 0 contains zero thread latest events.
795            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
796        }
797
798        // Now let's forget about room 0.
799        latest_events.forget_room(room_id_0).await;
800
801        {
802            let rooms = latest_events.state.registered_rooms.rooms.read().await;
803            // There are now zero rooms.
804            assert!(rooms.is_empty());
805        }
806    }
807
808    #[async_test]
809    async fn test_forget_thread() {
810        let room_id_0 = room_id!("!r0");
811        let room_id_1 = room_id!("!r1");
812        let thread_id_0_0 = event_id!("$ev0.0");
813
814        let server = MatrixMockServer::new().await;
815        let client = server.client_builder().build().await;
816
817        client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
818        client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
819
820        client.event_cache().subscribe().unwrap();
821
822        let latest_events = client.latest_events().await;
823
824        // Now let's fetch one thread .
825        assert!(latest_events.listen_to_thread(room_id_0, thread_id_0_0).await.unwrap());
826
827        {
828            let rooms = latest_events.state.registered_rooms.rooms.read().await;
829            // There is one room…
830            assert_eq!(rooms.len(), 1);
831            // … which is room 0.
832            assert!(rooms.contains_key(room_id_0));
833
834            // Room 0 contains one thread latest event…
835            let room_0 = rooms.get(room_id_0).unwrap().read().await;
836            assert_eq!(room_0.per_thread().len(), 1);
837            // … which is thread 0.0.
838            assert!(room_0.per_thread().contains_key(thread_id_0_0));
839        }
840
841        // Now let's forget about the thread.
842        latest_events.forget_thread(room_id_0, thread_id_0_0).await;
843
844        {
845            let rooms = latest_events.state.registered_rooms.rooms.read().await;
846            // There is still one room…
847            assert_eq!(rooms.len(), 1);
848            // … which is room 0.
849            assert!(rooms.contains_key(room_id_0));
850
851            // But the thread has been removed.
852            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
853        }
854    }
855
856    #[async_test]
857    async fn test_inputs_task_can_listen_to_room_event_cache() {
858        let room_id = owned_room_id!("!r0");
859
860        let server = MatrixMockServer::new().await;
861        let client = server.client_builder().build().await;
862        let weak_client = WeakClient::from_client(&client);
863        let weak_room = WeakRoom::new(weak_client, room_id.clone());
864
865        let event_cache = client.event_cache();
866
867        let registered_rooms = RwLock::new(HashMap::new());
868        let (room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
869            broadcast::channel(1);
870        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
871            broadcast::channel(1);
872        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
873        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
874
875        // New event cache update, but the `LatestEvents` isn't listening to it.
876        {
877            room_event_cache_generic_update_sender
878                .send(RoomEventCacheGenericUpdate { room_id: room_id.clone() })
879                .unwrap();
880
881            // Run the task.
882            assert!(
883                listen_to_updates(
884                    &registered_rooms,
885                    &mut room_event_cache_generic_update_receiver,
886                    &mut send_queue_generic_update_receiver,
887                    &mut room_info_update_receiver,
888                    &latest_event_queue_sender,
889                )
890                .await
891                .is_continue()
892            );
893
894            // No latest event computation has been triggered.
895            assert!(latest_event_queue_receiver.is_empty());
896        }
897
898        // New event cache update, but this time, the `LatestEvents` is
899        // listening to it.
900        {
901            registered_rooms.write().await.insert(
902                room_id.clone(),
903                With::inner(RoomLatestEvents::new(weak_room, event_cache)),
904            );
905            room_event_cache_generic_update_sender
906                .send(RoomEventCacheGenericUpdate { room_id: room_id.clone() })
907                .unwrap();
908
909            assert!(
910                listen_to_updates(
911                    &registered_rooms,
912                    &mut room_event_cache_generic_update_receiver,
913                    &mut send_queue_generic_update_receiver,
914                    &mut room_info_update_receiver,
915                    &latest_event_queue_sender,
916                )
917                .await
918                .is_continue()
919            );
920
921            // A latest event computation has been triggered!
922            assert!(latest_event_queue_receiver.is_empty().not());
923        }
924    }
925
926    #[async_test]
927    async fn test_inputs_task_can_listen_to_send_queue() {
928        let room_id = owned_room_id!("!r0");
929
930        let server = MatrixMockServer::new().await;
931        let client = server.client_builder().build().await;
932        let weak_client = WeakClient::from_client(&client);
933        let weak_room = WeakRoom::new(weak_client, room_id.clone());
934
935        let event_cache = client.event_cache();
936
937        let registered_rooms = RwLock::new(HashMap::new());
938
939        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
940            broadcast::channel(1);
941        let (send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
942            broadcast::channel(1);
943        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
944        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
945
946        // New send queue update, but the `LatestEvents` isn't listening to it.
947        {
948            send_queue_generic_update_sender
949                .send(SendQueueUpdate {
950                    room_id: room_id.clone(),
951                    update: RoomSendQueueUpdate::SentEvent {
952                        transaction_id: OwnedTransactionId::from("txnid0"),
953                        event_id: owned_event_id!("$ev0"),
954                    },
955                })
956                .unwrap();
957
958            // Run the task.
959            assert!(
960                listen_to_updates(
961                    &registered_rooms,
962                    &mut room_event_cache_generic_update_receiver,
963                    &mut send_queue_generic_update_receiver,
964                    &mut room_info_update_receiver,
965                    &latest_event_queue_sender,
966                )
967                .await
968                .is_continue()
969            );
970
971            // No latest event computation has been triggered.
972            assert!(latest_event_queue_receiver.is_empty());
973        }
974
975        // New send queue update, but this time, the `LatestEvents` is listening
976        // to it.
977        {
978            registered_rooms.write().await.insert(
979                room_id.clone(),
980                With::inner(RoomLatestEvents::new(weak_room, event_cache)),
981            );
982            send_queue_generic_update_sender
983                .send(SendQueueUpdate {
984                    room_id: room_id.clone(),
985                    update: RoomSendQueueUpdate::SentEvent {
986                        transaction_id: OwnedTransactionId::from("txnid1"),
987                        event_id: owned_event_id!("$ev1"),
988                    },
989                })
990                .unwrap();
991
992            assert!(
993                listen_to_updates(
994                    &registered_rooms,
995                    &mut room_event_cache_generic_update_receiver,
996                    &mut send_queue_generic_update_receiver,
997                    &mut room_info_update_receiver,
998                    &latest_event_queue_sender,
999                )
1000                .await
1001                .is_continue()
1002            );
1003
1004            // A latest event computation has been triggered!
1005            assert!(latest_event_queue_receiver.is_empty().not());
1006        }
1007    }
1008
1009    #[async_test]
1010    async fn test_inputs_task_can_listen_to_room_info() {
1011        let room_id = owned_room_id!("!r0");
1012
1013        let server = MatrixMockServer::new().await;
1014        let client = server.client_builder().build().await;
1015        let weak_client = WeakClient::from_client(&client);
1016        let weak_room = WeakRoom::new(weak_client, room_id.clone());
1017
1018        let event_cache = client.event_cache();
1019
1020        let registered_rooms = RwLock::new(HashMap::new());
1021
1022        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1023            broadcast::channel(1);
1024        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1025            broadcast::channel(1);
1026        let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1027        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1028
1029        // New room info update, but the `LatestEvents` isn't listening to it.
1030        {
1031            room_info_update_sender
1032                .send(RoomInfoNotableUpdate {
1033                    room_id: room_id.clone(),
1034                    reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1035                })
1036                .unwrap();
1037
1038            // Run the task.
1039            assert!(
1040                listen_to_updates(
1041                    &registered_rooms,
1042                    &mut room_event_cache_generic_update_receiver,
1043                    &mut send_queue_generic_update_receiver,
1044                    &mut room_info_update_receiver,
1045                    &latest_event_queue_sender,
1046                )
1047                .await
1048                .is_continue()
1049            );
1050
1051            // No latest event computation has been triggered.
1052            assert!(latest_event_queue_receiver.is_empty());
1053        }
1054
1055        // New room info update, but this time, the `LatestEvents` is listening
1056        // to it.
1057        {
1058            registered_rooms.write().await.insert(
1059                room_id.clone(),
1060                With::inner(RoomLatestEvents::new(weak_room, event_cache)),
1061            );
1062            room_info_update_sender
1063                .send(RoomInfoNotableUpdate {
1064                    room_id: room_id.clone(),
1065                    reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1066                })
1067                .unwrap();
1068
1069            assert!(
1070                listen_to_updates(
1071                    &registered_rooms,
1072                    &mut room_event_cache_generic_update_receiver,
1073                    &mut send_queue_generic_update_receiver,
1074                    &mut room_info_update_receiver,
1075                    &latest_event_queue_sender,
1076                )
1077                .await
1078                .is_continue()
1079            );
1080
1081            // A latest event computation has been triggered!
1082            assert!(latest_event_queue_receiver.is_empty().not());
1083        }
1084    }
1085
1086    #[async_test]
1087    async fn test_inputs_task_can_listen_to_specific_room_info_update_reasons() {
1088        let room_id = owned_room_id!("!r0");
1089
1090        let server = MatrixMockServer::new().await;
1091        let client = server.client_builder().build().await;
1092        let weak_client = WeakClient::from_client(&client);
1093        let weak_room = WeakRoom::new(weak_client, room_id.clone());
1094
1095        let event_cache = client.event_cache();
1096
1097        let registered_rooms = RwLock::new(HashMap::new());
1098
1099        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1100            broadcast::channel(1);
1101        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1102            broadcast::channel(1);
1103        let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1104        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1105
1106        registered_rooms
1107            .write()
1108            .await
1109            .insert(room_id.clone(), With::inner(RoomLatestEvents::new(weak_room, event_cache)));
1110
1111        // - `RoomInfoNotableUpdateReasons::LATEST_EVENT` is forbidden, otherwise it
1112        //   could create loops.
1113        // - Other reasons are ignored, except
1114        //   `RoomInfoNotableUpdateReasons::MEMBERSHIP`.
1115        for reason in {
1116            let mut all = RoomInfoNotableUpdateReasons::all();
1117            all.remove(RoomInfoNotableUpdateReasons::MEMBERSHIP);
1118
1119            all.iter()
1120        } {
1121            room_info_update_sender
1122                .send(RoomInfoNotableUpdate { room_id: room_id.clone(), reasons: reason })
1123                .unwrap();
1124
1125            assert!(
1126                listen_to_updates(
1127                    &registered_rooms,
1128                    &mut room_event_cache_generic_update_receiver,
1129                    &mut send_queue_generic_update_receiver,
1130                    &mut room_info_update_receiver,
1131                    &latest_event_queue_sender,
1132                )
1133                .await
1134                .is_continue()
1135            );
1136
1137            // No latest event computation has been triggered.
1138            assert!(latest_event_queue_receiver.is_empty());
1139        }
1140
1141        // `RoomInfoNotableUpdateReason::MEMBERSHIP` is accepted.
1142        {
1143            room_info_update_sender
1144                .send(RoomInfoNotableUpdate {
1145                    room_id: room_id.clone(),
1146                    reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1147                })
1148                .unwrap();
1149
1150            assert!(
1151                listen_to_updates(
1152                    &registered_rooms,
1153                    &mut room_event_cache_generic_update_receiver,
1154                    &mut send_queue_generic_update_receiver,
1155                    &mut room_info_update_receiver,
1156                    &latest_event_queue_sender,
1157                )
1158                .await
1159                .is_continue()
1160            );
1161
1162            // A latest event computation has been triggered!
1163            assert!(latest_event_queue_receiver.is_empty().not());
1164        }
1165    }
1166
1167    #[async_test]
1168    async fn test_inputs_task_stops_when_event_cache_channel_is_closed() {
1169        let registered_rooms = RwLock::new(HashMap::new());
1170        let (room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1171            broadcast::channel(1);
1172        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1173            broadcast::channel(1);
1174        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1175        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1176
1177        // Drop the sender to close the channel.
1178        drop(room_event_cache_generic_update_sender);
1179
1180        // Run the task.
1181        assert!(
1182            listen_to_updates(
1183                &registered_rooms,
1184                &mut room_event_cache_generic_update_receiver,
1185                &mut send_queue_generic_update_receiver,
1186                &mut room_info_update_receiver,
1187                &latest_event_queue_sender,
1188            )
1189            .await
1190            // It breaks!
1191            .is_break()
1192        );
1193
1194        assert!(latest_event_queue_receiver.is_empty());
1195    }
1196
1197    #[async_test]
1198    async fn test_inputs_task_stops_when_send_queue_channel_is_closed() {
1199        let registered_rooms = RwLock::new(HashMap::new());
1200        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1201            broadcast::channel(1);
1202        let (send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1203            broadcast::channel(1);
1204        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1205        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1206
1207        // Drop the sender to close the channel.
1208        drop(send_queue_generic_update_sender);
1209
1210        // Run the task.
1211        assert!(
1212            listen_to_updates(
1213                &registered_rooms,
1214                &mut room_event_cache_generic_update_receiver,
1215                &mut send_queue_generic_update_receiver,
1216                &mut room_info_update_receiver,
1217                &latest_event_queue_sender,
1218            )
1219            .await
1220            // It breaks!
1221            .is_break()
1222        );
1223
1224        assert!(latest_event_queue_receiver.is_empty());
1225    }
1226
1227    #[async_test]
1228    async fn test_inputs_task_stops_when_room_info_updates_are_closed() {
1229        let registered_rooms = RwLock::new(HashMap::new());
1230        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1231            broadcast::channel(1);
1232        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1233            broadcast::channel(1);
1234        let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1235        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1236
1237        // Drop the sender to close the channel.
1238        drop(room_info_update_sender);
1239
1240        // Run the task.
1241        assert!(
1242            listen_to_updates(
1243                &registered_rooms,
1244                &mut room_event_cache_generic_update_receiver,
1245                &mut send_queue_generic_update_receiver,
1246                &mut room_info_update_receiver,
1247                &latest_event_queue_sender,
1248            )
1249            .await
1250            // It breaks!
1251            .is_break()
1252        );
1253
1254        assert!(latest_event_queue_receiver.is_empty());
1255    }
1256
1257    #[async_test]
1258    async fn test_latest_event_value_is_updated_via_event_cache() {
1259        let room_id = owned_room_id!("!r0");
1260        let user_id = user_id!("@mnt_io:matrix.org");
1261        let event_factory = EventFactory::new().sender(user_id).room(&room_id);
1262        let event_id_0 = event_id!("$ev0");
1263
1264        let server = MatrixMockServer::new().await;
1265        let client = server.client_builder().build().await;
1266
1267        // Create the room.
1268        client.base_client().get_or_create_room(&room_id, RoomState::Joined);
1269
1270        let event_cache = client.event_cache();
1271        event_cache.subscribe().unwrap();
1272
1273        let latest_events = client.latest_events().await;
1274
1275        // Subscribe to the latest event values for this room.
1276        let mut latest_event_stream =
1277            latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1278
1279        // The stream is pending: no new latest event for the moment.
1280        assert_pending!(latest_event_stream);
1281
1282        // Update the event cache with a sync.
1283        server
1284            .sync_room(
1285                &client,
1286                JoinedRoomBuilder::new(&room_id)
1287                    .add_timeline_event(event_factory.text_msg("raclette !").event_id(event_id_0)),
1288            )
1289            .await;
1290
1291        // The event cache has received its update from the sync. It has emitted
1292        // a generic update, which has been received by `LatestEvents` tasks, up
1293        // to the `compute_latest_events` which has updated the latest event
1294        // value.
1295        assert_matches!(
1296            latest_event_stream.next().await,
1297            Some(LatestEventValue::Remote(RemoteLatestEventValue { kind: TimelineEventKind::PlainText { event }, .. })) => {
1298                assert_matches!(
1299                    event.deserialize().unwrap(),
1300                    AnySyncTimelineEvent::MessageLike(
1301                        AnySyncMessageLikeEvent::RoomMessage(
1302                            SyncMessageLikeEvent::Original(message_content)
1303                        )
1304                    ) => {
1305                        assert_eq!(message_content.content.body(), "raclette !");
1306                    }
1307                );
1308            }
1309        );
1310
1311        assert_pending!(latest_event_stream);
1312    }
1313
1314    #[async_test]
1315    async fn test_latest_event_value_is_initialized_by_the_event_cache_lazily() {
1316        let room_id = owned_room_id!("!r0");
1317        let user_id = user_id!("@mnt_io:matrix.org");
1318        let event_factory = EventFactory::new().sender(user_id).room(&room_id);
1319        let event_id_0 = event_id!("$ev0");
1320
1321        let server = MatrixMockServer::new().await;
1322        let client = server.client_builder().build().await;
1323
1324        // Prelude.
1325        {
1326            // Create the room.
1327            client.base_client().get_or_create_room(&room_id, RoomState::Joined);
1328
1329            // Initialise the event cache store.
1330            client
1331                .event_cache_store()
1332                .lock()
1333                .await
1334                .expect("Could not acquire the event cache lock")
1335                .as_clean()
1336                .expect("Could not acquire a clean event cache lock")
1337                .handle_linked_chunk_updates(
1338                    LinkedChunkId::Room(&room_id),
1339                    vec![
1340                        Update::NewItemsChunk {
1341                            previous: None,
1342                            new: ChunkIdentifier::new(0),
1343                            next: None,
1344                        },
1345                        Update::PushItems {
1346                            at: Position::new(ChunkIdentifier::new(0), 0),
1347                            items: vec![
1348                                event_factory.text_msg("hello").event_id(event_id_0).into(),
1349                            ],
1350                        },
1351                    ],
1352                )
1353                .await
1354                .unwrap();
1355        }
1356
1357        let event_cache = client.event_cache();
1358        event_cache.subscribe().unwrap();
1359
1360        let latest_events = client.latest_events().await;
1361
1362        let mut latest_event_stream =
1363            latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1364
1365        // We have a race if the system is busy. Initially, the latest event
1366        // value is `LatestEventValue::None`, then an Event Cache generic update
1367        // is broadcasted manually, computing a new `LatestEventValue`. So let's
1368        // wait on the system to finish this, and assert the final
1369        // `LatestEventValue`.
1370        yield_now().await;
1371        assert_matches!(latest_event_stream.next_now().await, LatestEventValue::Remote(_));
1372
1373        assert_pending!(latest_event_stream);
1374    }
1375
1376    /// This tests a part of
1377    /// [`test_latest_event_value_is_initialized_by_the_event_cache_lazily`].
1378    ///
1379    /// When `RegisteredRooms::room_latest_events` restores a
1380    /// `LatestEventValue::None` (via `RoomLatestEvents::new`), a
1381    /// `LatestEventQueueUpdate::EventCache` is broadcasted to compute a
1382    /// `LatestEventValue` from the Event Cache lazily.
1383    #[async_test]
1384    async fn test_latest_event_value_is_initialized_by_the_event_cache_lazily_inner() {
1385        let room_id_0 = owned_room_id!("!r0");
1386        let room_id_1 = owned_room_id!("!r1");
1387
1388        let server = MatrixMockServer::new().await;
1389        let client = server.client_builder().build().await;
1390
1391        // Create the rooms.
1392        let room_0 = client.base_client().get_or_create_room(&room_id_0, RoomState::Joined);
1393        let room_1 = client.base_client().get_or_create_room(&room_id_1, RoomState::Joined);
1394
1395        // Set up the rooms. `room_0` always has a `LatestEventValue::None` as
1396        // its the default value.
1397        let mut room_info_1 = room_0.clone_info();
1398        room_info_1.set_latest_event(LatestEventValue::LocalIsSending(local_room_message("foo")));
1399        room_1.update_room_info(|_| (room_info_1, Default::default())).await;
1400
1401        let weak_client = WeakClient::from_client(&client);
1402
1403        let event_cache = client.event_cache();
1404        event_cache.subscribe().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        // Room 0 has a `LatestEventValue::None`, a
1413        // `LatestEventQueueUpdate::EventCache` will be broadcasted.
1414        {
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        // Room 1 has a `LatestEventValue::Local*`, a
1430        // `LatestEventQueueUpdate::EventCache` will NOT be broadcasted.
1431        {
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 event_cache = client.event_cache();
1454        event_cache.subscribe().unwrap();
1455
1456        let latest_events = client.latest_events().await;
1457
1458        // Subscribe to the latest event values for this room.
1459        let mut latest_event_stream =
1460            latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1461
1462        // The stream is pending: no new latest event for the moment.
1463        assert_pending!(latest_event_stream);
1464
1465        let now = MilliSecondsSinceUnixEpoch::now().get();
1466
1467        // Update the room with a sync: the user is invited to a room.
1468        {
1469            server
1470                .sync_room(
1471                    &client,
1472                    InvitedRoomBuilder::new(&room_id).add_state_event(
1473                        event_factory
1474                            .member(other_user_id)
1475                            .invited(own_user_id)
1476                            .event_id(event_id_0),
1477                    ),
1478                )
1479                .await;
1480
1481            // The room has received its update from the sync. It has emitted a
1482            // room info update, which has been received by `LatestEvents`
1483            // tasks, up to the `compute_latest_events` which has updated the
1484            // latest event value.
1485            assert_matches!(
1486                latest_event_stream.next().await,
1487                Some(LatestEventValue::RemoteInvite { event_id, timestamp, inviter }) => {
1488                    // It's a stripped state event: they don't have an event ID.
1489                    assert!(event_id.is_none());
1490                    // It's a stripped state event: they don't have a timestamp (`origin_server_ts`), but `now` is normally used as a fallback.
1491                    assert!(timestamp.get() >= now);
1492                    assert_eq!(inviter.as_deref(), Some(other_user_id));
1493                }
1494            );
1495
1496            assert_pending!(latest_event_stream);
1497        };
1498
1499        // Update the room with a sync: the user is invited to the same room.
1500        {
1501            server
1502                .sync_room(
1503                    &client,
1504                    InvitedRoomBuilder::new(&room_id).add_state_event(
1505                        event_factory
1506                            .member(other_user_id)
1507                            .invited(own_user_id)
1508                            .event_id(event_id_0),
1509                    ),
1510                )
1511                .await;
1512
1513            // The room has received its update from the sync. It has emitted a
1514            // room info update, which has been received by `LatestEvents`
1515            // tasks, up to the `compute_latest_events` which has NOT updated
1516            // the latest event value because a previous `RemoteInvite` was
1517            // already computed.
1518            assert!(timeout(Duration::from_secs(1), latest_event_stream.next()).await.is_err());
1519
1520            assert_pending!(latest_event_stream);
1521        }
1522
1523        // Update the room with a sync: the user is joining the room.
1524        {
1525            let now = u64::from(now) + 10; // time flies
1526            server
1527                .sync_room(
1528                    &client,
1529                    JoinedRoomBuilder::new(&room_id).add_timeline_event(
1530                        event_factory
1531                            .member(own_user_id)
1532                            .membership(MembershipState::Join)
1533                            .event_id(event_id_1)
1534                            .server_ts(now),
1535                    ),
1536                )
1537                .await;
1538
1539            // The event cache has received its update from the sync. It has
1540            // emitted a generic update, which has been received by
1541            // `LatestEvents` tasks, up to the `compute_latest_events` which has
1542            // updated the latest event value.
1543            assert_matches!(
1544                latest_event_stream.next().await,
1545                Some(LatestEventValue::Remote(RemoteLatestEventValue { kind: TimelineEventKind::PlainText { event }, .. })) => {
1546                    assert_matches!(
1547                        event.deserialize().unwrap(),
1548                        AnySyncTimelineEvent::State(
1549                            AnySyncStateEvent::RoomMember(
1550                                SyncRoomMemberEvent::Original(event)
1551                            )
1552                        ) => {
1553                            assert_eq!(event.event_id, event_id_1);
1554                            assert_eq!(event.content.membership, MembershipState::Join);
1555                            assert_eq!(event.sender, own_user_id);
1556                            assert_eq!(event.state_key, own_user_id);
1557                            assert_eq!(u64::from(event.origin_server_ts.get()), now);
1558                        }
1559                    );
1560                }
1561            );
1562
1563            assert_pending!(latest_event_stream);
1564        }
1565    }
1566}