Skip to main content

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