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 infos
114        // 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 kind `None`,
292            // let's try to re-compute it without waiting on the Event Cache (so the sync
293            // usually) or the Send Queue. Maybe the system has migrated to a new version
294            // and the `LatestEventValue` has been erased, while it is still possible to
295            // compute a correct value.
296            if is_latest_event_value_none {
297                let _ = latest_event_queue_sender
298                    .send(LatestEventQueueUpdate::EventCache { room_id: room_id.to_owned() });
299            }
300        }
301
302        Ok(match thread_id {
303            // Get the room latest event with the aim of fetching the latest event for a particular
304            // thread.
305            //
306            // We need to take a write lock immediately, in case the thead latest event doesn't
307            // exist.
308            Some(thread_id) => {
309                let mut rooms = self.rooms.write().await;
310
311                // The `RoomLatestEvents` doesn't exist. Let's create and insert it.
312                if rooms.contains_key(room_id).not() {
313                    create_and_insert_room_latest_events(
314                        room_id,
315                        rooms.deref_mut(),
316                        &self.weak_client,
317                        &self.event_cache,
318                        &self.latest_event_queue_sender,
319                    );
320                }
321
322                if let Some(room_latest_event) = rooms.get(room_id) {
323                    let mut room_latest_event = room_latest_event.write().await;
324
325                    // In `RoomLatestEvents`, the `LatestEvent` for this thread doesn't exist. Let's
326                    // create and insert it.
327                    if room_latest_event.has_thread(thread_id).not() {
328                        room_latest_event.create_and_insert_latest_event_for_thread(thread_id);
329                    }
330                }
331
332                RwLockWriteGuard::try_downgrade_map(rooms, |rooms| rooms.get(room_id)).ok()
333            }
334
335            // Get the room latest event with the aim of fetching the latest event for a particular
336            // room.
337            None => {
338                match RwLockReadGuard::try_map(self.rooms.read().await, |rooms| rooms.get(room_id))
339                    .ok()
340                {
341                    value @ Some(_) => value,
342                    None => {
343                        let _timer = timer!(
344                            tracing::Level::INFO,
345                            format!("Creating `RoomLatestEvents` for {room_id:?}"),
346                        );
347
348                        let mut rooms = self.rooms.write().await;
349
350                        if rooms.contains_key(room_id).not() {
351                            create_and_insert_room_latest_events(
352                                room_id,
353                                rooms.deref_mut(),
354                                &self.weak_client,
355                                &self.event_cache,
356                                &self.latest_event_queue_sender,
357                            );
358                        }
359
360                        RwLockWriteGuard::try_downgrade_map(rooms, |rooms| rooms.get(room_id)).ok()
361                    }
362                }
363            }
364        })
365    }
366
367    /// Start listening to updates (if not already) for a particular room.
368    ///
369    /// It returns `None` if the room doesn't exist.
370    pub async fn for_room(
371        &self,
372        room_id: &RoomId,
373    ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
374        self.room_latest_event(room_id, None).await
375    }
376
377    /// Start listening to updates (if not already) for a particular room.
378    ///
379    /// It returns `None` if the room or the thread doesn't exist.
380    pub async fn for_thread(
381        &self,
382        room_id: &RoomId,
383        thread_id: &EventId,
384    ) -> Result<Option<RwLockReadGuard<'_, RoomLatestEvents>>, LatestEventsError> {
385        self.room_latest_event(room_id, Some(thread_id)).await
386    }
387
388    /// Forget a room.
389    ///
390    /// It means that [`LatestEvents`] will stop listening to updates for the
391    /// `LatestEvent`s of the room and all its threads.
392    ///
393    /// If [`LatestEvents`] is not listening for `room_id`, nothing happens.
394    pub async fn forget_room(&self, room_id: &RoomId) {
395        {
396            let mut rooms = self.rooms.write().await;
397
398            // Remove the whole `RoomLatestEvents`.
399            rooms.remove(room_id);
400        }
401    }
402
403    /// Forget a thread.
404    ///
405    /// It means that [`LatestEvents`] will stop listening to updates for the
406    /// `LatestEvent` of the thread.
407    ///
408    /// If [`LatestEvents`] is not listening for `room_id` or `thread_id`,
409    /// nothing happens.
410    pub async fn forget_thread(&self, room_id: &RoomId, thread_id: &EventId) {
411        let rooms = self.rooms.read().await;
412
413        // If the `RoomLatestEvents`, remove the `LatestEvent` in `per_thread`.
414        if let Some(room_latest_event) = rooms.get(room_id) {
415            let mut room_latest_event = room_latest_event.write().await;
416
417            // Release the lock on `self.rooms`.
418            drop(rooms);
419
420            room_latest_event.forget_thread(thread_id);
421        }
422    }
423}
424
425/// Represents the kind of updates the [`compute_latest_events_task`] will have
426/// to deal with.
427#[derive(Debug)]
428enum LatestEventQueueUpdate {
429    /// An update from the [`EventCache`] happened.
430    EventCache {
431        /// The ID of the room that has triggered the update.
432        room_id: OwnedRoomId,
433    },
434
435    /// An update from the [`SendQueue`] happened.
436    SendQueue {
437        /// The ID of the room that has triggered the update.
438        room_id: OwnedRoomId,
439
440        /// The update itself.
441        update: RoomSendQueueUpdate,
442    },
443
444    /// An update from the [`RoomInfo`] happened.
445    ///
446    /// [`RoomInfo`]: crate::RoomInfo
447    RoomInfo {
448        /// The ID of the room that has triggered the update.
449        room_id: OwnedRoomId,
450
451        /// The notable update reasons.
452        reasons: RoomInfoNotableUpdateReasons,
453    },
454}
455
456/// The task responsible to listen to the [`EventCache`], the [`SendQueue`] and
457/// the [`RoomInfoNotableUpdate`].
458///
459/// When an update is received and is considered relevant, a message is sent to
460/// the [`compute_latest_events_task`] to compute a new [`LatestEvent`].
461///
462/// When an update is considered relevant, a message is sent over the
463/// `latest_event_queue_sender` channel. See [`compute_latest_events_task`].
464async fn listen_to_updates_task(
465    registered_rooms: Arc<RegisteredRooms>,
466    event_cache: EventCache,
467    send_queue: SendQueue,
468    room_info_updates: broadcast::Receiver<RoomInfoNotableUpdate>,
469    latest_event_queue_sender: mpsc::UnboundedSender<LatestEventQueueUpdate>,
470) {
471    let mut event_cache_generic_updates_subscriber =
472        event_cache.subscribe_to_room_generic_updates();
473    let mut send_queue_generic_updates_subscriber = send_queue.subscribe();
474    let mut room_info_updates_subscriber = room_info_updates.resubscribe();
475
476    loop {
477        if listen_to_updates(
478            &registered_rooms.rooms,
479            &mut event_cache_generic_updates_subscriber,
480            &mut send_queue_generic_updates_subscriber,
481            &mut room_info_updates_subscriber,
482            &latest_event_queue_sender,
483        )
484        .await
485        .is_break()
486        {
487            warn!("`listen_to_updates_task` has stopped");
488
489            break;
490        }
491    }
492}
493
494/// The core of [`listen_to_updates_task`].
495///
496/// Having this function detached from its task is helpful for testing and for
497/// state isolation.
498async fn listen_to_updates(
499    registered_rooms: &RwLock<HashMap<OwnedRoomId, RoomLatestEvents>>,
500    event_cache_generic_updates_subscriber: &mut broadcast::Receiver<RoomEventCacheGenericUpdate>,
501    send_queue_generic_updates_subscriber: &mut broadcast::Receiver<SendQueueUpdate>,
502    room_info_updates_subscriber: &mut broadcast::Receiver<RoomInfoNotableUpdate>,
503    latest_event_queue_sender: &mpsc::UnboundedSender<LatestEventQueueUpdate>,
504) -> ControlFlow<()> {
505    select! {
506        room_event_cache_generic_update = event_cache_generic_updates_subscriber.recv() => {
507            if let Ok(RoomEventCacheGenericUpdate { room_id }) = room_event_cache_generic_update {
508                if registered_rooms.read().await.contains_key(&room_id) {
509                    let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::EventCache {
510                        room_id
511                    });
512                }
513            } else {
514                warn!("`event_cache_generic_updates` channel has been closed");
515
516                return ControlFlow::Break(());
517            }
518        }
519
520        send_queue_generic_update = send_queue_generic_updates_subscriber.recv() => {
521            if let Ok(SendQueueUpdate { room_id, update }) = send_queue_generic_update {
522                if registered_rooms.read().await.contains_key(&room_id) {
523                    let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::SendQueue {
524                        room_id,
525                        update
526                    });
527                }
528            } else {
529                warn!("`send_queue_generic_updates` channel has been closed");
530
531                return ControlFlow::Break(());
532            }
533        }
534
535        room_info_update = room_info_updates_subscriber.recv() => {
536            if let Ok(RoomInfoNotableUpdate { room_id, reasons }) = room_info_update {
537                // Filter the update reasons we are interested by.
538                if
539                    // Be careful: the `LATEST_EVENT` reason alone must always
540                    // be ignored! Otherwise it can create a loop.
541                    reasons == RoomInfoNotableUpdateReasons::LATEST_EVENT ||
542
543                    // We are interested by `MEMBERSHIP` so that it captures
544                    // when the user is invited, is joining, is knocking, or is
545                    // leaving a room.
546                    !reasons.contains(RoomInfoNotableUpdateReasons::MEMBERSHIP)
547                {
548                    return ControlFlow::Continue(())
549                }
550
551                if registered_rooms.read().await.contains_key(&room_id) {
552                    let _ = latest_event_queue_sender.send(LatestEventQueueUpdate::RoomInfo {
553                        room_id,
554                        reasons,
555                    });
556                }
557            } else {
558                warn!("`room_info_updates` channel has been closed");
559
560                return ControlFlow::Break(());
561            }
562        }
563    }
564
565    ControlFlow::Continue(())
566}
567
568/// The task responsible to compute new [`LatestEvent`] for a particular room or
569/// thread.
570///
571/// The messages are coming from [`listen_to_updates_task`].
572async fn compute_latest_events_task(
573    registered_rooms: Arc<RegisteredRooms>,
574    mut latest_event_queue_receiver: mpsc::UnboundedReceiver<LatestEventQueueUpdate>,
575) {
576    const BUFFER_SIZE: usize = 16;
577
578    let mut buffer = Vec::with_capacity(BUFFER_SIZE);
579
580    while latest_event_queue_receiver.recv_many(&mut buffer, BUFFER_SIZE).await > 0 {
581        compute_latest_events(&registered_rooms, &buffer).await;
582        buffer.clear();
583    }
584
585    warn!("`compute_latest_events_task` has stopped");
586}
587
588async fn compute_latest_events(
589    registered_rooms: &RegisteredRooms,
590    latest_event_queue_updates: &[LatestEventQueueUpdate],
591) {
592    async fn room_latest_events_write_guard(
593        registered_rooms: &RegisteredRooms,
594        room_id: &OwnedRoomId,
595    ) -> ControlFlow<RoomLatestEventsWriteGuard, ()> {
596        let rooms = registered_rooms.rooms.read().await;
597
598        if let Some(room_latest_events) = rooms.get(room_id) {
599            let room_latest_events = room_latest_events.write().await;
600
601            // Release the lock on `registered_rooms`.
602            // It is possible because `room_latest_events` is an owned lock guard.
603            drop(rooms);
604
605            ControlFlow::Break(room_latest_events)
606        } else {
607            info!(?room_id, "Failed to find the room");
608
609            ControlFlow::Continue(())
610        }
611    }
612
613    for latest_event_queue_update in latest_event_queue_updates {
614        match latest_event_queue_update {
615            LatestEventQueueUpdate::EventCache { room_id } => {
616                let ControlFlow::Break(mut room_latest_events) =
617                    room_latest_events_write_guard(registered_rooms, room_id).await
618                else {
619                    continue;
620                };
621
622                room_latest_events.update_with_event_cache().await;
623            }
624
625            LatestEventQueueUpdate::SendQueue { room_id, update } => {
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_send_queue(update).await;
633            }
634
635            LatestEventQueueUpdate::RoomInfo { room_id, reasons } => {
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_room_info(*reasons).await;
643            }
644        }
645    }
646}
647
648#[cfg(test)]
649fn local_room_message(body: &str) -> LocalLatestEventValue {
650    use matrix_sdk_base::store::SerializableEventContent;
651    use ruma::{
652        MilliSecondsSinceUnixEpoch,
653        events::{AnyMessageLikeEventContent, room::message::RoomMessageEventContent},
654    };
655
656    LocalLatestEventValue {
657        timestamp: MilliSecondsSinceUnixEpoch::now(),
658        content: SerializableEventContent::new(&AnyMessageLikeEventContent::RoomMessage(
659            RoomMessageEventContent::text_plain(body),
660        ))
661        .unwrap(),
662    }
663}
664
665#[cfg(all(test, not(target_family = "wasm")))]
666mod tests {
667    use std::{collections::HashMap, ops::Not, time::Duration};
668
669    use assert_matches::assert_matches;
670    use matrix_sdk_base::{
671        RoomState,
672        deserialized_responses::TimelineEventKind,
673        linked_chunk::{ChunkIdentifier, LinkedChunkId, Position, Update},
674    };
675    use matrix_sdk_test::{
676        InvitedRoomBuilder, JoinedRoomBuilder, async_test, event_factory::EventFactory,
677    };
678    use ruma::{
679        MilliSecondsSinceUnixEpoch, OwnedTransactionId, event_id,
680        events::{
681            AnySyncMessageLikeEvent, AnySyncStateEvent, AnySyncTimelineEvent, SyncMessageLikeEvent,
682            room::member::{MembershipState, SyncRoomMemberEvent},
683        },
684        owned_event_id, owned_room_id, room_id, user_id,
685    };
686    use stream_assert::assert_pending;
687    use tokio::{task::yield_now, time::timeout};
688
689    use super::{
690        LatestEventValue, RegisteredRooms, RemoteLatestEventValue, RoomEventCacheGenericUpdate,
691        RoomInfoNotableUpdate, RoomInfoNotableUpdateReasons, RoomLatestEvents, RoomSendQueueUpdate,
692        RwLock, SendQueueUpdate, WeakClient, WeakRoom, With, broadcast, listen_to_updates, mpsc,
693    };
694    use crate::{
695        latest_events::{LatestEventQueueUpdate, local_room_message},
696        test_utils::mocks::MatrixMockServer,
697    };
698
699    #[async_test]
700    async fn test_latest_events_are_lazy() {
701        let room_id_0 = room_id!("!r0");
702        let room_id_1 = room_id!("!r1");
703        let room_id_2 = room_id!("!r2");
704        let thread_id_1_0 = event_id!("$ev1.0");
705        let thread_id_2_0 = event_id!("$ev2.0");
706
707        let server = MatrixMockServer::new().await;
708        let client = server.client_builder().build().await;
709
710        client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
711        client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
712        client.base_client().get_or_create_room(room_id_2, RoomState::Joined);
713
714        client.event_cache().subscribe().unwrap();
715
716        let latest_events = client.latest_events().await;
717
718        // Despites there are many rooms, zero `RoomLatestEvents` are created.
719        assert!(latest_events.state.registered_rooms.rooms.read().await.is_empty());
720
721        // Now let's listen to two rooms.
722        assert!(latest_events.listen_to_room(room_id_0).await.unwrap());
723        assert!(latest_events.listen_to_room(room_id_1).await.unwrap());
724
725        {
726            let rooms = latest_events.state.registered_rooms.rooms.read().await;
727            // There are two rooms…
728            assert_eq!(rooms.len(), 2);
729            // … which are room 0 and room 1.
730            assert!(rooms.contains_key(room_id_0));
731            assert!(rooms.contains_key(room_id_1));
732
733            // Room 0 contains zero thread latest events.
734            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
735            // Room 1 contains zero thread latest events.
736            assert!(rooms.get(room_id_1).unwrap().read().await.per_thread().is_empty());
737        }
738
739        // Now let's listen to one thread respectively for two rooms.
740        assert!(latest_events.listen_to_thread(room_id_1, thread_id_1_0).await.unwrap());
741        assert!(latest_events.listen_to_thread(room_id_2, thread_id_2_0).await.unwrap());
742
743        {
744            let rooms = latest_events.state.registered_rooms.rooms.read().await;
745            // There are now three rooms…
746            assert_eq!(rooms.len(), 3);
747            // … yup, room 2 is now created.
748            assert!(rooms.contains_key(room_id_0));
749            assert!(rooms.contains_key(room_id_1));
750            assert!(rooms.contains_key(room_id_2));
751
752            // Room 0 contains zero thread latest events.
753            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
754            // Room 1 contains one thread latest event…
755            let room_1 = rooms.get(room_id_1).unwrap().read().await;
756            assert_eq!(room_1.per_thread().len(), 1);
757            // … which is thread 1.0.
758            assert!(room_1.per_thread().contains_key(thread_id_1_0));
759            // Room 2 contains one thread latest event…
760            let room_2 = rooms.get(room_id_2).unwrap().read().await;
761            assert_eq!(room_2.per_thread().len(), 1);
762            // … which is thread 2.0.
763            assert!(room_2.per_thread().contains_key(thread_id_2_0));
764        }
765    }
766
767    #[async_test]
768    async fn test_forget_room() {
769        let room_id_0 = room_id!("!r0");
770        let room_id_1 = room_id!("!r1");
771
772        let server = MatrixMockServer::new().await;
773        let client = server.client_builder().build().await;
774
775        client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
776        client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
777
778        client.event_cache().subscribe().unwrap();
779
780        let latest_events = client.latest_events().await;
781
782        // Now let's fetch one room.
783        assert!(latest_events.listen_to_room(room_id_0).await.unwrap());
784
785        {
786            let rooms = latest_events.state.registered_rooms.rooms.read().await;
787            // There are one room…
788            assert_eq!(rooms.len(), 1);
789            // … which is room 0.
790            assert!(rooms.contains_key(room_id_0));
791
792            // Room 0 contains zero thread latest events.
793            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
794        }
795
796        // Now let's forget about room 0.
797        latest_events.forget_room(room_id_0).await;
798
799        {
800            let rooms = latest_events.state.registered_rooms.rooms.read().await;
801            // There are now zero rooms.
802            assert!(rooms.is_empty());
803        }
804    }
805
806    #[async_test]
807    async fn test_forget_thread() {
808        let room_id_0 = room_id!("!r0");
809        let room_id_1 = room_id!("!r1");
810        let thread_id_0_0 = event_id!("$ev0.0");
811
812        let server = MatrixMockServer::new().await;
813        let client = server.client_builder().build().await;
814
815        client.base_client().get_or_create_room(room_id_0, RoomState::Joined);
816        client.base_client().get_or_create_room(room_id_1, RoomState::Joined);
817
818        client.event_cache().subscribe().unwrap();
819
820        let latest_events = client.latest_events().await;
821
822        // Now let's fetch one thread .
823        assert!(latest_events.listen_to_thread(room_id_0, thread_id_0_0).await.unwrap());
824
825        {
826            let rooms = latest_events.state.registered_rooms.rooms.read().await;
827            // There is one room…
828            assert_eq!(rooms.len(), 1);
829            // … which is room 0.
830            assert!(rooms.contains_key(room_id_0));
831
832            // Room 0 contains one thread latest event…
833            let room_0 = rooms.get(room_id_0).unwrap().read().await;
834            assert_eq!(room_0.per_thread().len(), 1);
835            // … which is thread 0.0.
836            assert!(room_0.per_thread().contains_key(thread_id_0_0));
837        }
838
839        // Now let's forget about the thread.
840        latest_events.forget_thread(room_id_0, thread_id_0_0).await;
841
842        {
843            let rooms = latest_events.state.registered_rooms.rooms.read().await;
844            // There is still one room…
845            assert_eq!(rooms.len(), 1);
846            // … which is room 0.
847            assert!(rooms.contains_key(room_id_0));
848
849            // But the thread has been removed.
850            assert!(rooms.get(room_id_0).unwrap().read().await.per_thread().is_empty());
851        }
852    }
853
854    #[async_test]
855    async fn test_inputs_task_can_listen_to_room_event_cache() {
856        let room_id = owned_room_id!("!r0");
857
858        let server = MatrixMockServer::new().await;
859        let client = server.client_builder().build().await;
860        let weak_client = WeakClient::from_client(&client);
861        let weak_room = WeakRoom::new(weak_client, room_id.clone());
862
863        let event_cache = client.event_cache();
864
865        let registered_rooms = RwLock::new(HashMap::new());
866        let (room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
867            broadcast::channel(1);
868        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
869            broadcast::channel(1);
870        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
871        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
872
873        // New event cache update, but the `LatestEvents` isn't listening to it.
874        {
875            room_event_cache_generic_update_sender
876                .send(RoomEventCacheGenericUpdate { room_id: room_id.clone() })
877                .unwrap();
878
879            // Run the task.
880            assert!(
881                listen_to_updates(
882                    &registered_rooms,
883                    &mut room_event_cache_generic_update_receiver,
884                    &mut send_queue_generic_update_receiver,
885                    &mut room_info_update_receiver,
886                    &latest_event_queue_sender,
887                )
888                .await
889                .is_continue()
890            );
891
892            // No latest event computation has been triggered.
893            assert!(latest_event_queue_receiver.is_empty());
894        }
895
896        // New event cache update, but this time, the `LatestEvents` is listening to it.
897        {
898            registered_rooms.write().await.insert(
899                room_id.clone(),
900                With::inner(RoomLatestEvents::new(weak_room, event_cache)),
901            );
902            room_event_cache_generic_update_sender
903                .send(RoomEventCacheGenericUpdate { room_id: room_id.clone() })
904                .unwrap();
905
906            assert!(
907                listen_to_updates(
908                    &registered_rooms,
909                    &mut room_event_cache_generic_update_receiver,
910                    &mut send_queue_generic_update_receiver,
911                    &mut room_info_update_receiver,
912                    &latest_event_queue_sender,
913                )
914                .await
915                .is_continue()
916            );
917
918            // A latest event computation has been triggered!
919            assert!(latest_event_queue_receiver.is_empty().not());
920        }
921    }
922
923    #[async_test]
924    async fn test_inputs_task_can_listen_to_send_queue() {
925        let room_id = owned_room_id!("!r0");
926
927        let server = MatrixMockServer::new().await;
928        let client = server.client_builder().build().await;
929        let weak_client = WeakClient::from_client(&client);
930        let weak_room = WeakRoom::new(weak_client, room_id.clone());
931
932        let event_cache = client.event_cache();
933
934        let registered_rooms = RwLock::new(HashMap::new());
935
936        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
937            broadcast::channel(1);
938        let (send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
939            broadcast::channel(1);
940        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
941        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
942
943        // New send queue update, but the `LatestEvents` isn't listening to it.
944        {
945            send_queue_generic_update_sender
946                .send(SendQueueUpdate {
947                    room_id: room_id.clone(),
948                    update: RoomSendQueueUpdate::SentEvent {
949                        transaction_id: OwnedTransactionId::from("txnid0"),
950                        event_id: owned_event_id!("$ev0"),
951                    },
952                })
953                .unwrap();
954
955            // Run the task.
956            assert!(
957                listen_to_updates(
958                    &registered_rooms,
959                    &mut room_event_cache_generic_update_receiver,
960                    &mut send_queue_generic_update_receiver,
961                    &mut room_info_update_receiver,
962                    &latest_event_queue_sender,
963                )
964                .await
965                .is_continue()
966            );
967
968            // No latest event computation has been triggered.
969            assert!(latest_event_queue_receiver.is_empty());
970        }
971
972        // New send queue update, but this time, the `LatestEvents` is listening to it.
973        {
974            registered_rooms.write().await.insert(
975                room_id.clone(),
976                With::inner(RoomLatestEvents::new(weak_room, event_cache)),
977            );
978            send_queue_generic_update_sender
979                .send(SendQueueUpdate {
980                    room_id: room_id.clone(),
981                    update: RoomSendQueueUpdate::SentEvent {
982                        transaction_id: OwnedTransactionId::from("txnid1"),
983                        event_id: owned_event_id!("$ev1"),
984                    },
985                })
986                .unwrap();
987
988            assert!(
989                listen_to_updates(
990                    &registered_rooms,
991                    &mut room_event_cache_generic_update_receiver,
992                    &mut send_queue_generic_update_receiver,
993                    &mut room_info_update_receiver,
994                    &latest_event_queue_sender,
995                )
996                .await
997                .is_continue()
998            );
999
1000            // A latest event computation has been triggered!
1001            assert!(latest_event_queue_receiver.is_empty().not());
1002        }
1003    }
1004
1005    #[async_test]
1006    async fn test_inputs_task_can_listen_to_room_info() {
1007        let room_id = owned_room_id!("!r0");
1008
1009        let server = MatrixMockServer::new().await;
1010        let client = server.client_builder().build().await;
1011        let weak_client = WeakClient::from_client(&client);
1012        let weak_room = WeakRoom::new(weak_client, room_id.clone());
1013
1014        let event_cache = client.event_cache();
1015
1016        let registered_rooms = RwLock::new(HashMap::new());
1017
1018        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1019            broadcast::channel(1);
1020        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1021            broadcast::channel(1);
1022        let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1023        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1024
1025        // New room info update, but the `LatestEvents` isn't listening to it.
1026        {
1027            room_info_update_sender
1028                .send(RoomInfoNotableUpdate {
1029                    room_id: room_id.clone(),
1030                    reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1031                })
1032                .unwrap();
1033
1034            // Run the task.
1035            assert!(
1036                listen_to_updates(
1037                    &registered_rooms,
1038                    &mut room_event_cache_generic_update_receiver,
1039                    &mut send_queue_generic_update_receiver,
1040                    &mut room_info_update_receiver,
1041                    &latest_event_queue_sender,
1042                )
1043                .await
1044                .is_continue()
1045            );
1046
1047            // No latest event computation has been triggered.
1048            assert!(latest_event_queue_receiver.is_empty());
1049        }
1050
1051        // New room info update, but this time, the `LatestEvents` is listening to it.
1052        {
1053            registered_rooms.write().await.insert(
1054                room_id.clone(),
1055                With::inner(RoomLatestEvents::new(weak_room, event_cache)),
1056            );
1057            room_info_update_sender
1058                .send(RoomInfoNotableUpdate {
1059                    room_id: room_id.clone(),
1060                    reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1061                })
1062                .unwrap();
1063
1064            assert!(
1065                listen_to_updates(
1066                    &registered_rooms,
1067                    &mut room_event_cache_generic_update_receiver,
1068                    &mut send_queue_generic_update_receiver,
1069                    &mut room_info_update_receiver,
1070                    &latest_event_queue_sender,
1071                )
1072                .await
1073                .is_continue()
1074            );
1075
1076            // A latest event computation has been triggered!
1077            assert!(latest_event_queue_receiver.is_empty().not());
1078        }
1079    }
1080
1081    #[async_test]
1082    async fn test_inputs_task_can_listen_to_specific_room_info_update_reasons() {
1083        let room_id = owned_room_id!("!r0");
1084
1085        let server = MatrixMockServer::new().await;
1086        let client = server.client_builder().build().await;
1087        let weak_client = WeakClient::from_client(&client);
1088        let weak_room = WeakRoom::new(weak_client, room_id.clone());
1089
1090        let event_cache = client.event_cache();
1091
1092        let registered_rooms = RwLock::new(HashMap::new());
1093
1094        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1095            broadcast::channel(1);
1096        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1097            broadcast::channel(1);
1098        let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1099        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1100
1101        registered_rooms
1102            .write()
1103            .await
1104            .insert(room_id.clone(), With::inner(RoomLatestEvents::new(weak_room, event_cache)));
1105
1106        // - `RoomInfoNotableUpdateReasons::LATEST_EVENT` is forbidden, otherwise it
1107        //   could create loops.
1108        // - Other reasons are ignored, except
1109        //   `RoomInfoNotableUpdateReasons::MEMBERSHIP`.
1110        for reason in {
1111            let mut all = RoomInfoNotableUpdateReasons::all();
1112            all.remove(RoomInfoNotableUpdateReasons::MEMBERSHIP);
1113
1114            all.iter()
1115        } {
1116            room_info_update_sender
1117                .send(RoomInfoNotableUpdate { room_id: room_id.clone(), reasons: reason })
1118                .unwrap();
1119
1120            assert!(
1121                listen_to_updates(
1122                    &registered_rooms,
1123                    &mut room_event_cache_generic_update_receiver,
1124                    &mut send_queue_generic_update_receiver,
1125                    &mut room_info_update_receiver,
1126                    &latest_event_queue_sender,
1127                )
1128                .await
1129                .is_continue()
1130            );
1131
1132            // No latest event computation has been triggered.
1133            assert!(latest_event_queue_receiver.is_empty());
1134        }
1135
1136        // `RoomInfoNotableUpdateReason::MEMBERSHIP` is accepted.
1137        {
1138            room_info_update_sender
1139                .send(RoomInfoNotableUpdate {
1140                    room_id: room_id.clone(),
1141                    reasons: RoomInfoNotableUpdateReasons::MEMBERSHIP,
1142                })
1143                .unwrap();
1144
1145            assert!(
1146                listen_to_updates(
1147                    &registered_rooms,
1148                    &mut room_event_cache_generic_update_receiver,
1149                    &mut send_queue_generic_update_receiver,
1150                    &mut room_info_update_receiver,
1151                    &latest_event_queue_sender,
1152                )
1153                .await
1154                .is_continue()
1155            );
1156
1157            // A latest event computation has been triggered!
1158            assert!(latest_event_queue_receiver.is_empty().not());
1159        }
1160    }
1161
1162    #[async_test]
1163    async fn test_inputs_task_stops_when_event_cache_channel_is_closed() {
1164        let registered_rooms = RwLock::new(HashMap::new());
1165        let (room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1166            broadcast::channel(1);
1167        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1168            broadcast::channel(1);
1169        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1170        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1171
1172        // Drop the sender to close the channel.
1173        drop(room_event_cache_generic_update_sender);
1174
1175        // Run the task.
1176        assert!(
1177            listen_to_updates(
1178                &registered_rooms,
1179                &mut room_event_cache_generic_update_receiver,
1180                &mut send_queue_generic_update_receiver,
1181                &mut room_info_update_receiver,
1182                &latest_event_queue_sender,
1183            )
1184            .await
1185            // It breaks!
1186            .is_break()
1187        );
1188
1189        assert!(latest_event_queue_receiver.is_empty());
1190    }
1191
1192    #[async_test]
1193    async fn test_inputs_task_stops_when_send_queue_channel_is_closed() {
1194        let registered_rooms = RwLock::new(HashMap::new());
1195        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1196            broadcast::channel(1);
1197        let (send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1198            broadcast::channel(1);
1199        let (_room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1200        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1201
1202        // Drop the sender to close the channel.
1203        drop(send_queue_generic_update_sender);
1204
1205        // Run the task.
1206        assert!(
1207            listen_to_updates(
1208                &registered_rooms,
1209                &mut room_event_cache_generic_update_receiver,
1210                &mut send_queue_generic_update_receiver,
1211                &mut room_info_update_receiver,
1212                &latest_event_queue_sender,
1213            )
1214            .await
1215            // It breaks!
1216            .is_break()
1217        );
1218
1219        assert!(latest_event_queue_receiver.is_empty());
1220    }
1221
1222    #[async_test]
1223    async fn test_inputs_task_stops_when_room_info_updates_are_closed() {
1224        let registered_rooms = RwLock::new(HashMap::new());
1225        let (_room_event_cache_generic_update_sender, mut room_event_cache_generic_update_receiver) =
1226            broadcast::channel(1);
1227        let (_send_queue_generic_update_sender, mut send_queue_generic_update_receiver) =
1228            broadcast::channel(1);
1229        let (room_info_update_sender, mut room_info_update_receiver) = broadcast::channel(1);
1230        let (latest_event_queue_sender, latest_event_queue_receiver) = mpsc::unbounded_channel();
1231
1232        // Drop the sender to close the channel.
1233        drop(room_info_update_sender);
1234
1235        // Run the task.
1236        assert!(
1237            listen_to_updates(
1238                &registered_rooms,
1239                &mut room_event_cache_generic_update_receiver,
1240                &mut send_queue_generic_update_receiver,
1241                &mut room_info_update_receiver,
1242                &latest_event_queue_sender,
1243            )
1244            .await
1245            // It breaks!
1246            .is_break()
1247        );
1248
1249        assert!(latest_event_queue_receiver.is_empty());
1250    }
1251
1252    #[async_test]
1253    async fn test_latest_event_value_is_updated_via_event_cache() {
1254        let room_id = owned_room_id!("!r0");
1255        let user_id = user_id!("@mnt_io:matrix.org");
1256        let event_factory = EventFactory::new().sender(user_id).room(&room_id);
1257        let event_id_0 = event_id!("$ev0");
1258
1259        let server = MatrixMockServer::new().await;
1260        let client = server.client_builder().build().await;
1261
1262        // Create the room.
1263        client.base_client().get_or_create_room(&room_id, RoomState::Joined);
1264
1265        let event_cache = client.event_cache();
1266        event_cache.subscribe().unwrap();
1267
1268        let latest_events = client.latest_events().await;
1269
1270        // Subscribe to the latest event values for this room.
1271        let mut latest_event_stream =
1272            latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1273
1274        // The stream is pending: no new latest event for the moment.
1275        assert_pending!(latest_event_stream);
1276
1277        // Update the event cache with a sync.
1278        server
1279            .sync_room(
1280                &client,
1281                JoinedRoomBuilder::new(&room_id)
1282                    .add_timeline_event(event_factory.text_msg("raclette !").event_id(event_id_0)),
1283            )
1284            .await;
1285
1286        // The event cache has received its update from the sync. It has emitted a
1287        // generic update, which has been received by `LatestEvents` tasks, up to the
1288        // `compute_latest_events` which has updated the latest event value.
1289        assert_matches!(
1290            latest_event_stream.next().await,
1291            Some(LatestEventValue::Remote(RemoteLatestEventValue { kind: TimelineEventKind::PlainText { event }, .. })) => {
1292                assert_matches!(
1293                    event.deserialize().unwrap(),
1294                    AnySyncTimelineEvent::MessageLike(
1295                        AnySyncMessageLikeEvent::RoomMessage(
1296                            SyncMessageLikeEvent::Original(message_content)
1297                        )
1298                    ) => {
1299                        assert_eq!(message_content.content.body(), "raclette !");
1300                    }
1301                );
1302            }
1303        );
1304
1305        assert_pending!(latest_event_stream);
1306    }
1307
1308    #[async_test]
1309    async fn test_latest_event_value_is_initialized_by_the_event_cache_lazily() {
1310        let room_id = owned_room_id!("!r0");
1311        let user_id = user_id!("@mnt_io:matrix.org");
1312        let event_factory = EventFactory::new().sender(user_id).room(&room_id);
1313        let event_id_0 = event_id!("$ev0");
1314
1315        let server = MatrixMockServer::new().await;
1316        let client = server.client_builder().build().await;
1317
1318        // Prelude.
1319        {
1320            // Create the room.
1321            client.base_client().get_or_create_room(&room_id, RoomState::Joined);
1322
1323            // Initialise the event cache store.
1324            client
1325                .event_cache_store()
1326                .lock()
1327                .await
1328                .expect("Could not acquire the event cache lock")
1329                .as_clean()
1330                .expect("Could not acquire a clean event cache lock")
1331                .handle_linked_chunk_updates(
1332                    LinkedChunkId::Room(&room_id),
1333                    vec![
1334                        Update::NewItemsChunk {
1335                            previous: None,
1336                            new: ChunkIdentifier::new(0),
1337                            next: None,
1338                        },
1339                        Update::PushItems {
1340                            at: Position::new(ChunkIdentifier::new(0), 0),
1341                            items: vec![
1342                                event_factory.text_msg("hello").event_id(event_id_0).into(),
1343                            ],
1344                        },
1345                    ],
1346                )
1347                .await
1348                .unwrap();
1349        }
1350
1351        let event_cache = client.event_cache();
1352        event_cache.subscribe().unwrap();
1353
1354        let latest_events = client.latest_events().await;
1355
1356        let mut latest_event_stream =
1357            latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1358
1359        // We have a race if the system is busy. Initially, the latest event
1360        // value is `LatestEventValue::None`, then an Event Cache generic update
1361        // is broadcasted manually, computing a new `LatestEventValue`. So let's
1362        // wait on the system to finish this, and assert the final
1363        // `LatestEventValue`.
1364        yield_now().await;
1365        assert_matches!(latest_event_stream.next_now().await, LatestEventValue::Remote(_));
1366
1367        assert_pending!(latest_event_stream);
1368    }
1369
1370    /// This tests a part of
1371    /// [`test_latest_event_value_is_initialized_by_the_event_cache_lazily`].
1372    ///
1373    /// When `RegisteredRooms::room_latest_events` restores a
1374    /// `LatestEventValue::None` (via `RoomLatestEvents::new`),
1375    /// a `LatestEventQueueUpdate::EventCache` is broadcasted to compute a
1376    /// `LatestEventValue` from the Event Cache lazily.
1377    #[async_test]
1378    async fn test_latest_event_value_is_initialized_by_the_event_cache_lazily_inner() {
1379        let room_id_0 = owned_room_id!("!r0");
1380        let room_id_1 = owned_room_id!("!r1");
1381
1382        let server = MatrixMockServer::new().await;
1383        let client = server.client_builder().build().await;
1384
1385        // Create the rooms.
1386        let room_0 = client.base_client().get_or_create_room(&room_id_0, RoomState::Joined);
1387        let room_1 = client.base_client().get_or_create_room(&room_id_1, RoomState::Joined);
1388
1389        // Set up the rooms.
1390        // `room_0` always has a `LatestEventValue::None` as its the default value.
1391        let mut room_info_1 = room_0.clone_info();
1392        room_info_1.set_latest_event(LatestEventValue::LocalIsSending(local_room_message("foo")));
1393        room_1.update_room_info(|_| (room_info_1, Default::default())).await;
1394
1395        let weak_client = WeakClient::from_client(&client);
1396
1397        let event_cache = client.event_cache();
1398        event_cache.subscribe().unwrap();
1399
1400        let (latest_event_queue_sender, mut latest_event_queue_receiver) =
1401            mpsc::unbounded_channel();
1402
1403        let registered_rooms =
1404            RegisteredRooms::new(weak_client, event_cache, &latest_event_queue_sender);
1405
1406        // Room 0 has a `LatestEventValue::None`, a
1407        // `LatestEventQueueUpdate::EventCache` will be broadcasted.
1408        {
1409            let room_latest_events = registered_rooms.for_room(&room_id_0).await.unwrap().unwrap();
1410            assert_matches!(
1411                room_latest_events.read().await.for_room().get().await,
1412                LatestEventValue::None
1413            );
1414            assert_matches!(
1415                latest_event_queue_receiver.recv().await,
1416                Some(LatestEventQueueUpdate::EventCache { room_id }) => {
1417                    assert_eq!(room_id, room_id_0);
1418                }
1419            );
1420            assert!(latest_event_queue_receiver.is_empty());
1421        }
1422
1423        // Room 1 has a `LatestEventValue::Local*`, a
1424        // `LatestEventQueueUpdate::EventCache` will NOT be broadcasted.
1425        {
1426            let room_latest_events = registered_rooms.for_room(&room_id_1).await.unwrap().unwrap();
1427            assert_matches!(
1428                room_latest_events.read().await.for_room().get().await,
1429                LatestEventValue::LocalIsSending(_)
1430            );
1431            assert!(latest_event_queue_receiver.is_empty());
1432        }
1433    }
1434
1435    #[async_test]
1436    async fn test_latest_event_value_is_updated_via_room_infos_for_invites() {
1437        let room_id = owned_room_id!("!r0");
1438        let event_factory = EventFactory::new().room(&room_id);
1439        let event_id_0 = event_id!("$ev0");
1440        let event_id_1 = event_id!("$ev1");
1441
1442        let server = MatrixMockServer::new().await;
1443        let client = server.client_builder().build().await;
1444        let own_user_id = client.user_id().unwrap();
1445        let other_user_id = user_id!("@other:servername");
1446
1447        let event_cache = client.event_cache();
1448        event_cache.subscribe().unwrap();
1449
1450        let latest_events = client.latest_events().await;
1451
1452        // Subscribe to the latest event values for this room.
1453        let mut latest_event_stream =
1454            latest_events.listen_and_subscribe_to_room(&room_id).await.unwrap().unwrap();
1455
1456        // The stream is pending: no new latest event for the moment.
1457        assert_pending!(latest_event_stream);
1458
1459        let now = MilliSecondsSinceUnixEpoch::now().get();
1460
1461        // Update the room with a sync: the user is invited to a room.
1462        {
1463            server
1464                .sync_room(
1465                    &client,
1466                    InvitedRoomBuilder::new(&room_id).add_state_event(
1467                        event_factory
1468                            .member(other_user_id)
1469                            .invited(own_user_id)
1470                            .event_id(event_id_0),
1471                    ),
1472                )
1473                .await;
1474
1475            // The room has received its update from the sync. It has emitted a room info
1476            // update, which has been received by `LatestEvents` tasks, up to the
1477            // `compute_latest_events` which has updated the latest event value.
1478            assert_matches!(
1479                latest_event_stream.next().await,
1480                Some(LatestEventValue::RemoteInvite { event_id, timestamp, inviter }) => {
1481                    // It's a stripped state event: they don't have an event ID.
1482                    assert!(event_id.is_none());
1483                    // It's a stripped state event: they don't have a timestamp (`origin_server_ts`), but `now` is normally used as a fallback.
1484                    assert!(timestamp.get() >= now);
1485                    assert_eq!(inviter.as_deref(), Some(other_user_id));
1486                }
1487            );
1488
1489            assert_pending!(latest_event_stream);
1490        };
1491
1492        // Update the room with a sync: the user is invited to the same room.
1493        {
1494            server
1495                .sync_room(
1496                    &client,
1497                    InvitedRoomBuilder::new(&room_id).add_state_event(
1498                        event_factory
1499                            .member(other_user_id)
1500                            .invited(own_user_id)
1501                            .event_id(event_id_0),
1502                    ),
1503                )
1504                .await;
1505
1506            // The room has received its update from the sync. It has emitted a room info
1507            // update, which has been received by `LatestEvents` tasks, up to the
1508            // `compute_latest_events` which has NOT updated the latest event value because
1509            // a previous `RemoteInvite` was already computed.
1510            assert!(timeout(Duration::from_secs(1), latest_event_stream.next()).await.is_err());
1511
1512            assert_pending!(latest_event_stream);
1513        }
1514
1515        // Update the room with a sync: the user is joining the room.
1516        {
1517            let now = u64::from(now) + 10; // time flies
1518            server
1519                .sync_room(
1520                    &client,
1521                    JoinedRoomBuilder::new(&room_id).add_timeline_event(
1522                        event_factory
1523                            .member(own_user_id)
1524                            .membership(MembershipState::Join)
1525                            .event_id(event_id_1)
1526                            .server_ts(now),
1527                    ),
1528                )
1529                .await;
1530
1531            // The event cache has received its update from the sync. It has emitted a
1532            // generic update, which has been received by `LatestEvents` tasks, up to the
1533            // `compute_latest_events` which has updated the latest event value.
1534            assert_matches!(
1535                latest_event_stream.next().await,
1536                Some(LatestEventValue::Remote(RemoteLatestEventValue { kind: TimelineEventKind::PlainText { event }, .. })) => {
1537                    assert_matches!(
1538                        event.deserialize().unwrap(),
1539                        AnySyncTimelineEvent::State(
1540                            AnySyncStateEvent::RoomMember(
1541                                SyncRoomMemberEvent::Original(event)
1542                            )
1543                        ) => {
1544                            assert_eq!(event.event_id, event_id_1);
1545                            assert_eq!(event.content.membership, MembershipState::Join);
1546                            assert_eq!(event.sender, own_user_id);
1547                            assert_eq!(event.state_key, own_user_id);
1548                            assert_eq!(u64::from(event.origin_server_ts.get()), now);
1549                        }
1550                    );
1551                }
1552            );
1553
1554            assert_pending!(latest_event_stream);
1555        }
1556    }
1557}