Skip to main content

matrix_sdk/event_cache/caches/room/
updates.rs

1// Copyright 2026 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
15use std::collections::BTreeMap;
16
17use matrix_sdk_base::{
18    deserialized_responses::AmbiguityChange,
19    event_cache::{Event, Gap},
20    linked_chunk::{self, OwnedLinkedChunkId},
21};
22use ruma::{
23    OwnedEventId, OwnedMxcUri, OwnedRoomId, OwnedUserId, events::AnySyncEphemeralRoomEvent,
24    serde::Raw,
25};
26use tokio::sync::broadcast::{Receiver, Sender};
27
28use super::super::TimelineVectorDiffs;
29
30/// An update related to events happened in a room.
31#[derive(Debug, Clone)]
32pub enum RoomEventCacheUpdate {
33    /// The fully read marker has moved to a different event.
34    MoveReadMarkerTo {
35        /// Event at which the read marker is now pointing.
36        event_id: OwnedEventId,
37    },
38
39    /// The members have changed.
40    UpdateMembers {
41        /// Collection of ambiguity changes that room member events trigger.
42        ///
43        /// This is a map of event ID of the `m.room.member` event to the
44        /// details of the ambiguity change.
45        ambiguity_changes: BTreeMap<OwnedEventId, AmbiguityChange>,
46
47        /// Collection of avatar changes that room member events trigger.
48        avatar_changes: Option<BTreeMap<OwnedUserId, Option<OwnedMxcUri>>>,
49    },
50
51    /// The room has received updates for the timeline as _diffs_.
52    UpdateTimelineEvents(TimelineVectorDiffs),
53
54    /// The room has received new ephemeral events.
55    AddEphemeralEvents {
56        /// XXX: this is temporary, until read receipts are handled in the event
57        /// cache
58        events: Vec<Raw<AnySyncEphemeralRoomEvent>>,
59    },
60}
61
62/// Represents a timeline update of a room. It hides the details of
63/// [`RoomEventCacheUpdate`] by being more generic.
64///
65/// This is used by [`EventCache::subscribe_to_room_generic_updates`][0]. Please
66/// read it to learn more about the motivation behind this type.
67///
68/// [0]: super::super::super::EventCache::subscribe_to_room_generic_updates
69#[derive(Clone, Debug)]
70pub struct RoomEventCacheGenericUpdate {
71    /// The room ID owning the timeline.
72    pub room_id: OwnedRoomId,
73}
74
75/// An update being triggered when events change in the persisted event cache
76/// for any room.
77#[derive(Clone, Debug)]
78pub struct RoomEventCacheLinkedChunkUpdate {
79    /// The linked chunk affected by the update.
80    pub linked_chunk_id: OwnedLinkedChunkId,
81
82    /// A vector of all the linked chunk updates that happened during this event
83    /// cache update.
84    pub updates: Vec<linked_chunk::Update<Event, Gap>>,
85}
86
87impl RoomEventCacheLinkedChunkUpdate {
88    /// Return all the new events propagated by this update, in topological
89    /// order.
90    pub fn events(self) -> impl DoubleEndedIterator<Item = Event> {
91        use itertools::Either;
92        self.updates.into_iter().flat_map(|update| match update {
93            linked_chunk::Update::PushItems { items, .. } => {
94                Either::Left(Either::Left(items.into_iter()))
95            }
96            linked_chunk::Update::ReplaceItem { item, .. } => {
97                Either::Left(Either::Right(std::iter::once(item)))
98            }
99            linked_chunk::Update::RemoveItem { .. }
100            | linked_chunk::Update::DetachLastItems { .. }
101            | linked_chunk::Update::StartReattachItems
102            | linked_chunk::Update::EndReattachItems
103            | linked_chunk::Update::NewItemsChunk { .. }
104            | linked_chunk::Update::NewGapChunk { .. }
105            | linked_chunk::Update::RemoveChunk(..)
106            | linked_chunk::Update::Clear => {
107                // All these updates don't contain any new event.
108                Either::Right(std::iter::empty())
109            }
110        })
111    }
112}
113
114/// A small type to send updates in all channels.
115#[derive(Clone)]
116pub struct RoomEventCacheUpdateSender {
117    room_sender: Sender<RoomEventCacheUpdate>,
118    generic_sender: Sender<RoomEventCacheGenericUpdate>,
119}
120
121impl RoomEventCacheUpdateSender {
122    /// Create a new [`RoomEventCacheUpdateSender`].
123    pub fn new(generic_sender: Sender<RoomEventCacheGenericUpdate>) -> Self {
124        Self { room_sender: Sender::new(32), generic_sender }
125    }
126
127    /// Send a [`RoomEventCacheUpdate`] and an optional
128    /// [`RoomEventCacheGenericUpdate`].
129    pub fn send(
130        &self,
131        room_update: RoomEventCacheUpdate,
132        generic_update: Option<RoomEventCacheGenericUpdate>,
133    ) {
134        let _ = self.room_sender.send(room_update);
135
136        if let Some(generic_update) = generic_update {
137            let _ = self.generic_sender.send(generic_update);
138        }
139    }
140
141    /// Create a new [`Receiver`] of [`RoomEventCacheUpdate`].
142    pub(super) fn new_room_receiver(&self) -> Receiver<RoomEventCacheUpdate> {
143        self.room_sender.subscribe()
144    }
145}