matrix_sdk_base/store/
memory_store.rs

1// Copyright 2021 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::{
16    collections::{BTreeMap, BTreeSet, HashMap},
17    sync::RwLock,
18};
19
20use async_trait::async_trait;
21use growable_bloom_filter::GrowableBloom;
22use matrix_sdk_common::{ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK};
23use ruma::{
24    CanonicalJsonObject, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri,
25    OwnedRoomId, OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId,
26    api::client::sync::sync_events::StrippedState,
27    canonical_json::{RedactedBecause, redact},
28    events::{
29        AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnySyncStateEvent,
30        GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType,
31        presence::PresenceEvent,
32        receipt::{Receipt, ReceiptThread, ReceiptType},
33        room::member::{MembershipState, StrippedRoomMemberEvent, SyncRoomMemberEvent},
34    },
35    serde::Raw,
36    time::Instant,
37};
38use tracing::{debug, instrument, warn};
39
40use super::{
41    DependentQueuedRequest, DependentQueuedRequestKind, QueuedRequestKind, Result, RoomInfo,
42    RoomLoadSettings, StateChanges, StateStore, StoreError,
43    send_queue::{ChildTransactionId, QueuedRequest, SentRequestKey},
44    traits::{ComposerDraft, ServerInfo},
45};
46use crate::{
47    MinimalRoomMemberEvent, RoomMemberships, StateStoreDataKey, StateStoreDataValue,
48    deserialized_responses::{DisplayName, RawAnySyncOrStrippedState},
49    store::{QueueWedgeError, ThreadSubscription},
50};
51
52#[derive(Debug, Default)]
53#[allow(clippy::type_complexity)]
54struct MemoryStoreInner {
55    recently_visited_rooms: HashMap<OwnedUserId, Vec<OwnedRoomId>>,
56    composer_drafts: HashMap<(OwnedRoomId, Option<OwnedEventId>), ComposerDraft>,
57    user_avatar_url: HashMap<OwnedUserId, OwnedMxcUri>,
58    sync_token: Option<String>,
59    server_info: Option<ServerInfo>,
60    filters: HashMap<String, String>,
61    utd_hook_manager_data: Option<GrowableBloom>,
62    account_data: HashMap<GlobalAccountDataEventType, Raw<AnyGlobalAccountDataEvent>>,
63    profiles: HashMap<OwnedRoomId, HashMap<OwnedUserId, MinimalRoomMemberEvent>>,
64    display_names: HashMap<OwnedRoomId, HashMap<DisplayName, BTreeSet<OwnedUserId>>>,
65    members: HashMap<OwnedRoomId, HashMap<OwnedUserId, MembershipState>>,
66    room_info: HashMap<OwnedRoomId, RoomInfo>,
67    room_state:
68        HashMap<OwnedRoomId, HashMap<StateEventType, HashMap<String, Raw<AnySyncStateEvent>>>>,
69    room_account_data:
70        HashMap<OwnedRoomId, HashMap<RoomAccountDataEventType, Raw<AnyRoomAccountDataEvent>>>,
71    stripped_room_state:
72        HashMap<OwnedRoomId, HashMap<StateEventType, HashMap<String, Raw<StrippedState>>>>,
73    stripped_members: HashMap<OwnedRoomId, HashMap<OwnedUserId, MembershipState>>,
74    presence: HashMap<OwnedUserId, Raw<PresenceEvent>>,
75    room_user_receipts: HashMap<
76        OwnedRoomId,
77        HashMap<(String, Option<String>), HashMap<OwnedUserId, (OwnedEventId, Receipt)>>,
78    >,
79    room_event_receipts: HashMap<
80        OwnedRoomId,
81        HashMap<(String, Option<String>), HashMap<OwnedEventId, HashMap<OwnedUserId, Receipt>>>,
82    >,
83    custom: HashMap<Vec<u8>, Vec<u8>>,
84    send_queue_events: BTreeMap<OwnedRoomId, Vec<QueuedRequest>>,
85    dependent_send_queue_events: BTreeMap<OwnedRoomId, Vec<DependentQueuedRequest>>,
86    seen_knock_requests: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, OwnedUserId>>,
87    thread_subscriptions: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, ThreadSubscription>>,
88}
89
90/// In-memory, non-persistent implementation of the `StateStore`.
91///
92/// Default if no other is configured at startup.
93#[derive(Debug, Default)]
94pub struct MemoryStore {
95    inner: RwLock<MemoryStoreInner>,
96}
97
98impl MemoryStore {
99    /// Create a new empty MemoryStore
100    pub fn new() -> Self {
101        Self::default()
102    }
103
104    fn get_user_room_receipt_event_impl(
105        &self,
106        room_id: &RoomId,
107        receipt_type: ReceiptType,
108        thread: ReceiptThread,
109        user_id: &UserId,
110    ) -> Option<(OwnedEventId, Receipt)> {
111        self.inner
112            .read()
113            .unwrap()
114            .room_user_receipts
115            .get(room_id)?
116            .get(&(receipt_type.to_string(), thread.as_str().map(ToOwned::to_owned)))?
117            .get(user_id)
118            .cloned()
119    }
120
121    fn get_event_room_receipt_events_impl(
122        &self,
123        room_id: &RoomId,
124        receipt_type: ReceiptType,
125        thread: ReceiptThread,
126        event_id: &EventId,
127    ) -> Option<Vec<(OwnedUserId, Receipt)>> {
128        Some(
129            self.inner
130                .read()
131                .unwrap()
132                .room_event_receipts
133                .get(room_id)?
134                .get(&(receipt_type.to_string(), thread.as_str().map(ToOwned::to_owned)))?
135                .get(event_id)?
136                .iter()
137                .map(|(key, value)| (key.clone(), value.clone()))
138                .collect(),
139        )
140    }
141}
142
143#[cfg_attr(target_family = "wasm", async_trait(?Send))]
144#[cfg_attr(not(target_family = "wasm"), async_trait)]
145impl StateStore for MemoryStore {
146    type Error = StoreError;
147
148    async fn get_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<Option<StateStoreDataValue>> {
149        let inner = self.inner.read().unwrap();
150        Ok(match key {
151            StateStoreDataKey::SyncToken => {
152                inner.sync_token.clone().map(StateStoreDataValue::SyncToken)
153            }
154            StateStoreDataKey::ServerInfo => {
155                inner.server_info.clone().map(StateStoreDataValue::ServerInfo)
156            }
157            StateStoreDataKey::Filter(filter_name) => {
158                inner.filters.get(filter_name).cloned().map(StateStoreDataValue::Filter)
159            }
160            StateStoreDataKey::UserAvatarUrl(user_id) => {
161                inner.user_avatar_url.get(user_id).cloned().map(StateStoreDataValue::UserAvatarUrl)
162            }
163            StateStoreDataKey::RecentlyVisitedRooms(user_id) => inner
164                .recently_visited_rooms
165                .get(user_id)
166                .cloned()
167                .map(StateStoreDataValue::RecentlyVisitedRooms),
168            StateStoreDataKey::UtdHookManagerData => {
169                inner.utd_hook_manager_data.clone().map(StateStoreDataValue::UtdHookManagerData)
170            }
171            StateStoreDataKey::ComposerDraft(room_id, thread_root) => {
172                let key = (room_id.to_owned(), thread_root.map(ToOwned::to_owned));
173                inner.composer_drafts.get(&key).cloned().map(StateStoreDataValue::ComposerDraft)
174            }
175            StateStoreDataKey::SeenKnockRequests(room_id) => inner
176                .seen_knock_requests
177                .get(room_id)
178                .cloned()
179                .map(StateStoreDataValue::SeenKnockRequests),
180        })
181    }
182
183    async fn set_kv_data(
184        &self,
185        key: StateStoreDataKey<'_>,
186        value: StateStoreDataValue,
187    ) -> Result<()> {
188        let mut inner = self.inner.write().unwrap();
189        match key {
190            StateStoreDataKey::SyncToken => {
191                inner.sync_token =
192                    Some(value.into_sync_token().expect("Session data not a sync token"))
193            }
194            StateStoreDataKey::Filter(filter_name) => {
195                inner.filters.insert(
196                    filter_name.to_owned(),
197                    value.into_filter().expect("Session data not a filter"),
198                );
199            }
200            StateStoreDataKey::UserAvatarUrl(user_id) => {
201                inner.user_avatar_url.insert(
202                    user_id.to_owned(),
203                    value.into_user_avatar_url().expect("Session data not a user avatar url"),
204                );
205            }
206            StateStoreDataKey::RecentlyVisitedRooms(user_id) => {
207                inner.recently_visited_rooms.insert(
208                    user_id.to_owned(),
209                    value
210                        .into_recently_visited_rooms()
211                        .expect("Session data not a list of recently visited rooms"),
212                );
213            }
214            StateStoreDataKey::UtdHookManagerData => {
215                inner.utd_hook_manager_data = Some(
216                    value
217                        .into_utd_hook_manager_data()
218                        .expect("Session data not the hook manager data"),
219                );
220            }
221            StateStoreDataKey::ComposerDraft(room_id, thread_root) => {
222                inner.composer_drafts.insert(
223                    (room_id.to_owned(), thread_root.map(ToOwned::to_owned)),
224                    value.into_composer_draft().expect("Session data not a composer draft"),
225                );
226            }
227            StateStoreDataKey::ServerInfo => {
228                inner.server_info = Some(
229                    value.into_server_info().expect("Session data not containing server info"),
230                );
231            }
232            StateStoreDataKey::SeenKnockRequests(room_id) => {
233                inner.seen_knock_requests.insert(
234                    room_id.to_owned(),
235                    value
236                        .into_seen_knock_requests()
237                        .expect("Session data is not a set of seen join request ids"),
238                );
239            }
240        }
241
242        Ok(())
243    }
244
245    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<()> {
246        let mut inner = self.inner.write().unwrap();
247        match key {
248            StateStoreDataKey::SyncToken => inner.sync_token = None,
249            StateStoreDataKey::ServerInfo => inner.server_info = None,
250            StateStoreDataKey::Filter(filter_name) => {
251                inner.filters.remove(filter_name);
252            }
253            StateStoreDataKey::UserAvatarUrl(user_id) => {
254                inner.user_avatar_url.remove(user_id);
255            }
256            StateStoreDataKey::RecentlyVisitedRooms(user_id) => {
257                inner.recently_visited_rooms.remove(user_id);
258            }
259            StateStoreDataKey::UtdHookManagerData => inner.utd_hook_manager_data = None,
260            StateStoreDataKey::ComposerDraft(room_id, thread_root) => {
261                let key = (room_id.to_owned(), thread_root.map(ToOwned::to_owned));
262                inner.composer_drafts.remove(&key);
263            }
264            StateStoreDataKey::SeenKnockRequests(room_id) => {
265                inner.seen_knock_requests.remove(room_id);
266            }
267        }
268        Ok(())
269    }
270
271    #[instrument(skip(self, changes))]
272    async fn save_changes(&self, changes: &StateChanges) -> Result<()> {
273        let now = Instant::now();
274
275        let mut inner = self.inner.write().unwrap();
276
277        if let Some(s) = &changes.sync_token {
278            inner.sync_token = Some(s.to_owned());
279        }
280
281        for (room, users) in &changes.profiles_to_delete {
282            let Some(room_profiles) = inner.profiles.get_mut(room) else {
283                continue;
284            };
285            for user in users {
286                room_profiles.remove(user);
287            }
288        }
289
290        for (room, users) in &changes.profiles {
291            for (user_id, profile) in users {
292                inner
293                    .profiles
294                    .entry(room.clone())
295                    .or_default()
296                    .insert(user_id.clone(), profile.clone());
297            }
298        }
299
300        for (room, map) in &changes.ambiguity_maps {
301            for (display_name, display_names) in map {
302                inner
303                    .display_names
304                    .entry(room.clone())
305                    .or_default()
306                    .insert(display_name.clone(), display_names.clone());
307            }
308        }
309
310        for (event_type, event) in &changes.account_data {
311            inner.account_data.insert(event_type.clone(), event.clone());
312        }
313
314        for (room, events) in &changes.room_account_data {
315            for (event_type, event) in events {
316                inner
317                    .room_account_data
318                    .entry(room.clone())
319                    .or_default()
320                    .insert(event_type.clone(), event.clone());
321            }
322        }
323
324        for (room, event_types) in &changes.state {
325            for (event_type, events) in event_types {
326                for (state_key, raw_event) in events {
327                    inner
328                        .room_state
329                        .entry(room.clone())
330                        .or_default()
331                        .entry(event_type.clone())
332                        .or_default()
333                        .insert(state_key.to_owned(), raw_event.clone());
334                    inner.stripped_room_state.remove(room);
335
336                    if *event_type == StateEventType::RoomMember {
337                        let event =
338                            match raw_event.deserialize_as_unchecked::<SyncRoomMemberEvent>() {
339                                Ok(ev) => ev,
340                                Err(e) => {
341                                    let event_id: Option<String> =
342                                        raw_event.get_field("event_id").ok().flatten();
343                                    debug!(event_id, "Failed to deserialize member event: {e}");
344                                    continue;
345                                }
346                            };
347
348                        inner.stripped_members.remove(room);
349
350                        inner
351                            .members
352                            .entry(room.clone())
353                            .or_default()
354                            .insert(event.state_key().to_owned(), event.membership().clone());
355                    }
356                }
357            }
358        }
359
360        for (room_id, info) in &changes.room_infos {
361            inner.room_info.insert(room_id.clone(), info.clone());
362        }
363
364        for (sender, event) in &changes.presence {
365            inner.presence.insert(sender.clone(), event.clone());
366        }
367
368        for (room, event_types) in &changes.stripped_state {
369            for (event_type, events) in event_types {
370                for (state_key, raw_event) in events {
371                    inner
372                        .stripped_room_state
373                        .entry(room.clone())
374                        .or_default()
375                        .entry(event_type.clone())
376                        .or_default()
377                        .insert(state_key.to_owned(), raw_event.clone());
378
379                    if *event_type == StateEventType::RoomMember {
380                        let event =
381                            match raw_event.deserialize_as_unchecked::<StrippedRoomMemberEvent>() {
382                                Ok(ev) => ev,
383                                Err(e) => {
384                                    let event_id: Option<String> =
385                                        raw_event.get_field("event_id").ok().flatten();
386                                    debug!(
387                                        event_id,
388                                        "Failed to deserialize stripped member event: {e}"
389                                    );
390                                    continue;
391                                }
392                            };
393
394                        inner
395                            .stripped_members
396                            .entry(room.clone())
397                            .or_default()
398                            .insert(event.state_key, event.content.membership.clone());
399                    }
400                }
401            }
402        }
403
404        for (room, content) in &changes.receipts {
405            for (event_id, receipts) in &content.0 {
406                for (receipt_type, receipts) in receipts {
407                    for (user_id, receipt) in receipts {
408                        let thread = receipt.thread.as_str().map(ToOwned::to_owned);
409                        // Add the receipt to the room user receipts
410                        if let Some((old_event, _)) = inner
411                            .room_user_receipts
412                            .entry(room.clone())
413                            .or_default()
414                            .entry((receipt_type.to_string(), thread.clone()))
415                            .or_default()
416                            .insert(user_id.clone(), (event_id.clone(), receipt.clone()))
417                        {
418                            // Remove the old receipt from the room event receipts
419                            if let Some(receipt_map) = inner.room_event_receipts.get_mut(room)
420                                && let Some(event_map) =
421                                    receipt_map.get_mut(&(receipt_type.to_string(), thread.clone()))
422                                && let Some(user_map) = event_map.get_mut(&old_event)
423                            {
424                                user_map.remove(user_id);
425                            }
426                        }
427
428                        // Add the receipt to the room event receipts
429                        inner
430                            .room_event_receipts
431                            .entry(room.clone())
432                            .or_default()
433                            .entry((receipt_type.to_string(), thread))
434                            .or_default()
435                            .entry(event_id.clone())
436                            .or_default()
437                            .insert(user_id.clone(), receipt.clone());
438                    }
439                }
440            }
441        }
442
443        let make_redaction_rules = |room_info: &HashMap<OwnedRoomId, RoomInfo>, room_id| {
444            room_info.get(room_id).map(|info| info.room_version_rules_or_default()).unwrap_or_else(|| {
445                warn!(
446                    ?room_id,
447                    "Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}"
448                );
449                ROOM_VERSION_RULES_FALLBACK
450            }).redaction
451        };
452
453        let inner = &mut *inner;
454        for (room_id, redactions) in &changes.redactions {
455            let mut redaction_rules = None;
456
457            if let Some(room) = inner.room_state.get_mut(room_id) {
458                for ref_room_mu in room.values_mut() {
459                    for raw_evt in ref_room_mu.values_mut() {
460                        if let Ok(Some(event_id)) = raw_evt.get_field::<OwnedEventId>("event_id")
461                            && let Some(redaction) = redactions.get(&event_id)
462                        {
463                            let redacted = redact(
464                                raw_evt.deserialize_as::<CanonicalJsonObject>()?,
465                                redaction_rules.get_or_insert_with(|| {
466                                    make_redaction_rules(&inner.room_info, room_id)
467                                }),
468                                Some(RedactedBecause::from_raw_event(redaction)?),
469                            )
470                            .map_err(StoreError::Redaction)?;
471                            *raw_evt = Raw::new(&redacted)?.cast_unchecked();
472                        }
473                    }
474                }
475            }
476        }
477
478        debug!("Saved changes in {:?}", now.elapsed());
479
480        Ok(())
481    }
482
483    async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
484        Ok(self.inner.read().unwrap().presence.get(user_id).cloned())
485    }
486
487    async fn get_presence_events(
488        &self,
489        user_ids: &[OwnedUserId],
490    ) -> Result<Vec<Raw<PresenceEvent>>> {
491        let presence = &self.inner.read().unwrap().presence;
492        Ok(user_ids.iter().filter_map(|user_id| presence.get(user_id).cloned()).collect())
493    }
494
495    async fn get_state_event(
496        &self,
497        room_id: &RoomId,
498        event_type: StateEventType,
499        state_key: &str,
500    ) -> Result<Option<RawAnySyncOrStrippedState>> {
501        Ok(self
502            .get_state_events_for_keys(room_id, event_type, &[state_key])
503            .await?
504            .into_iter()
505            .next())
506    }
507
508    async fn get_state_events(
509        &self,
510        room_id: &RoomId,
511        event_type: StateEventType,
512    ) -> Result<Vec<RawAnySyncOrStrippedState>> {
513        fn get_events<T>(
514            state_map: &HashMap<OwnedRoomId, HashMap<StateEventType, HashMap<String, Raw<T>>>>,
515            room_id: &RoomId,
516            event_type: &StateEventType,
517            to_enum: fn(Raw<T>) -> RawAnySyncOrStrippedState,
518        ) -> Option<Vec<RawAnySyncOrStrippedState>> {
519            let state_events = state_map.get(room_id)?.get(event_type)?;
520            Some(state_events.values().cloned().map(to_enum).collect())
521        }
522
523        let inner = self.inner.read().unwrap();
524        Ok(get_events(
525            &inner.stripped_room_state,
526            room_id,
527            &event_type,
528            RawAnySyncOrStrippedState::Stripped,
529        )
530        .or_else(|| {
531            get_events(&inner.room_state, room_id, &event_type, RawAnySyncOrStrippedState::Sync)
532        })
533        .unwrap_or_default())
534    }
535
536    async fn get_state_events_for_keys(
537        &self,
538        room_id: &RoomId,
539        event_type: StateEventType,
540        state_keys: &[&str],
541    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
542        let inner = self.inner.read().unwrap();
543
544        if let Some(stripped_state_events) =
545            inner.stripped_room_state.get(room_id).and_then(|events| events.get(&event_type))
546        {
547            Ok(state_keys
548                .iter()
549                .filter_map(|k| {
550                    stripped_state_events
551                        .get(*k)
552                        .map(|e| RawAnySyncOrStrippedState::Stripped(e.clone()))
553                })
554                .collect())
555        } else if let Some(sync_state_events) =
556            inner.room_state.get(room_id).and_then(|events| events.get(&event_type))
557        {
558            Ok(state_keys
559                .iter()
560                .filter_map(|k| {
561                    sync_state_events.get(*k).map(|e| RawAnySyncOrStrippedState::Sync(e.clone()))
562                })
563                .collect())
564        } else {
565            Ok(Vec::new())
566        }
567    }
568
569    async fn get_profile(
570        &self,
571        room_id: &RoomId,
572        user_id: &UserId,
573    ) -> Result<Option<MinimalRoomMemberEvent>> {
574        Ok(self
575            .inner
576            .read()
577            .unwrap()
578            .profiles
579            .get(room_id)
580            .and_then(|room_profiles| room_profiles.get(user_id))
581            .cloned())
582    }
583
584    async fn get_profiles<'a>(
585        &self,
586        room_id: &RoomId,
587        user_ids: &'a [OwnedUserId],
588    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>> {
589        if user_ids.is_empty() {
590            return Ok(BTreeMap::new());
591        }
592
593        let profiles = &self.inner.read().unwrap().profiles;
594        let Some(room_profiles) = profiles.get(room_id) else {
595            return Ok(BTreeMap::new());
596        };
597
598        Ok(user_ids
599            .iter()
600            .filter_map(|user_id| room_profiles.get(user_id).map(|p| (&**user_id, p.clone())))
601            .collect())
602    }
603
604    #[instrument(skip(self, memberships))]
605    async fn get_user_ids(
606        &self,
607        room_id: &RoomId,
608        memberships: RoomMemberships,
609    ) -> Result<Vec<OwnedUserId>> {
610        /// Get the user IDs for the given room with the given memberships and
611        /// stripped state.
612        ///
613        /// If `memberships` is empty, returns all user IDs in the room with the
614        /// given stripped state.
615        fn get_user_ids_inner(
616            members: &HashMap<OwnedRoomId, HashMap<OwnedUserId, MembershipState>>,
617            room_id: &RoomId,
618            memberships: RoomMemberships,
619        ) -> Vec<OwnedUserId> {
620            members
621                .get(room_id)
622                .map(|members| {
623                    members
624                        .iter()
625                        .filter_map(|(user_id, membership)| {
626                            memberships.matches(membership).then_some(user_id)
627                        })
628                        .cloned()
629                        .collect()
630                })
631                .unwrap_or_default()
632        }
633        let inner = self.inner.read().unwrap();
634        let v = get_user_ids_inner(&inner.stripped_members, room_id, memberships);
635        if !v.is_empty() {
636            return Ok(v);
637        }
638        Ok(get_user_ids_inner(&inner.members, room_id, memberships))
639    }
640
641    async fn get_room_infos(&self, room_load_settings: &RoomLoadSettings) -> Result<Vec<RoomInfo>> {
642        let memory_store_inner = self.inner.read().unwrap();
643        let room_infos = &memory_store_inner.room_info;
644
645        Ok(match room_load_settings {
646            RoomLoadSettings::All => room_infos.values().cloned().collect(),
647
648            RoomLoadSettings::One(room_id) => match room_infos.get(room_id) {
649                Some(room_info) => vec![room_info.clone()],
650                None => vec![],
651            },
652        })
653    }
654
655    async fn get_users_with_display_name(
656        &self,
657        room_id: &RoomId,
658        display_name: &DisplayName,
659    ) -> Result<BTreeSet<OwnedUserId>> {
660        Ok(self
661            .inner
662            .read()
663            .unwrap()
664            .display_names
665            .get(room_id)
666            .and_then(|room_names| room_names.get(display_name).cloned())
667            .unwrap_or_default())
668    }
669
670    async fn get_users_with_display_names<'a>(
671        &self,
672        room_id: &RoomId,
673        display_names: &'a [DisplayName],
674    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>> {
675        if display_names.is_empty() {
676            return Ok(HashMap::new());
677        }
678
679        let inner = self.inner.read().unwrap();
680        let Some(room_names) = inner.display_names.get(room_id) else {
681            return Ok(HashMap::new());
682        };
683
684        Ok(display_names.iter().filter_map(|n| room_names.get(n).map(|d| (n, d.clone()))).collect())
685    }
686
687    async fn get_account_data_event(
688        &self,
689        event_type: GlobalAccountDataEventType,
690    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>> {
691        Ok(self.inner.read().unwrap().account_data.get(&event_type).cloned())
692    }
693
694    async fn get_room_account_data_event(
695        &self,
696        room_id: &RoomId,
697        event_type: RoomAccountDataEventType,
698    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>> {
699        Ok(self
700            .inner
701            .read()
702            .unwrap()
703            .room_account_data
704            .get(room_id)
705            .and_then(|m| m.get(&event_type))
706            .cloned())
707    }
708
709    async fn get_user_room_receipt_event(
710        &self,
711        room_id: &RoomId,
712        receipt_type: ReceiptType,
713        thread: ReceiptThread,
714        user_id: &UserId,
715    ) -> Result<Option<(OwnedEventId, Receipt)>> {
716        Ok(self.get_user_room_receipt_event_impl(room_id, receipt_type, thread, user_id))
717    }
718
719    async fn get_event_room_receipt_events(
720        &self,
721        room_id: &RoomId,
722        receipt_type: ReceiptType,
723        thread: ReceiptThread,
724        event_id: &EventId,
725    ) -> Result<Vec<(OwnedUserId, Receipt)>> {
726        Ok(self
727            .get_event_room_receipt_events_impl(room_id, receipt_type, thread, event_id)
728            .unwrap_or_default())
729    }
730
731    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
732        Ok(self.inner.read().unwrap().custom.get(key).cloned())
733    }
734
735    async fn set_custom_value(&self, key: &[u8], value: Vec<u8>) -> Result<Option<Vec<u8>>> {
736        Ok(self.inner.write().unwrap().custom.insert(key.to_vec(), value))
737    }
738
739    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
740        Ok(self.inner.write().unwrap().custom.remove(key))
741    }
742
743    async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
744        let mut inner = self.inner.write().unwrap();
745
746        inner.profiles.remove(room_id);
747        inner.display_names.remove(room_id);
748        inner.members.remove(room_id);
749        inner.room_info.remove(room_id);
750        inner.room_state.remove(room_id);
751        inner.room_account_data.remove(room_id);
752        inner.stripped_room_state.remove(room_id);
753        inner.stripped_members.remove(room_id);
754        inner.room_user_receipts.remove(room_id);
755        inner.room_event_receipts.remove(room_id);
756        inner.send_queue_events.remove(room_id);
757        inner.dependent_send_queue_events.remove(room_id);
758        inner.thread_subscriptions.remove(room_id);
759
760        Ok(())
761    }
762
763    async fn save_send_queue_request(
764        &self,
765        room_id: &RoomId,
766        transaction_id: OwnedTransactionId,
767        created_at: MilliSecondsSinceUnixEpoch,
768        kind: QueuedRequestKind,
769        priority: usize,
770    ) -> Result<(), Self::Error> {
771        self.inner
772            .write()
773            .unwrap()
774            .send_queue_events
775            .entry(room_id.to_owned())
776            .or_default()
777            .push(QueuedRequest { kind, transaction_id, error: None, priority, created_at });
778        Ok(())
779    }
780
781    async fn update_send_queue_request(
782        &self,
783        room_id: &RoomId,
784        transaction_id: &TransactionId,
785        kind: QueuedRequestKind,
786    ) -> Result<bool, Self::Error> {
787        if let Some(entry) = self
788            .inner
789            .write()
790            .unwrap()
791            .send_queue_events
792            .entry(room_id.to_owned())
793            .or_default()
794            .iter_mut()
795            .find(|item| item.transaction_id == transaction_id)
796        {
797            entry.kind = kind;
798            entry.error = None;
799            Ok(true)
800        } else {
801            Ok(false)
802        }
803    }
804
805    async fn remove_send_queue_request(
806        &self,
807        room_id: &RoomId,
808        transaction_id: &TransactionId,
809    ) -> Result<bool, Self::Error> {
810        let mut inner = self.inner.write().unwrap();
811        let q = &mut inner.send_queue_events;
812
813        let entry = q.get_mut(room_id);
814        if let Some(entry) = entry {
815            // Find the event by id in its room queue, and remove it if present.
816            if let Some(pos) = entry.iter().position(|item| item.transaction_id == transaction_id) {
817                entry.remove(pos);
818                // And if this was the last event before removal, remove the entire room entry.
819                if entry.is_empty() {
820                    q.remove(room_id);
821                }
822                return Ok(true);
823            }
824        }
825
826        Ok(false)
827    }
828
829    async fn load_send_queue_requests(
830        &self,
831        room_id: &RoomId,
832    ) -> Result<Vec<QueuedRequest>, Self::Error> {
833        let mut ret = self
834            .inner
835            .write()
836            .unwrap()
837            .send_queue_events
838            .entry(room_id.to_owned())
839            .or_default()
840            .clone();
841        // Inverted order of priority, use stable sort to keep insertion order.
842        ret.sort_by(|lhs, rhs| rhs.priority.cmp(&lhs.priority));
843        Ok(ret)
844    }
845
846    async fn update_send_queue_request_status(
847        &self,
848        room_id: &RoomId,
849        transaction_id: &TransactionId,
850        error: Option<QueueWedgeError>,
851    ) -> Result<(), Self::Error> {
852        if let Some(entry) = self
853            .inner
854            .write()
855            .unwrap()
856            .send_queue_events
857            .entry(room_id.to_owned())
858            .or_default()
859            .iter_mut()
860            .find(|item| item.transaction_id == transaction_id)
861        {
862            entry.error = error;
863        }
864        Ok(())
865    }
866
867    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
868        Ok(self.inner.read().unwrap().send_queue_events.keys().cloned().collect())
869    }
870
871    async fn save_dependent_queued_request(
872        &self,
873        room: &RoomId,
874        parent_transaction_id: &TransactionId,
875        own_transaction_id: ChildTransactionId,
876        created_at: MilliSecondsSinceUnixEpoch,
877        content: DependentQueuedRequestKind,
878    ) -> Result<(), Self::Error> {
879        self.inner
880            .write()
881            .unwrap()
882            .dependent_send_queue_events
883            .entry(room.to_owned())
884            .or_default()
885            .push(DependentQueuedRequest {
886                kind: content,
887                parent_transaction_id: parent_transaction_id.to_owned(),
888                own_transaction_id,
889                parent_key: None,
890                created_at,
891            });
892        Ok(())
893    }
894
895    async fn mark_dependent_queued_requests_as_ready(
896        &self,
897        room: &RoomId,
898        parent_txn_id: &TransactionId,
899        sent_parent_key: SentRequestKey,
900    ) -> Result<usize, Self::Error> {
901        let mut inner = self.inner.write().unwrap();
902        let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
903        let mut num_updated = 0;
904        for d in dependents.iter_mut().filter(|item| item.parent_transaction_id == parent_txn_id) {
905            d.parent_key = Some(sent_parent_key.clone());
906            num_updated += 1;
907        }
908        Ok(num_updated)
909    }
910
911    async fn update_dependent_queued_request(
912        &self,
913        room: &RoomId,
914        own_transaction_id: &ChildTransactionId,
915        new_content: DependentQueuedRequestKind,
916    ) -> Result<bool, Self::Error> {
917        let mut inner = self.inner.write().unwrap();
918        let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
919        for d in dependents.iter_mut() {
920            if d.own_transaction_id == *own_transaction_id {
921                d.kind = new_content;
922                return Ok(true);
923            }
924        }
925        Ok(false)
926    }
927
928    async fn remove_dependent_queued_request(
929        &self,
930        room: &RoomId,
931        txn_id: &ChildTransactionId,
932    ) -> Result<bool, Self::Error> {
933        let mut inner = self.inner.write().unwrap();
934        let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
935        if let Some(pos) = dependents.iter().position(|item| item.own_transaction_id == *txn_id) {
936            dependents.remove(pos);
937            Ok(true)
938        } else {
939            Ok(false)
940        }
941    }
942
943    async fn load_dependent_queued_requests(
944        &self,
945        room: &RoomId,
946    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
947        Ok(self
948            .inner
949            .read()
950            .unwrap()
951            .dependent_send_queue_events
952            .get(room)
953            .cloned()
954            .unwrap_or_default())
955    }
956
957    async fn upsert_thread_subscription(
958        &self,
959        room: &RoomId,
960        thread_id: &EventId,
961        subscription: ThreadSubscription,
962    ) -> Result<(), Self::Error> {
963        self.inner
964            .write()
965            .unwrap()
966            .thread_subscriptions
967            .entry(room.to_owned())
968            .or_default()
969            .insert(thread_id.to_owned(), subscription);
970        Ok(())
971    }
972
973    async fn load_thread_subscription(
974        &self,
975        room: &RoomId,
976        thread_id: &EventId,
977    ) -> Result<Option<ThreadSubscription>, Self::Error> {
978        let inner = self.inner.read().unwrap();
979        Ok(inner
980            .thread_subscriptions
981            .get(room)
982            .and_then(|subscriptions| subscriptions.get(thread_id))
983            .copied())
984    }
985
986    async fn remove_thread_subscription(
987        &self,
988        room: &RoomId,
989        thread_id: &EventId,
990    ) -> Result<(), Self::Error> {
991        let mut inner = self.inner.write().unwrap();
992
993        let Some(room_subs) = inner.thread_subscriptions.get_mut(room) else {
994            return Ok(());
995        };
996
997        room_subs.remove(thread_id);
998
999        if room_subs.is_empty() {
1000            // If there are no more subscriptions for this room, remove the room entry.
1001            inner.thread_subscriptions.remove(room);
1002        }
1003
1004        Ok(())
1005    }
1006}
1007
1008#[cfg(test)]
1009mod tests {
1010    use super::{MemoryStore, Result, StateStore};
1011
1012    async fn get_store() -> Result<impl StateStore> {
1013        Ok(MemoryStore::new())
1014    }
1015
1016    statestore_integration_tests!();
1017}