Skip to main content

matrix_sdk_base/store/
traits.rs

1// Copyright 2023 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    borrow::Borrow,
17    collections::{BTreeMap, BTreeSet, HashMap},
18    fmt,
19    ops::Deref,
20    sync::Arc,
21};
22
23use as_variant::as_variant;
24use async_trait::async_trait;
25use growable_bloom_filter::GrowableBloom;
26use matrix_sdk_common::{AsyncTraitDeps, ttl::TtlValue};
27use ruma::{
28    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId,
29    OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId,
30    api::{
31        MatrixVersion, SupportedVersions,
32        client::{
33            discovery::{
34                discover_homeserver::{self, HomeserverInfo, IdentityServerInfo, TileServerInfo},
35                get_capabilities::v3::Capabilities,
36            },
37            rtc::RtcTransport,
38        },
39    },
40    events::{
41        AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, EmptyStateKey, GlobalAccountDataEvent,
42        GlobalAccountDataEventContent, GlobalAccountDataEventType, RedactContent,
43        RedactedStateEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
44        RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
45        presence::PresenceEvent,
46        receipt::{Receipt, ReceiptThread, ReceiptType},
47    },
48    profile::UserProfile,
49    serde::Raw,
50};
51use serde::{Deserialize, Serialize};
52use thiserror::Error;
53use tokio::sync::{Mutex, MutexGuard};
54
55use super::{
56    ChildTransactionId, DependentQueuedRequest, DependentQueuedRequestKind, QueueWedgeError,
57    QueuedRequest, QueuedRequestKind, RoomLoadSettings, StateChanges, StoreError,
58    send_queue::SentRequestKey,
59};
60use crate::{
61    MinimalRoomMemberEvent, RoomInfo, RoomMemberships,
62    deserialized_responses::{
63        DisplayName, RawAnySyncOrStrippedState, RawMemberEvent, RawSyncOrStrippedState,
64    },
65    store::StoredThreadSubscription,
66};
67
68/// An abstract state store trait that can be used to implement different stores
69/// for the SDK.
70#[cfg_attr(target_family = "wasm", async_trait(?Send))]
71#[cfg_attr(not(target_family = "wasm"), async_trait)]
72pub trait StateStore: AsyncTraitDeps {
73    /// The error type used by this state store.
74    type Error: fmt::Debug + Into<StoreError> + From<serde_json::Error>;
75
76    /// Get key-value data from the store.
77    ///
78    /// # Arguments
79    ///
80    /// * `key` - The key to fetch data for.
81    async fn get_kv_data(
82        &self,
83        key: StateStoreDataKey<'_>,
84    ) -> Result<Option<StateStoreDataValue>, Self::Error>;
85
86    /// Put key-value data into the store.
87    ///
88    /// # Arguments
89    ///
90    /// * `key` - The key to identify the data in the store.
91    ///
92    /// * `value` - The data to insert.
93    ///
94    /// Panics if the key and value variants do not match.
95    async fn set_kv_data(
96        &self,
97        key: StateStoreDataKey<'_>,
98        value: StateStoreDataValue,
99    ) -> Result<(), Self::Error>;
100
101    /// Remove key-value data from the store.
102    ///
103    /// # Arguments
104    ///
105    /// * `key` - The key to remove the data for.
106    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error>;
107
108    /// Save the set of state changes in the store.
109    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error>;
110
111    /// Get the stored presence event for the given user.
112    ///
113    /// # Arguments
114    ///
115    /// * `user_id` - The id of the user for which we wish to fetch the presence
116    /// event for.
117    async fn get_presence_event(
118        &self,
119        user_id: &UserId,
120    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error>;
121
122    /// Get the stored presence events for the given users.
123    ///
124    /// # Arguments
125    ///
126    /// * `user_ids` - The IDs of the users to fetch the presence events for.
127    async fn get_presence_events(
128        &self,
129        user_ids: &[OwnedUserId],
130    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error>;
131
132    /// Get a state event out of the state store.
133    ///
134    /// # Arguments
135    ///
136    /// * `room_id` - The id of the room the state event was received for.
137    ///
138    /// * `event_type` - The event type of the state event.
139    async fn get_state_event(
140        &self,
141        room_id: &RoomId,
142        event_type: StateEventType,
143        state_key: &str,
144    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error>;
145
146    /// Get a list of state events for a given room and `StateEventType`.
147    ///
148    /// # Arguments
149    ///
150    /// * `room_id` - The id of the room to find events for.
151    ///
152    /// * `event_type` - The event type.
153    async fn get_state_events(
154        &self,
155        room_id: &RoomId,
156        event_type: StateEventType,
157    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
158
159    /// Get a list of state events for a given room, `StateEventType`, and the
160    /// given state keys.
161    ///
162    /// # Arguments
163    ///
164    /// * `room_id` - The id of the room to find events for.
165    ///
166    /// * `event_type` - The event type.
167    ///
168    /// * `state_keys` - The list of state keys to find.
169    async fn get_state_events_for_keys(
170        &self,
171        room_id: &RoomId,
172        event_type: StateEventType,
173        state_keys: &[&str],
174    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
175
176    /// Get the current profile for the given user in the given room.
177    ///
178    /// # Arguments
179    ///
180    /// * `room_id` - The room id the profile is used in.
181    ///
182    /// * `user_id` - The id of the user the profile belongs to.
183    async fn get_profile(
184        &self,
185        room_id: &RoomId,
186        user_id: &UserId,
187    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error>;
188
189    /// Get the current profiles for the given users in the given room.
190    ///
191    /// # Arguments
192    ///
193    /// * `room_id` - The ID of the room the profiles are used in.
194    ///
195    /// * `user_ids` - The IDs of the users the profiles belong to.
196    async fn get_profiles<'a>(
197        &self,
198        room_id: &RoomId,
199        user_ids: &'a [OwnedUserId],
200    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error>;
201
202    /// Get the user ids of members for a given room with the given memberships,
203    /// for stripped and regular rooms alike.
204    async fn get_user_ids(
205        &self,
206        room_id: &RoomId,
207        memberships: RoomMemberships,
208    ) -> Result<Vec<OwnedUserId>, Self::Error>;
209
210    /// Get a set of pure `RoomInfo`s the store knows about.
211    async fn get_room_infos(
212        &self,
213        room_load_settings: &RoomLoadSettings,
214    ) -> Result<Vec<RoomInfo>, Self::Error>;
215
216    /// Get all the users that use the given display name in the given room.
217    ///
218    /// # Arguments
219    ///
220    /// * `room_id` - The id of the room for which the display name users should
221    /// be fetched for.
222    ///
223    /// * `display_name` - The display name that the users use.
224    async fn get_users_with_display_name(
225        &self,
226        room_id: &RoomId,
227        display_name: &DisplayName,
228    ) -> Result<BTreeSet<OwnedUserId>, Self::Error>;
229
230    /// Get all the users that use the given display names in the given room.
231    ///
232    /// # Arguments
233    ///
234    /// * `room_id` - The ID of the room to fetch the display names for.
235    ///
236    /// * `display_names` - The display names that the users use.
237    async fn get_users_with_display_names<'a>(
238        &self,
239        room_id: &RoomId,
240        display_names: &'a [DisplayName],
241    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error>;
242
243    /// Get an event out of the account data store.
244    ///
245    /// # Arguments
246    ///
247    /// * `event_type` - The event type of the account data event.
248    async fn get_account_data_event(
249        &self,
250        event_type: GlobalAccountDataEventType,
251    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error>;
252
253    /// Get an event out of the room account data store.
254    ///
255    /// # Arguments
256    ///
257    /// * `room_id` - The id of the room for which the room account data event
258    ///   should
259    /// be fetched.
260    ///
261    /// * `event_type` - The event type of the room account data event.
262    async fn get_room_account_data_event(
263        &self,
264        room_id: &RoomId,
265        event_type: RoomAccountDataEventType,
266    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error>;
267
268    /// Get a user's read receipt for a given room and receipt type and thread.
269    ///
270    /// # Arguments
271    ///
272    /// * `room_id` - The id of the room for which the receipt should be
273    ///   fetched.
274    ///
275    /// * `receipt_type` - The type of the receipt.
276    ///
277    /// * `receipt_thread` - The thread a receipt applies to.
278    ///
279    /// * `user_id` - The id of the user for whom the receipt should be fetched.
280    async fn get_user_room_receipt_event(
281        &self,
282        room_id: &RoomId,
283        receipt_type: ReceiptType,
284        receipt_thread: &ReceiptThread,
285        user_id: &UserId,
286    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error>;
287
288    /// Get an event's read receipts for a given room, receipt type, and thread.
289    ///
290    /// # Arguments
291    ///
292    /// * `room_id` - The id of the room for which the receipts should be
293    ///   fetched.
294    ///
295    /// * `receipt_type` - The type of the receipts.
296    ///
297    /// * `receipt_thread` - The thread a receipt applies to.
298    ///
299    /// * `event_id` - The id of the event for which the receipts should be
300    ///   fetched.
301    async fn get_event_room_receipt_events(
302        &self,
303        room_id: &RoomId,
304        receipt_type: ReceiptType,
305        receipt_thread: &ReceiptThread,
306        event_id: &EventId,
307    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error>;
308
309    /// Get arbitrary data from the custom store
310    ///
311    /// # Arguments
312    ///
313    /// * `key` - The key to fetch data for
314    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
315
316    /// Put arbitrary data into the custom store, return the data previously
317    /// stored
318    ///
319    /// # Arguments
320    ///
321    /// * `key` - The key to insert data into
322    ///
323    /// * `value` - The value to insert
324    async fn set_custom_value(
325        &self,
326        key: &[u8],
327        value: Vec<u8>,
328    ) -> Result<Option<Vec<u8>>, Self::Error>;
329
330    /// Put arbitrary data into the custom store, do not attempt to read any
331    /// previous data
332    ///
333    /// Optimization option for set_custom_values for stores that would perform
334    /// better withouts the extra read and the caller not needing that data
335    /// returned. Otherwise this just wraps around `set_custom_data` and
336    /// discards the result.
337    ///
338    /// # Arguments
339    ///
340    /// * `key` - The key to insert data into
341    ///
342    /// * `value` - The value to insert
343    async fn set_custom_value_no_read(
344        &self,
345        key: &[u8],
346        value: Vec<u8>,
347    ) -> Result<(), Self::Error> {
348        self.set_custom_value(key, value).await.map(|_| ())
349    }
350
351    /// Remove arbitrary data from the custom store and return it if existed
352    ///
353    /// # Arguments
354    ///
355    /// * `key` - The key to remove data from
356    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
357
358    /// Remove a room and all elements associated from the state store.
359    ///
360    /// # Arguments
361    ///
362    /// * `room_id` - The `RoomId` of the room to delete.
363    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error>;
364
365    /// Save a request to be sent by a send queue later (e.g. sending an event).
366    ///
367    /// # Arguments
368    ///
369    /// * `room_id` - The `RoomId` of the send queue's room.
370    /// * `transaction_id` - The unique key identifying the event to be sent
371    ///   (and its transaction). Note: this is expected to be randomly generated
372    ///   and thus unique.
373    /// * `content` - Serializable event content to be sent.
374    async fn save_send_queue_request(
375        &self,
376        room_id: &RoomId,
377        transaction_id: OwnedTransactionId,
378        created_at: MilliSecondsSinceUnixEpoch,
379        request: QueuedRequestKind,
380        priority: usize,
381    ) -> Result<(), Self::Error>;
382
383    /// Updates a send queue request with the given content, and resets its
384    /// error status.
385    ///
386    /// # Arguments
387    ///
388    /// * `room_id` - The `RoomId` of the send queue's room.
389    /// * `transaction_id` - The unique key identifying the request to be sent
390    ///   (and its transaction).
391    /// * `content` - Serializable event content to replace the original one.
392    ///
393    /// Returns true if a request has been updated, or false otherwise.
394    async fn update_send_queue_request(
395        &self,
396        room_id: &RoomId,
397        transaction_id: &TransactionId,
398        content: QueuedRequestKind,
399    ) -> Result<bool, Self::Error>;
400
401    /// Remove a request previously inserted with
402    /// [`Self::save_send_queue_request`] from the database, based on its
403    /// transaction id.
404    ///
405    /// Returns true if something has been removed, or false otherwise.
406    async fn remove_send_queue_request(
407        &self,
408        room_id: &RoomId,
409        transaction_id: &TransactionId,
410    ) -> Result<bool, Self::Error>;
411
412    /// Loads all the send queue requests for the given room.
413    ///
414    /// The resulting vector of queued requests should be ordered from higher
415    /// priority to lower priority, and respect the insertion order when
416    /// priorities are equal.
417    async fn load_send_queue_requests(
418        &self,
419        room_id: &RoomId,
420    ) -> Result<Vec<QueuedRequest>, Self::Error>;
421
422    /// Updates the send queue error status (wedge) for a given send queue
423    /// request.
424    async fn update_send_queue_request_status(
425        &self,
426        room_id: &RoomId,
427        transaction_id: &TransactionId,
428        error: Option<QueueWedgeError>,
429    ) -> Result<(), Self::Error>;
430
431    /// Loads all the rooms which have any pending requests in their send queue.
432    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error>;
433
434    /// Add a new entry to the list of dependent send queue requests for a
435    /// parent request.
436    async fn save_dependent_queued_request(
437        &self,
438        room_id: &RoomId,
439        parent_txn_id: &TransactionId,
440        own_txn_id: ChildTransactionId,
441        created_at: MilliSecondsSinceUnixEpoch,
442        content: DependentQueuedRequestKind,
443    ) -> Result<(), Self::Error>;
444
445    /// Mark a set of dependent send queue requests as ready, using a key
446    /// identifying the homeserver's response.
447    ///
448    /// ⚠ Beware! There's no verification applied that the parent key type is
449    /// compatible with the dependent event type. The invalid state may be
450    /// lazily filtered out in `load_dependent_queued_requests`.
451    ///
452    /// Returns the number of updated requests.
453    async fn mark_dependent_queued_requests_as_ready(
454        &self,
455        room_id: &RoomId,
456        parent_txn_id: &TransactionId,
457        sent_parent_key: SentRequestKey,
458    ) -> Result<usize, Self::Error>;
459
460    /// Update a dependent send queue request with the new content.
461    ///
462    /// Returns true if the request was found and could be updated.
463    async fn update_dependent_queued_request(
464        &self,
465        room_id: &RoomId,
466        own_transaction_id: &ChildTransactionId,
467        new_content: DependentQueuedRequestKind,
468    ) -> Result<bool, Self::Error>;
469
470    /// Remove a specific dependent send queue request by id.
471    ///
472    /// Returns true if the dependent send queue request has been indeed
473    /// removed.
474    async fn remove_dependent_queued_request(
475        &self,
476        room: &RoomId,
477        own_txn_id: &ChildTransactionId,
478    ) -> Result<bool, Self::Error>;
479
480    /// List all the dependent send queue requests.
481    ///
482    /// This returns absolutely all the dependent send queue requests, whether
483    /// they have a parent event id or not. As a contract for implementors, they
484    /// must be returned in insertion order.
485    async fn load_dependent_queued_requests(
486        &self,
487        room: &RoomId,
488    ) -> Result<Vec<DependentQueuedRequest>, Self::Error>;
489
490    /// Inserts or updates multiple thread subscriptions.
491    ///
492    /// If the new thread subscription hasn't set a bumpstamp, and there was a
493    /// previous subscription in the database with a bumpstamp, the existing
494    /// bumpstamp is kept.
495    ///
496    /// If the new thread subscription has a bumpstamp that's lower than or
497    /// equal to a previous one, the existing subscription is kept, i.e.
498    /// this method must have no effect.
499    async fn upsert_thread_subscriptions(
500        &self,
501        updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
502    ) -> Result<(), Self::Error>;
503
504    /// Remove a previous thread subscription for a given room and thread.
505    ///
506    /// Note: removing an unknown thread subscription is a no-op.
507    async fn remove_thread_subscription(
508        &self,
509        room: &RoomId,
510        thread_id: &EventId,
511    ) -> Result<(), Self::Error>;
512
513    /// Loads the current thread subscription for a given room and thread.
514    ///
515    /// Returns `None` if there was no entry for the given room/thread pair.
516    async fn load_thread_subscription(
517        &self,
518        room: &RoomId,
519        thread_id: &EventId,
520    ) -> Result<Option<StoredThreadSubscription>, Self::Error>;
521
522    /// Get a user's global profile from the store.
523    ///
524    /// Global profiles are persisted as part of [`StateStore::save_changes`],
525    /// from the [`StateChanges::global_profiles`] field, following the MSC4262
526    /// update pattern: fields with an explicit `null` value are removed, while
527    /// fields not present are left unchanged.
528    ///
529    /// Returns `None` if there was no stored global profile for the given user.
530    async fn get_global_profile(
531        &self,
532        user_id: &UserId,
533    ) -> Result<Option<UserProfile>, Self::Error>;
534
535    /// Get the global profiles for the given users from the store.
536    ///
537    /// See [`StateStore::get_global_profile`] for more details. Users without a
538    /// stored global profile are absent from the returned map.
539    async fn get_global_profiles<'a>(
540        &self,
541        user_ids: &'a [OwnedUserId],
542    ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error>;
543
544    /// Close the store, releasing all held resources (database connections,
545    /// file descriptors, file locks).
546    ///
547    /// In-flight operations complete before this method returns. After it
548    /// returns, operations will fail until [`Self::reopen()`] is called.
549    async fn close(&self) -> Result<(), Self::Error>;
550
551    /// Reopen the store after a [`Self::close()`], re-acquiring database
552    /// connections.
553    async fn reopen(&self) -> Result<(), Self::Error>;
554
555    /// Perform database optimizations if any are available, i.e. vacuuming in
556    /// SQLite.
557    ///
558    /// /// **Warning:** this was added to check if SQLite fragmentation was the
559    /// source of performance issues, **DO NOT use in production**.
560    #[doc(hidden)]
561    async fn optimize(&self) -> Result<(), Self::Error>;
562
563    /// Returns the size of the store in bytes, if known.
564    async fn get_size(&self) -> Result<Option<usize>, Self::Error>;
565}
566
567#[cfg_attr(target_family = "wasm", async_trait(?Send))]
568#[cfg_attr(not(target_family = "wasm"), async_trait)]
569impl<T: StateStore> StateStore for &T {
570    type Error = T::Error;
571
572    async fn get_kv_data(
573        &self,
574        key: StateStoreDataKey<'_>,
575    ) -> Result<Option<StateStoreDataValue>, Self::Error> {
576        (*self).get_kv_data(key).await
577    }
578
579    async fn set_kv_data(
580        &self,
581        key: StateStoreDataKey<'_>,
582        value: StateStoreDataValue,
583    ) -> Result<(), Self::Error> {
584        (*self).set_kv_data(key, value).await
585    }
586
587    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
588        (*self).remove_kv_data(key).await
589    }
590
591    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
592        (*self).save_changes(changes).await
593    }
594
595    async fn get_presence_event(
596        &self,
597        user_id: &UserId,
598    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
599        (*self).get_presence_event(user_id).await
600    }
601
602    async fn get_presence_events(
603        &self,
604        user_ids: &[OwnedUserId],
605    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
606        (*self).get_presence_events(user_ids).await
607    }
608
609    async fn get_state_event(
610        &self,
611        room_id: &RoomId,
612        event_type: StateEventType,
613        state_key: &str,
614    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
615        (*self).get_state_event(room_id, event_type, state_key).await
616    }
617
618    async fn get_state_events(
619        &self,
620        room_id: &RoomId,
621        event_type: StateEventType,
622    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
623        (*self).get_state_events(room_id, event_type).await
624    }
625
626    async fn get_state_events_for_keys(
627        &self,
628        room_id: &RoomId,
629        event_type: StateEventType,
630        state_keys: &[&str],
631    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
632        (*self).get_state_events_for_keys(room_id, event_type, state_keys).await
633    }
634
635    async fn get_profile(
636        &self,
637        room_id: &RoomId,
638        user_id: &UserId,
639    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
640        (*self).get_profile(room_id, user_id).await
641    }
642
643    async fn get_profiles<'a>(
644        &self,
645        room_id: &RoomId,
646        user_ids: &'a [OwnedUserId],
647    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
648        (*self).get_profiles(room_id, user_ids).await
649    }
650
651    async fn get_user_ids(
652        &self,
653        room_id: &RoomId,
654        memberships: RoomMemberships,
655    ) -> Result<Vec<OwnedUserId>, Self::Error> {
656        (*self).get_user_ids(room_id, memberships).await
657    }
658
659    async fn get_room_infos(
660        &self,
661        room_load_settings: &RoomLoadSettings,
662    ) -> Result<Vec<RoomInfo>, Self::Error> {
663        (*self).get_room_infos(room_load_settings).await
664    }
665
666    async fn get_users_with_display_name(
667        &self,
668        room_id: &RoomId,
669        display_name: &DisplayName,
670    ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
671        (*self).get_users_with_display_name(room_id, display_name).await
672    }
673
674    async fn get_users_with_display_names<'a>(
675        &self,
676        room_id: &RoomId,
677        display_names: &'a [DisplayName],
678    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
679        (*self).get_users_with_display_names(room_id, display_names).await
680    }
681
682    async fn get_account_data_event(
683        &self,
684        event_type: GlobalAccountDataEventType,
685    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
686        (*self).get_account_data_event(event_type).await
687    }
688
689    async fn get_room_account_data_event(
690        &self,
691        room_id: &RoomId,
692        event_type: RoomAccountDataEventType,
693    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
694        (*self).get_room_account_data_event(room_id, event_type).await
695    }
696
697    async fn get_user_room_receipt_event(
698        &self,
699        room_id: &RoomId,
700        receipt_type: ReceiptType,
701        receipt_thread: &ReceiptThread,
702        user_id: &UserId,
703    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
704        (*self).get_user_room_receipt_event(room_id, receipt_type, receipt_thread, user_id).await
705    }
706
707    async fn get_event_room_receipt_events(
708        &self,
709        room_id: &RoomId,
710        receipt_type: ReceiptType,
711        receipt_thread: &ReceiptThread,
712        event_id: &EventId,
713    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
714        (*self).get_event_room_receipt_events(room_id, receipt_type, receipt_thread, event_id).await
715    }
716
717    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
718        (*self).get_custom_value(key).await
719    }
720
721    async fn set_custom_value(
722        &self,
723        key: &[u8],
724        value: Vec<u8>,
725    ) -> Result<Option<Vec<u8>>, Self::Error> {
726        (*self).set_custom_value(key, value).await
727    }
728
729    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
730        (*self).remove_custom_value(key).await
731    }
732
733    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
734        (*self).remove_room(room_id).await
735    }
736
737    async fn save_send_queue_request(
738        &self,
739        room_id: &RoomId,
740        transaction_id: OwnedTransactionId,
741        created_at: MilliSecondsSinceUnixEpoch,
742        request: QueuedRequestKind,
743        priority: usize,
744    ) -> Result<(), Self::Error> {
745        (*self)
746            .save_send_queue_request(room_id, transaction_id, created_at, request, priority)
747            .await
748    }
749
750    async fn update_send_queue_request(
751        &self,
752        room_id: &RoomId,
753        transaction_id: &TransactionId,
754        content: QueuedRequestKind,
755    ) -> Result<bool, Self::Error> {
756        (*self).update_send_queue_request(room_id, transaction_id, content).await
757    }
758
759    async fn remove_send_queue_request(
760        &self,
761        room_id: &RoomId,
762        transaction_id: &TransactionId,
763    ) -> Result<bool, Self::Error> {
764        (*self).remove_send_queue_request(room_id, transaction_id).await
765    }
766
767    async fn load_send_queue_requests(
768        &self,
769        room_id: &RoomId,
770    ) -> Result<Vec<QueuedRequest>, Self::Error> {
771        (*self).load_send_queue_requests(room_id).await
772    }
773
774    async fn update_send_queue_request_status(
775        &self,
776        room_id: &RoomId,
777        transaction_id: &TransactionId,
778        error: Option<QueueWedgeError>,
779    ) -> Result<(), Self::Error> {
780        (*self).update_send_queue_request_status(room_id, transaction_id, error).await
781    }
782
783    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
784        (*self).load_rooms_with_unsent_requests().await
785    }
786
787    async fn save_dependent_queued_request(
788        &self,
789        room_id: &RoomId,
790        parent_txn_id: &TransactionId,
791        own_txn_id: ChildTransactionId,
792        created_at: MilliSecondsSinceUnixEpoch,
793        content: DependentQueuedRequestKind,
794    ) -> Result<(), Self::Error> {
795        (*self)
796            .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
797            .await
798    }
799
800    async fn mark_dependent_queued_requests_as_ready(
801        &self,
802        room_id: &RoomId,
803        parent_txn_id: &TransactionId,
804        sent_parent_key: SentRequestKey,
805    ) -> Result<usize, Self::Error> {
806        (*self)
807            .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
808            .await
809    }
810
811    async fn update_dependent_queued_request(
812        &self,
813        room_id: &RoomId,
814        own_transaction_id: &ChildTransactionId,
815        new_content: DependentQueuedRequestKind,
816    ) -> Result<bool, Self::Error> {
817        (*self).update_dependent_queued_request(room_id, own_transaction_id, new_content).await
818    }
819
820    async fn remove_dependent_queued_request(
821        &self,
822        room: &RoomId,
823        own_txn_id: &ChildTransactionId,
824    ) -> Result<bool, Self::Error> {
825        (*self).remove_dependent_queued_request(room, own_txn_id).await
826    }
827
828    async fn load_dependent_queued_requests(
829        &self,
830        room: &RoomId,
831    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
832        (*self).load_dependent_queued_requests(room).await
833    }
834
835    async fn upsert_thread_subscriptions(
836        &self,
837        updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
838    ) -> Result<(), Self::Error> {
839        (*self).upsert_thread_subscriptions(updates).await
840    }
841
842    async fn remove_thread_subscription(
843        &self,
844        room: &RoomId,
845        thread_id: &EventId,
846    ) -> Result<(), Self::Error> {
847        (*self).remove_thread_subscription(room, thread_id).await
848    }
849
850    async fn load_thread_subscription(
851        &self,
852        room: &RoomId,
853        thread_id: &EventId,
854    ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
855        (*self).load_thread_subscription(room, thread_id).await
856    }
857
858    async fn get_global_profile(
859        &self,
860        user_id: &UserId,
861    ) -> Result<Option<UserProfile>, Self::Error> {
862        (*self).get_global_profile(user_id).await
863    }
864
865    async fn get_global_profiles<'a>(
866        &self,
867        user_ids: &'a [OwnedUserId],
868    ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error> {
869        (*self).get_global_profiles(user_ids).await
870    }
871
872    async fn close(&self) -> Result<(), Self::Error> {
873        (*self).close().await
874    }
875
876    async fn reopen(&self) -> Result<(), Self::Error> {
877        (*self).reopen().await
878    }
879
880    async fn optimize(&self) -> Result<(), Self::Error> {
881        (*self).optimize().await
882    }
883
884    async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
885        (*self).get_size().await
886    }
887}
888
889#[cfg_attr(target_family = "wasm", async_trait(?Send))]
890#[cfg_attr(not(target_family = "wasm"), async_trait)]
891impl<T: StateStore + ?Sized> StateStore for Arc<T> {
892    type Error = T::Error;
893
894    async fn get_kv_data(
895        &self,
896        key: StateStoreDataKey<'_>,
897    ) -> Result<Option<StateStoreDataValue>, Self::Error> {
898        self.deref().get_kv_data(key).await
899    }
900
901    async fn set_kv_data(
902        &self,
903        key: StateStoreDataKey<'_>,
904        value: StateStoreDataValue,
905    ) -> Result<(), Self::Error> {
906        self.deref().set_kv_data(key, value).await
907    }
908
909    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
910        self.deref().remove_kv_data(key).await
911    }
912
913    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
914        self.deref().save_changes(changes).await
915    }
916
917    async fn get_presence_event(
918        &self,
919        user_id: &UserId,
920    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
921        self.deref().get_presence_event(user_id).await
922    }
923
924    async fn get_presence_events(
925        &self,
926        user_ids: &[OwnedUserId],
927    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
928        self.deref().get_presence_events(user_ids).await
929    }
930
931    async fn get_state_event(
932        &self,
933        room_id: &RoomId,
934        event_type: StateEventType,
935        state_key: &str,
936    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
937        self.deref().get_state_event(room_id, event_type, state_key).await
938    }
939
940    async fn get_state_events(
941        &self,
942        room_id: &RoomId,
943        event_type: StateEventType,
944    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
945        self.deref().get_state_events(room_id, event_type).await
946    }
947
948    async fn get_state_events_for_keys(
949        &self,
950        room_id: &RoomId,
951        event_type: StateEventType,
952        state_keys: &[&str],
953    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
954        self.deref().get_state_events_for_keys(room_id, event_type, state_keys).await
955    }
956
957    async fn get_profile(
958        &self,
959        room_id: &RoomId,
960        user_id: &UserId,
961    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
962        self.deref().get_profile(room_id, user_id).await
963    }
964
965    async fn get_profiles<'a>(
966        &self,
967        room_id: &RoomId,
968        user_ids: &'a [OwnedUserId],
969    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
970        self.deref().get_profiles(room_id, user_ids).await
971    }
972
973    async fn get_user_ids(
974        &self,
975        room_id: &RoomId,
976        memberships: RoomMemberships,
977    ) -> Result<Vec<OwnedUserId>, Self::Error> {
978        self.deref().get_user_ids(room_id, memberships).await
979    }
980
981    async fn get_room_infos(
982        &self,
983        room_load_settings: &RoomLoadSettings,
984    ) -> Result<Vec<RoomInfo>, Self::Error> {
985        self.deref().get_room_infos(room_load_settings).await
986    }
987
988    async fn get_users_with_display_name(
989        &self,
990        room_id: &RoomId,
991        display_name: &DisplayName,
992    ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
993        self.deref().get_users_with_display_name(room_id, display_name).await
994    }
995
996    async fn get_users_with_display_names<'a>(
997        &self,
998        room_id: &RoomId,
999        display_names: &'a [DisplayName],
1000    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
1001        self.deref().get_users_with_display_names(room_id, display_names).await
1002    }
1003
1004    async fn get_account_data_event(
1005        &self,
1006        event_type: GlobalAccountDataEventType,
1007    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
1008        self.deref().get_account_data_event(event_type).await
1009    }
1010
1011    async fn get_room_account_data_event(
1012        &self,
1013        room_id: &RoomId,
1014        event_type: RoomAccountDataEventType,
1015    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
1016        self.deref().get_room_account_data_event(room_id, event_type).await
1017    }
1018
1019    async fn get_user_room_receipt_event(
1020        &self,
1021        room_id: &RoomId,
1022        receipt_type: ReceiptType,
1023        receipt_thread: &ReceiptThread,
1024        user_id: &UserId,
1025    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
1026        self.deref()
1027            .get_user_room_receipt_event(room_id, receipt_type, receipt_thread, user_id)
1028            .await
1029    }
1030
1031    async fn get_event_room_receipt_events(
1032        &self,
1033        room_id: &RoomId,
1034        receipt_type: ReceiptType,
1035        receipt_thread: &ReceiptThread,
1036        event_id: &EventId,
1037    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
1038        self.deref()
1039            .get_event_room_receipt_events(room_id, receipt_type, receipt_thread, event_id)
1040            .await
1041    }
1042
1043    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
1044        self.deref().get_custom_value(key).await
1045    }
1046
1047    async fn set_custom_value(
1048        &self,
1049        key: &[u8],
1050        value: Vec<u8>,
1051    ) -> Result<Option<Vec<u8>>, Self::Error> {
1052        self.deref().set_custom_value(key, value).await
1053    }
1054
1055    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
1056        self.deref().remove_custom_value(key).await
1057    }
1058
1059    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
1060        self.deref().remove_room(room_id).await
1061    }
1062
1063    async fn save_send_queue_request(
1064        &self,
1065        room_id: &RoomId,
1066        transaction_id: OwnedTransactionId,
1067        created_at: MilliSecondsSinceUnixEpoch,
1068        request: QueuedRequestKind,
1069        priority: usize,
1070    ) -> Result<(), Self::Error> {
1071        self.deref()
1072            .save_send_queue_request(room_id, transaction_id, created_at, request, priority)
1073            .await
1074    }
1075
1076    async fn update_send_queue_request(
1077        &self,
1078        room_id: &RoomId,
1079        transaction_id: &TransactionId,
1080        content: QueuedRequestKind,
1081    ) -> Result<bool, Self::Error> {
1082        self.deref().update_send_queue_request(room_id, transaction_id, content).await
1083    }
1084
1085    async fn remove_send_queue_request(
1086        &self,
1087        room_id: &RoomId,
1088        transaction_id: &TransactionId,
1089    ) -> Result<bool, Self::Error> {
1090        self.deref().remove_send_queue_request(room_id, transaction_id).await
1091    }
1092
1093    async fn load_send_queue_requests(
1094        &self,
1095        room_id: &RoomId,
1096    ) -> Result<Vec<QueuedRequest>, Self::Error> {
1097        self.deref().load_send_queue_requests(room_id).await
1098    }
1099
1100    async fn update_send_queue_request_status(
1101        &self,
1102        room_id: &RoomId,
1103        transaction_id: &TransactionId,
1104        error: Option<QueueWedgeError>,
1105    ) -> Result<(), Self::Error> {
1106        self.deref().update_send_queue_request_status(room_id, transaction_id, error).await
1107    }
1108
1109    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
1110        self.deref().load_rooms_with_unsent_requests().await
1111    }
1112
1113    async fn save_dependent_queued_request(
1114        &self,
1115        room_id: &RoomId,
1116        parent_txn_id: &TransactionId,
1117        own_txn_id: ChildTransactionId,
1118        created_at: MilliSecondsSinceUnixEpoch,
1119        content: DependentQueuedRequestKind,
1120    ) -> Result<(), Self::Error> {
1121        self.deref()
1122            .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
1123            .await
1124    }
1125
1126    async fn mark_dependent_queued_requests_as_ready(
1127        &self,
1128        room_id: &RoomId,
1129        parent_txn_id: &TransactionId,
1130        sent_parent_key: SentRequestKey,
1131    ) -> Result<usize, Self::Error> {
1132        self.deref()
1133            .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
1134            .await
1135    }
1136
1137    async fn update_dependent_queued_request(
1138        &self,
1139        room_id: &RoomId,
1140        own_transaction_id: &ChildTransactionId,
1141        new_content: DependentQueuedRequestKind,
1142    ) -> Result<bool, Self::Error> {
1143        self.deref().update_dependent_queued_request(room_id, own_transaction_id, new_content).await
1144    }
1145
1146    async fn remove_dependent_queued_request(
1147        &self,
1148        room: &RoomId,
1149        own_txn_id: &ChildTransactionId,
1150    ) -> Result<bool, Self::Error> {
1151        self.deref().remove_dependent_queued_request(room, own_txn_id).await
1152    }
1153
1154    async fn load_dependent_queued_requests(
1155        &self,
1156        room: &RoomId,
1157    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
1158        self.deref().load_dependent_queued_requests(room).await
1159    }
1160
1161    async fn upsert_thread_subscriptions(
1162        &self,
1163        updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
1164    ) -> Result<(), Self::Error> {
1165        self.deref().upsert_thread_subscriptions(updates).await
1166    }
1167
1168    async fn remove_thread_subscription(
1169        &self,
1170        room: &RoomId,
1171        thread_id: &EventId,
1172    ) -> Result<(), Self::Error> {
1173        self.deref().remove_thread_subscription(room, thread_id).await
1174    }
1175
1176    async fn load_thread_subscription(
1177        &self,
1178        room: &RoomId,
1179        thread_id: &EventId,
1180    ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
1181        self.deref().load_thread_subscription(room, thread_id).await
1182    }
1183
1184    async fn get_global_profile(
1185        &self,
1186        user_id: &UserId,
1187    ) -> Result<Option<UserProfile>, Self::Error> {
1188        self.deref().get_global_profile(user_id).await
1189    }
1190
1191    async fn get_global_profiles<'a>(
1192        &self,
1193        user_ids: &'a [OwnedUserId],
1194    ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error> {
1195        self.deref().get_global_profiles(user_ids).await
1196    }
1197
1198    async fn close(&self) -> Result<(), Self::Error> {
1199        self.deref().close().await
1200    }
1201
1202    async fn reopen(&self) -> Result<(), Self::Error> {
1203        self.deref().reopen().await
1204    }
1205
1206    async fn optimize(&self) -> Result<(), Self::Error> {
1207        self.deref().optimize().await
1208    }
1209
1210    async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1211        self.deref().get_size().await
1212    }
1213}
1214
1215#[repr(transparent)]
1216struct EraseStateStoreError<T>(T);
1217
1218#[cfg(not(tarpaulin_include))]
1219impl<T: fmt::Debug> fmt::Debug for EraseStateStoreError<T> {
1220    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1221        self.0.fmt(f)
1222    }
1223}
1224
1225#[cfg_attr(target_family = "wasm", async_trait(?Send))]
1226#[cfg_attr(not(target_family = "wasm"), async_trait)]
1227impl<T: StateStore> StateStore for EraseStateStoreError<T> {
1228    type Error = StoreError;
1229
1230    async fn get_kv_data(
1231        &self,
1232        key: StateStoreDataKey<'_>,
1233    ) -> Result<Option<StateStoreDataValue>, Self::Error> {
1234        self.0.get_kv_data(key).await.map_err(Into::into)
1235    }
1236
1237    async fn set_kv_data(
1238        &self,
1239        key: StateStoreDataKey<'_>,
1240        value: StateStoreDataValue,
1241    ) -> Result<(), Self::Error> {
1242        self.0.set_kv_data(key, value).await.map_err(Into::into)
1243    }
1244
1245    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
1246        self.0.remove_kv_data(key).await.map_err(Into::into)
1247    }
1248
1249    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
1250        self.0.save_changes(changes).await.map_err(Into::into)
1251    }
1252
1253    async fn get_presence_event(
1254        &self,
1255        user_id: &UserId,
1256    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
1257        self.0.get_presence_event(user_id).await.map_err(Into::into)
1258    }
1259
1260    async fn get_presence_events(
1261        &self,
1262        user_ids: &[OwnedUserId],
1263    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
1264        self.0.get_presence_events(user_ids).await.map_err(Into::into)
1265    }
1266
1267    async fn get_state_event(
1268        &self,
1269        room_id: &RoomId,
1270        event_type: StateEventType,
1271        state_key: &str,
1272    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
1273        self.0.get_state_event(room_id, event_type, state_key).await.map_err(Into::into)
1274    }
1275
1276    async fn get_state_events(
1277        &self,
1278        room_id: &RoomId,
1279        event_type: StateEventType,
1280    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
1281        self.0.get_state_events(room_id, event_type).await.map_err(Into::into)
1282    }
1283
1284    async fn get_state_events_for_keys(
1285        &self,
1286        room_id: &RoomId,
1287        event_type: StateEventType,
1288        state_keys: &[&str],
1289    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
1290        self.0.get_state_events_for_keys(room_id, event_type, state_keys).await.map_err(Into::into)
1291    }
1292
1293    async fn get_profile(
1294        &self,
1295        room_id: &RoomId,
1296        user_id: &UserId,
1297    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
1298        self.0.get_profile(room_id, user_id).await.map_err(Into::into)
1299    }
1300
1301    async fn get_profiles<'a>(
1302        &self,
1303        room_id: &RoomId,
1304        user_ids: &'a [OwnedUserId],
1305    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
1306        self.0.get_profiles(room_id, user_ids).await.map_err(Into::into)
1307    }
1308
1309    async fn get_user_ids(
1310        &self,
1311        room_id: &RoomId,
1312        memberships: RoomMemberships,
1313    ) -> Result<Vec<OwnedUserId>, Self::Error> {
1314        self.0.get_user_ids(room_id, memberships).await.map_err(Into::into)
1315    }
1316
1317    async fn get_room_infos(
1318        &self,
1319        room_load_settings: &RoomLoadSettings,
1320    ) -> Result<Vec<RoomInfo>, Self::Error> {
1321        self.0.get_room_infos(room_load_settings).await.map_err(Into::into)
1322    }
1323
1324    async fn get_users_with_display_name(
1325        &self,
1326        room_id: &RoomId,
1327        display_name: &DisplayName,
1328    ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
1329        self.0.get_users_with_display_name(room_id, display_name).await.map_err(Into::into)
1330    }
1331
1332    async fn get_users_with_display_names<'a>(
1333        &self,
1334        room_id: &RoomId,
1335        display_names: &'a [DisplayName],
1336    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
1337        self.0.get_users_with_display_names(room_id, display_names).await.map_err(Into::into)
1338    }
1339
1340    async fn get_account_data_event(
1341        &self,
1342        event_type: GlobalAccountDataEventType,
1343    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
1344        self.0.get_account_data_event(event_type).await.map_err(Into::into)
1345    }
1346
1347    async fn get_room_account_data_event(
1348        &self,
1349        room_id: &RoomId,
1350        event_type: RoomAccountDataEventType,
1351    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
1352        self.0.get_room_account_data_event(room_id, event_type).await.map_err(Into::into)
1353    }
1354
1355    async fn get_user_room_receipt_event(
1356        &self,
1357        room_id: &RoomId,
1358        receipt_type: ReceiptType,
1359        receipt_thread: &ReceiptThread,
1360        user_id: &UserId,
1361    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
1362        self.0
1363            .get_user_room_receipt_event(room_id, receipt_type, receipt_thread, user_id)
1364            .await
1365            .map_err(Into::into)
1366    }
1367
1368    async fn get_event_room_receipt_events(
1369        &self,
1370        room_id: &RoomId,
1371        receipt_type: ReceiptType,
1372        receipt_thread: &ReceiptThread,
1373        event_id: &EventId,
1374    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
1375        self.0
1376            .get_event_room_receipt_events(room_id, receipt_type, receipt_thread, event_id)
1377            .await
1378            .map_err(Into::into)
1379    }
1380
1381    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
1382        self.0.get_custom_value(key).await.map_err(Into::into)
1383    }
1384
1385    async fn set_custom_value(
1386        &self,
1387        key: &[u8],
1388        value: Vec<u8>,
1389    ) -> Result<Option<Vec<u8>>, Self::Error> {
1390        self.0.set_custom_value(key, value).await.map_err(Into::into)
1391    }
1392
1393    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
1394        self.0.remove_custom_value(key).await.map_err(Into::into)
1395    }
1396
1397    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
1398        self.0.remove_room(room_id).await.map_err(Into::into)
1399    }
1400
1401    async fn save_send_queue_request(
1402        &self,
1403        room_id: &RoomId,
1404        transaction_id: OwnedTransactionId,
1405        created_at: MilliSecondsSinceUnixEpoch,
1406        content: QueuedRequestKind,
1407        priority: usize,
1408    ) -> Result<(), Self::Error> {
1409        self.0
1410            .save_send_queue_request(room_id, transaction_id, created_at, content, priority)
1411            .await
1412            .map_err(Into::into)
1413    }
1414
1415    async fn update_send_queue_request(
1416        &self,
1417        room_id: &RoomId,
1418        transaction_id: &TransactionId,
1419        content: QueuedRequestKind,
1420    ) -> Result<bool, Self::Error> {
1421        self.0.update_send_queue_request(room_id, transaction_id, content).await.map_err(Into::into)
1422    }
1423
1424    async fn remove_send_queue_request(
1425        &self,
1426        room_id: &RoomId,
1427        transaction_id: &TransactionId,
1428    ) -> Result<bool, Self::Error> {
1429        self.0.remove_send_queue_request(room_id, transaction_id).await.map_err(Into::into)
1430    }
1431
1432    async fn load_send_queue_requests(
1433        &self,
1434        room_id: &RoomId,
1435    ) -> Result<Vec<QueuedRequest>, Self::Error> {
1436        self.0.load_send_queue_requests(room_id).await.map_err(Into::into)
1437    }
1438
1439    async fn update_send_queue_request_status(
1440        &self,
1441        room_id: &RoomId,
1442        transaction_id: &TransactionId,
1443        error: Option<QueueWedgeError>,
1444    ) -> Result<(), Self::Error> {
1445        self.0
1446            .update_send_queue_request_status(room_id, transaction_id, error)
1447            .await
1448            .map_err(Into::into)
1449    }
1450
1451    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
1452        self.0.load_rooms_with_unsent_requests().await.map_err(Into::into)
1453    }
1454
1455    async fn save_dependent_queued_request(
1456        &self,
1457        room_id: &RoomId,
1458        parent_txn_id: &TransactionId,
1459        own_txn_id: ChildTransactionId,
1460        created_at: MilliSecondsSinceUnixEpoch,
1461        content: DependentQueuedRequestKind,
1462    ) -> Result<(), Self::Error> {
1463        self.0
1464            .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
1465            .await
1466            .map_err(Into::into)
1467    }
1468
1469    async fn mark_dependent_queued_requests_as_ready(
1470        &self,
1471        room_id: &RoomId,
1472        parent_txn_id: &TransactionId,
1473        sent_parent_key: SentRequestKey,
1474    ) -> Result<usize, Self::Error> {
1475        self.0
1476            .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
1477            .await
1478            .map_err(Into::into)
1479    }
1480
1481    async fn remove_dependent_queued_request(
1482        &self,
1483        room_id: &RoomId,
1484        own_txn_id: &ChildTransactionId,
1485    ) -> Result<bool, Self::Error> {
1486        self.0.remove_dependent_queued_request(room_id, own_txn_id).await.map_err(Into::into)
1487    }
1488
1489    async fn load_dependent_queued_requests(
1490        &self,
1491        room_id: &RoomId,
1492    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
1493        self.0.load_dependent_queued_requests(room_id).await.map_err(Into::into)
1494    }
1495
1496    async fn update_dependent_queued_request(
1497        &self,
1498        room_id: &RoomId,
1499        own_transaction_id: &ChildTransactionId,
1500        new_content: DependentQueuedRequestKind,
1501    ) -> Result<bool, Self::Error> {
1502        self.0
1503            .update_dependent_queued_request(room_id, own_transaction_id, new_content)
1504            .await
1505            .map_err(Into::into)
1506    }
1507
1508    async fn upsert_thread_subscriptions(
1509        &self,
1510        updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
1511    ) -> Result<(), Self::Error> {
1512        self.0.upsert_thread_subscriptions(updates).await.map_err(Into::into)
1513    }
1514
1515    async fn load_thread_subscription(
1516        &self,
1517        room: &RoomId,
1518        thread_id: &EventId,
1519    ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
1520        self.0.load_thread_subscription(room, thread_id).await.map_err(Into::into)
1521    }
1522
1523    async fn remove_thread_subscription(
1524        &self,
1525        room: &RoomId,
1526        thread_id: &EventId,
1527    ) -> Result<(), Self::Error> {
1528        self.0.remove_thread_subscription(room, thread_id).await.map_err(Into::into)
1529    }
1530
1531    async fn get_global_profile(
1532        &self,
1533        user_id: &UserId,
1534    ) -> Result<Option<UserProfile>, Self::Error> {
1535        self.0.get_global_profile(user_id).await.map_err(Into::into)
1536    }
1537
1538    async fn get_global_profiles<'a>(
1539        &self,
1540        user_ids: &'a [OwnedUserId],
1541    ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error> {
1542        self.0.get_global_profiles(user_ids).await.map_err(Into::into)
1543    }
1544
1545    async fn close(&self) -> Result<(), Self::Error> {
1546        self.0.close().await.map_err(Into::into)
1547    }
1548
1549    async fn reopen(&self) -> Result<(), Self::Error> {
1550        self.0.reopen().await.map_err(Into::into)
1551    }
1552
1553    async fn optimize(&self) -> Result<(), Self::Error> {
1554        self.0.optimize().await.map_err(Into::into)
1555    }
1556
1557    async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1558        self.0.get_size().await.map_err(Into::into)
1559    }
1560}
1561
1562/// A wrapper around a [`StateStore`] that supports synchronizing calls to
1563/// [`StateStore::save_changes`].
1564#[derive(Debug, Clone)]
1565pub struct SaveLockedStateStore<T = Arc<DynStateStore>> {
1566    store: T,
1567    lock: Arc<Mutex<()>>,
1568}
1569
1570/// An error type that represents a scenario where a [`MutexGuard`] provided to
1571/// a function does not reference the underlying [`Mutex`] in the enclosing
1572/// [`SaveLockedStateStore`].
1573#[derive(Debug, Error)]
1574#[error("a mutex guard was provided, but it does not reference the correct mutex")]
1575pub struct IncorrectMutexGuardError;
1576
1577impl From<IncorrectMutexGuardError> for StoreError {
1578    fn from(value: IncorrectMutexGuardError) -> Self {
1579        Self::backend(value)
1580    }
1581}
1582
1583impl<T> SaveLockedStateStore<T> {
1584    /// Creates a new [`SaveLockedStateStore`] with the provided store.
1585    pub fn new(store: T) -> Self {
1586        Self { store, lock: Arc::new(Mutex::new(())) }
1587    }
1588
1589    /// Returns a reference to the underlying [`Mutex`] used to synchronize
1590    /// calls to [`StateStore::save_changes`].
1591    pub fn lock(&self) -> &Mutex<()> {
1592        self.lock.as_ref()
1593    }
1594}
1595
1596impl<T: StateStore> SaveLockedStateStore<T> {
1597    /// Provides a means of calling [`StateStore::save_changes`] when the caller
1598    /// has already acquired the underlying [`Mutex`]. Returns an error if
1599    /// the [`MutexGuard`] provided does not reference the underlying
1600    /// [`Mutex`].
1601    pub async fn save_changes_with_guard(
1602        &self,
1603        guard: &MutexGuard<'_, ()>,
1604        changes: &StateChanges,
1605    ) -> Result<(), StoreError> {
1606        if !std::ptr::eq(MutexGuard::mutex(guard), self.lock()) {
1607            Err(IncorrectMutexGuardError.into())
1608        } else {
1609            self.store.save_changes(changes).await.map_err(Into::into)
1610        }
1611    }
1612
1613    /// Provides a means of calling [`StateStore::remove_room`] when the caller
1614    /// has already acquired the underlying [`Mutex`]. Returns an error if
1615    /// the [`MutexGuard`] provided does not reference the underlying
1616    /// [`Mutex`].
1617    pub async fn remove_room_with_guard(
1618        &self,
1619        guard: &MutexGuard<'_, ()>,
1620        room_id: &RoomId,
1621    ) -> Result<(), StoreError> {
1622        if !std::ptr::eq(MutexGuard::mutex(guard), self.lock()) {
1623            Err(IncorrectMutexGuardError.into())
1624        } else {
1625            self.store.remove_room(room_id).await.map_err(Into::into)
1626        }
1627    }
1628}
1629
1630#[cfg_attr(target_family = "wasm", async_trait(?Send))]
1631#[cfg_attr(not(target_family = "wasm"), async_trait)]
1632impl<T: StateStore> StateStore for SaveLockedStateStore<T> {
1633    type Error = T::Error;
1634
1635    async fn get_kv_data(
1636        &self,
1637        key: StateStoreDataKey<'_>,
1638    ) -> Result<Option<StateStoreDataValue>, Self::Error> {
1639        self.store.get_kv_data(key).await
1640    }
1641
1642    async fn set_kv_data(
1643        &self,
1644        key: StateStoreDataKey<'_>,
1645        value: StateStoreDataValue,
1646    ) -> Result<(), Self::Error> {
1647        self.store.set_kv_data(key, value).await
1648    }
1649
1650    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
1651        self.store.remove_kv_data(key).await
1652    }
1653
1654    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
1655        let _guard = self.lock.lock().await;
1656        self.store.save_changes(changes).await
1657    }
1658
1659    async fn get_presence_event(
1660        &self,
1661        user_id: &UserId,
1662    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
1663        self.store.get_presence_event(user_id).await
1664    }
1665
1666    async fn get_presence_events(
1667        &self,
1668        user_ids: &[OwnedUserId],
1669    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
1670        self.store.get_presence_events(user_ids).await
1671    }
1672
1673    async fn get_state_event(
1674        &self,
1675        room_id: &RoomId,
1676        event_type: StateEventType,
1677        state_key: &str,
1678    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
1679        self.store.get_state_event(room_id, event_type, state_key).await
1680    }
1681
1682    async fn get_state_events(
1683        &self,
1684        room_id: &RoomId,
1685        event_type: StateEventType,
1686    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
1687        self.store.get_state_events(room_id, event_type).await
1688    }
1689
1690    async fn get_state_events_for_keys(
1691        &self,
1692        room_id: &RoomId,
1693        event_type: StateEventType,
1694        state_keys: &[&str],
1695    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
1696        self.store.get_state_events_for_keys(room_id, event_type, state_keys).await
1697    }
1698
1699    async fn get_profile(
1700        &self,
1701        room_id: &RoomId,
1702        user_id: &UserId,
1703    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
1704        self.store.get_profile(room_id, user_id).await
1705    }
1706
1707    async fn get_profiles<'a>(
1708        &self,
1709        room_id: &RoomId,
1710        user_ids: &'a [OwnedUserId],
1711    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
1712        self.store.get_profiles(room_id, user_ids).await
1713    }
1714
1715    async fn get_user_ids(
1716        &self,
1717        room_id: &RoomId,
1718        memberships: RoomMemberships,
1719    ) -> Result<Vec<OwnedUserId>, Self::Error> {
1720        self.store.get_user_ids(room_id, memberships).await
1721    }
1722
1723    async fn get_room_infos(
1724        &self,
1725        room_load_settings: &RoomLoadSettings,
1726    ) -> Result<Vec<RoomInfo>, Self::Error> {
1727        self.store.get_room_infos(room_load_settings).await
1728    }
1729
1730    async fn get_users_with_display_name(
1731        &self,
1732        room_id: &RoomId,
1733        display_name: &DisplayName,
1734    ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
1735        self.store.get_users_with_display_name(room_id, display_name).await
1736    }
1737
1738    async fn get_users_with_display_names<'a>(
1739        &self,
1740        room_id: &RoomId,
1741        display_names: &'a [DisplayName],
1742    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
1743        self.store.get_users_with_display_names(room_id, display_names).await
1744    }
1745
1746    async fn get_account_data_event(
1747        &self,
1748        event_type: GlobalAccountDataEventType,
1749    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
1750        self.store.get_account_data_event(event_type).await
1751    }
1752
1753    async fn get_room_account_data_event(
1754        &self,
1755        room_id: &RoomId,
1756        event_type: RoomAccountDataEventType,
1757    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
1758        self.store.get_room_account_data_event(room_id, event_type).await
1759    }
1760
1761    async fn get_user_room_receipt_event(
1762        &self,
1763        room_id: &RoomId,
1764        receipt_type: ReceiptType,
1765        receipt_thread: &ReceiptThread,
1766        user_id: &UserId,
1767    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
1768        self.store.get_user_room_receipt_event(room_id, receipt_type, receipt_thread, user_id).await
1769    }
1770
1771    async fn get_event_room_receipt_events(
1772        &self,
1773        room_id: &RoomId,
1774        receipt_type: ReceiptType,
1775        receipt_thread: &ReceiptThread,
1776        event_id: &EventId,
1777    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
1778        self.store
1779            .get_event_room_receipt_events(room_id, receipt_type, receipt_thread, event_id)
1780            .await
1781    }
1782
1783    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
1784        self.store.get_custom_value(key).await
1785    }
1786
1787    async fn set_custom_value(
1788        &self,
1789        key: &[u8],
1790        value: Vec<u8>,
1791    ) -> Result<Option<Vec<u8>>, Self::Error> {
1792        self.store.set_custom_value(key, value).await
1793    }
1794
1795    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
1796        self.store.remove_custom_value(key).await
1797    }
1798
1799    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
1800        let _guard = self.lock.lock().await;
1801        self.store.remove_room(room_id).await
1802    }
1803
1804    async fn save_send_queue_request(
1805        &self,
1806        room_id: &RoomId,
1807        transaction_id: OwnedTransactionId,
1808        created_at: MilliSecondsSinceUnixEpoch,
1809        request: QueuedRequestKind,
1810        priority: usize,
1811    ) -> Result<(), Self::Error> {
1812        self.store
1813            .save_send_queue_request(room_id, transaction_id, created_at, request, priority)
1814            .await
1815    }
1816
1817    async fn update_send_queue_request(
1818        &self,
1819        room_id: &RoomId,
1820        transaction_id: &TransactionId,
1821        content: QueuedRequestKind,
1822    ) -> Result<bool, Self::Error> {
1823        self.store.update_send_queue_request(room_id, transaction_id, content).await
1824    }
1825
1826    async fn remove_send_queue_request(
1827        &self,
1828        room_id: &RoomId,
1829        transaction_id: &TransactionId,
1830    ) -> Result<bool, Self::Error> {
1831        self.store.remove_send_queue_request(room_id, transaction_id).await
1832    }
1833
1834    async fn load_send_queue_requests(
1835        &self,
1836        room_id: &RoomId,
1837    ) -> Result<Vec<QueuedRequest>, Self::Error> {
1838        self.store.load_send_queue_requests(room_id).await
1839    }
1840
1841    async fn update_send_queue_request_status(
1842        &self,
1843        room_id: &RoomId,
1844        transaction_id: &TransactionId,
1845        error: Option<QueueWedgeError>,
1846    ) -> Result<(), Self::Error> {
1847        self.store.update_send_queue_request_status(room_id, transaction_id, error).await
1848    }
1849
1850    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
1851        self.store.load_rooms_with_unsent_requests().await
1852    }
1853
1854    async fn save_dependent_queued_request(
1855        &self,
1856        room_id: &RoomId,
1857        parent_txn_id: &TransactionId,
1858        own_txn_id: ChildTransactionId,
1859        created_at: MilliSecondsSinceUnixEpoch,
1860        content: DependentQueuedRequestKind,
1861    ) -> Result<(), Self::Error> {
1862        self.store
1863            .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
1864            .await
1865    }
1866
1867    async fn mark_dependent_queued_requests_as_ready(
1868        &self,
1869        room_id: &RoomId,
1870        parent_txn_id: &TransactionId,
1871        sent_parent_key: SentRequestKey,
1872    ) -> Result<usize, Self::Error> {
1873        self.store
1874            .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
1875            .await
1876    }
1877
1878    async fn update_dependent_queued_request(
1879        &self,
1880        room_id: &RoomId,
1881        own_transaction_id: &ChildTransactionId,
1882        new_content: DependentQueuedRequestKind,
1883    ) -> Result<bool, Self::Error> {
1884        self.store.update_dependent_queued_request(room_id, own_transaction_id, new_content).await
1885    }
1886
1887    async fn remove_dependent_queued_request(
1888        &self,
1889        room: &RoomId,
1890        own_txn_id: &ChildTransactionId,
1891    ) -> Result<bool, Self::Error> {
1892        self.store.remove_dependent_queued_request(room, own_txn_id).await
1893    }
1894
1895    async fn load_dependent_queued_requests(
1896        &self,
1897        room: &RoomId,
1898    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
1899        self.store.load_dependent_queued_requests(room).await
1900    }
1901
1902    async fn upsert_thread_subscriptions(
1903        &self,
1904        updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
1905    ) -> Result<(), Self::Error> {
1906        self.store.upsert_thread_subscriptions(updates).await
1907    }
1908
1909    async fn load_thread_subscription(
1910        &self,
1911        room: &RoomId,
1912        thread_id: &EventId,
1913    ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
1914        self.store.load_thread_subscription(room, thread_id).await
1915    }
1916
1917    async fn remove_thread_subscription(
1918        &self,
1919        room: &RoomId,
1920        thread_id: &EventId,
1921    ) -> Result<(), Self::Error> {
1922        self.store.remove_thread_subscription(room, thread_id).await
1923    }
1924
1925    async fn get_global_profile(
1926        &self,
1927        user_id: &UserId,
1928    ) -> Result<Option<UserProfile>, Self::Error> {
1929        self.store.get_global_profile(user_id).await
1930    }
1931
1932    async fn get_global_profiles<'a>(
1933        &self,
1934        user_ids: &'a [OwnedUserId],
1935    ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error> {
1936        self.store.get_global_profiles(user_ids).await
1937    }
1938
1939    async fn close(&self) -> Result<(), Self::Error> {
1940        self.store.close().await
1941    }
1942
1943    async fn reopen(&self) -> Result<(), Self::Error> {
1944        self.store.reopen().await
1945    }
1946
1947    async fn optimize(&self) -> Result<(), Self::Error> {
1948        self.store.optimize().await
1949    }
1950
1951    async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1952        self.store.get_size().await
1953    }
1954}
1955
1956/// Convenience functionality for state stores.
1957#[cfg_attr(target_family = "wasm", async_trait(?Send))]
1958#[cfg_attr(not(target_family = "wasm"), async_trait)]
1959pub trait StateStoreExt: StateStore {
1960    /// Get a specific state event of statically-known type.
1961    ///
1962    /// # Arguments
1963    ///
1964    /// * `room_id` - The id of the room the state event was received for.
1965    async fn get_state_event_static<C>(
1966        &self,
1967        room_id: &RoomId,
1968    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
1969    where
1970        C: StaticEventContent<IsPrefix = ruma::events::False>
1971            + StaticStateEventContent<StateKey = EmptyStateKey>
1972            + RedactContent,
1973        C::Redacted: RedactedStateEventContent,
1974    {
1975        Ok(self.get_state_event(room_id, C::TYPE.into(), "").await?.map(|raw| raw.cast()))
1976    }
1977
1978    /// Get a specific state event of statically-known type.
1979    ///
1980    /// # Arguments
1981    ///
1982    /// * `room_id` - The id of the room the state event was received for.
1983    async fn get_state_event_static_for_key<C, K>(
1984        &self,
1985        room_id: &RoomId,
1986        state_key: &K,
1987    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
1988    where
1989        C: StaticEventContent<IsPrefix = ruma::events::False>
1990            + StaticStateEventContent
1991            + RedactContent,
1992        C::StateKey: Borrow<K>,
1993        C::Redacted: RedactedStateEventContent,
1994        K: AsRef<str> + ?Sized + Sync,
1995    {
1996        Ok(self
1997            .get_state_event(room_id, C::TYPE.into(), state_key.as_ref())
1998            .await?
1999            .map(|raw| raw.cast()))
2000    }
2001
2002    /// Get a list of state events of a statically-known type for a given room.
2003    ///
2004    /// # Arguments
2005    ///
2006    /// * `room_id` - The id of the room to find events for.
2007    async fn get_state_events_static<C>(
2008        &self,
2009        room_id: &RoomId,
2010    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
2011    where
2012        C: StaticEventContent<IsPrefix = ruma::events::False>
2013            + StaticStateEventContent
2014            + RedactContent,
2015        C::Redacted: RedactedStateEventContent,
2016    {
2017        // FIXME: Could be more efficient, if we had streaming store accessor functions
2018        Ok(self
2019            .get_state_events(room_id, C::TYPE.into())
2020            .await?
2021            .into_iter()
2022            .map(|raw| raw.cast())
2023            .collect())
2024    }
2025
2026    /// Get a list of state events of a statically-known type for a given room
2027    /// and given state keys.
2028    ///
2029    /// # Arguments
2030    ///
2031    /// * `room_id` - The id of the room to find events for.
2032    ///
2033    /// * `state_keys` - The list of state keys to find.
2034    async fn get_state_events_for_keys_static<'a, C, K, I>(
2035        &self,
2036        room_id: &RoomId,
2037        state_keys: I,
2038    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
2039    where
2040        C: StaticEventContent<IsPrefix = ruma::events::False>
2041            + StaticStateEventContent
2042            + RedactContent,
2043        C::StateKey: Borrow<K>,
2044        C::Redacted: RedactedStateEventContent,
2045        K: AsRef<str> + Sized + Sync + 'a,
2046        I: IntoIterator<Item = &'a K> + Send,
2047        I::IntoIter: Send,
2048    {
2049        Ok(self
2050            .get_state_events_for_keys(
2051                room_id,
2052                C::TYPE.into(),
2053                &state_keys.into_iter().map(|k| k.as_ref()).collect::<Vec<_>>(),
2054            )
2055            .await?
2056            .into_iter()
2057            .map(|raw| raw.cast())
2058            .collect())
2059    }
2060
2061    /// Get an event of a statically-known type from the account data store.
2062    async fn get_account_data_event_static<C>(
2063        &self,
2064    ) -> Result<Option<Raw<GlobalAccountDataEvent<C>>>, Self::Error>
2065    where
2066        C: StaticEventContent<IsPrefix = ruma::events::False> + GlobalAccountDataEventContent,
2067    {
2068        Ok(self.get_account_data_event(C::TYPE.into()).await?.map(Raw::cast_unchecked))
2069    }
2070
2071    /// Get an event of a statically-known type from the room account data
2072    /// store.
2073    ///
2074    /// # Arguments
2075    ///
2076    /// * `room_id` - The id of the room for which the room account data event
2077    ///   should be fetched.
2078    async fn get_room_account_data_event_static<C>(
2079        &self,
2080        room_id: &RoomId,
2081    ) -> Result<Option<Raw<RoomAccountDataEvent<C>>>, Self::Error>
2082    where
2083        C: StaticEventContent<IsPrefix = ruma::events::False> + RoomAccountDataEventContent,
2084    {
2085        Ok(self
2086            .get_room_account_data_event(room_id, C::TYPE.into())
2087            .await?
2088            .map(Raw::cast_unchecked))
2089    }
2090
2091    /// Get the `MemberEvent` for the given state key in the given room id.
2092    ///
2093    /// # Arguments
2094    ///
2095    /// * `room_id` - The room id the member event belongs to.
2096    ///
2097    /// * `state_key` - The user id that the member event defines the state for.
2098    async fn get_member_event(
2099        &self,
2100        room_id: &RoomId,
2101        state_key: &UserId,
2102    ) -> Result<Option<RawMemberEvent>, Self::Error> {
2103        self.get_state_event_static_for_key(room_id, state_key).await
2104    }
2105}
2106
2107#[cfg_attr(target_family = "wasm", async_trait(?Send))]
2108#[cfg_attr(not(target_family = "wasm"), async_trait)]
2109impl<T: StateStore + ?Sized> StateStoreExt for T {}
2110
2111/// A type-erased [`StateStore`].
2112pub type DynStateStore = dyn StateStore<Error = StoreError>;
2113
2114/// A type that can be type-erased into `Arc<dyn StateStore>`.
2115///
2116/// This trait is not meant to be implemented directly outside
2117/// `matrix-sdk-crypto`, but it is automatically implemented for everything that
2118/// implements `StateStore`.
2119pub trait IntoStateStore {
2120    #[doc(hidden)]
2121    fn into_state_store(self) -> Arc<DynStateStore>;
2122}
2123
2124impl<T> IntoStateStore for T
2125where
2126    T: StateStore + Sized + 'static,
2127{
2128    fn into_state_store(self) -> Arc<DynStateStore> {
2129        Arc::new(EraseStateStoreError(self))
2130    }
2131}
2132
2133/// Serialisable representation of get_supported_versions::Response.
2134#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2135pub struct SupportedVersionsResponse {
2136    /// Versions supported by the remote server.
2137    pub versions: Vec<String>,
2138
2139    /// List of unstable features and their enablement status.
2140    pub unstable_features: BTreeMap<String, bool>,
2141}
2142
2143impl SupportedVersionsResponse {
2144    /// Extracts known Matrix versions and features from the un-typed lists of
2145    /// strings.
2146    ///
2147    /// Note: Matrix versions and features that Ruma cannot parse, or does not
2148    /// know about, are discarded.
2149    pub fn supported_versions(&self) -> SupportedVersions {
2150        let mut supported_versions =
2151            SupportedVersions::from_parts(&self.versions, &self.unstable_features);
2152
2153        // We need at least one supported version to be able to make requests, so we
2154        // default to Matrix 1.0.
2155        if supported_versions.versions.is_empty() {
2156            supported_versions.versions.insert(MatrixVersion::V1_0);
2157        }
2158
2159        supported_versions
2160    }
2161}
2162
2163#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2164/// A serialisable representation of discover_homeserver::Response.
2165pub struct WellKnownResponse {
2166    /// Information about the homeserver to connect to.
2167    pub homeserver: HomeserverInfo,
2168
2169    /// Information about the identity server to connect to.
2170    pub identity_server: Option<IdentityServerInfo>,
2171
2172    /// Information about the tile server to use to display location data.
2173    pub tile_server: Option<TileServerInfo>,
2174
2175    /// A list of the available MatrixRTC foci, ordered by priority.
2176    pub rtc_foci: Vec<RtcTransport>,
2177}
2178
2179impl From<discover_homeserver::Response> for WellKnownResponse {
2180    fn from(response: discover_homeserver::Response) -> Self {
2181        Self {
2182            homeserver: response.homeserver,
2183            identity_server: response.identity_server,
2184            tile_server: response.tile_server,
2185            rtc_foci: response.rtc_foci,
2186        }
2187    }
2188}
2189
2190/// A value for key-value data that should be persisted into the store.
2191#[derive(Debug, Clone)]
2192pub enum StateStoreDataValue {
2193    /// The sync token.
2194    SyncToken(String),
2195
2196    /// The supported versions of the server.
2197    SupportedVersions(TtlValue<SupportedVersionsResponse>),
2198
2199    /// The well-known information of the server.
2200    WellKnown(TtlValue<Option<WellKnownResponse>>),
2201
2202    /// A filter with the given ID.
2203    Filter(String),
2204
2205    /// The user avatar url
2206    UserAvatarUrl(OwnedMxcUri),
2207
2208    /// A list of recently visited room identifiers for the current user
2209    RecentlyVisitedRooms(Vec<OwnedRoomId>),
2210
2211    /// Persistent data for
2212    /// `matrix_sdk_ui::unable_to_decrypt_hook::UtdHookManager`.
2213    UtdHookManagerData(GrowableBloom),
2214
2215    /// A unit value telling us that the client uploaded duplicate one-time
2216    /// keys.
2217    OneTimeKeyAlreadyUploaded,
2218
2219    /// A composer draft for the room.
2220    /// To learn more, see [`ComposerDraft`].
2221    ///
2222    /// [`ComposerDraft`]: Self::ComposerDraft
2223    ComposerDraft(ComposerDraft),
2224
2225    /// A list of knock request ids marked as seen in a room.
2226    SeenKnockRequests(BTreeMap<OwnedEventId, OwnedUserId>),
2227
2228    /// A list of tokens to continue thread subscriptions catchup.
2229    ///
2230    /// See documentation of [`ThreadSubscriptionCatchupToken`] for more
2231    /// details.
2232    ThreadSubscriptionsCatchupTokens(Vec<ThreadSubscriptionCatchupToken>),
2233
2234    /// The capabilities the homeserver supports or disables.
2235    HomeserverCapabilities(TtlValue<Capabilities>),
2236}
2237
2238/// Tokens to use when catching up on thread subscriptions.
2239///
2240/// These tokens are created when the client receives some thread subscriptions
2241/// from sync, but the sync indicates that there are more thread subscriptions
2242/// available on the server. In this case, it's expected that the client will
2243/// call the [MSC4308] companion endpoint to catch up (back-paginate) on
2244/// previous thread subscriptions.
2245///
2246/// [MSC4308]: https://github.com/matrix-org/matrix-spec-proposals/pull/4308
2247#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2248pub struct ThreadSubscriptionCatchupToken {
2249    /// The token to use as the lower bound when fetching new threads
2250    /// subscriptions.
2251    ///
2252    /// In sliding sync, this is the `prev_batch` value of a sliding sync
2253    /// response.
2254    pub from: String,
2255
2256    /// The token to use as the upper bound when fetching new threads
2257    /// subscriptions.
2258    ///
2259    /// In sliding sync, it must be set to the `pos` value of the sliding sync
2260    /// *request*, which response received a `prev_batch` token.
2261    pub to: Option<String>,
2262}
2263
2264/// Current draft of the composer for the room.
2265#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2266pub struct ComposerDraft {
2267    /// The draft content in plain text.
2268    pub plain_text: String,
2269    /// If the message is formatted in HTML, the HTML representation of the
2270    /// message.
2271    pub html_text: Option<String>,
2272    /// The type of draft.
2273    pub draft_type: ComposerDraftType,
2274    /// Attachments associated with this draft.
2275    #[serde(default)]
2276    pub attachments: Vec<DraftAttachment>,
2277}
2278
2279/// An attachment stored with a composer draft.
2280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2281pub struct DraftAttachment {
2282    /// The filename of the attachment.
2283    pub filename: String,
2284    /// The attachment content with type-specific data.
2285    pub content: DraftAttachmentContent,
2286}
2287
2288/// The content of a draft attachment with type-specific data.
2289#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2290#[serde(tag = "type")]
2291pub enum DraftAttachmentContent {
2292    /// Image attachment.
2293    Image {
2294        /// The image file data.
2295        data: Vec<u8>,
2296        /// MIME type.
2297        mimetype: Option<String>,
2298        /// File size in bytes.
2299        size: Option<u64>,
2300        /// Width in pixels.
2301        width: Option<u64>,
2302        /// Height in pixels.
2303        height: Option<u64>,
2304        /// BlurHash string.
2305        blurhash: Option<String>,
2306        /// Optional thumbnail.
2307        thumbnail: Option<DraftThumbnail>,
2308    },
2309    /// Video attachment.
2310    Video {
2311        /// The video file data.
2312        data: Vec<u8>,
2313        /// MIME type.
2314        mimetype: Option<String>,
2315        /// File size in bytes.
2316        size: Option<u64>,
2317        /// Width in pixels.
2318        width: Option<u64>,
2319        /// Height in pixels.
2320        height: Option<u64>,
2321        /// Duration.
2322        duration: Option<std::time::Duration>,
2323        /// BlurHash string.
2324        blurhash: Option<String>,
2325        /// Optional thumbnail.
2326        thumbnail: Option<DraftThumbnail>,
2327    },
2328    /// Audio attachment.
2329    Audio {
2330        /// The audio file data.
2331        data: Vec<u8>,
2332        /// MIME type.
2333        mimetype: Option<String>,
2334        /// File size in bytes.
2335        size: Option<u64>,
2336        /// Duration.
2337        duration: Option<std::time::Duration>,
2338    },
2339    /// Generic file attachment.
2340    File {
2341        /// The file data.
2342        data: Vec<u8>,
2343        /// MIME type.
2344        mimetype: Option<String>,
2345        /// File size in bytes.
2346        size: Option<u64>,
2347    },
2348}
2349
2350/// Thumbnail data for a draft attachment.
2351#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2352pub struct DraftThumbnail {
2353    /// The filename of the thumbnail.
2354    pub filename: String,
2355    /// The thumbnail image data.
2356    pub data: Vec<u8>,
2357    /// MIME type of the thumbnail.
2358    pub mimetype: Option<String>,
2359    /// Width in pixels.
2360    pub width: Option<u64>,
2361    /// Height in pixels.
2362    pub height: Option<u64>,
2363    /// File size in bytes.
2364    pub size: Option<u64>,
2365}
2366
2367/// The type of draft of the composer.
2368#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2369pub enum ComposerDraftType {
2370    /// The draft is a new message.
2371    NewMessage,
2372    /// The draft is a reply to an event.
2373    Reply {
2374        /// The ID of the event being replied to.
2375        event_id: OwnedEventId,
2376    },
2377    /// The draft is an edit of an event.
2378    Edit {
2379        /// The ID of the event being edited.
2380        event_id: OwnedEventId,
2381    },
2382}
2383
2384impl StateStoreDataValue {
2385    /// Get this value if it is a sync token.
2386    pub fn into_sync_token(self) -> Option<String> {
2387        as_variant!(self, Self::SyncToken)
2388    }
2389
2390    /// Get this value if it is a filter.
2391    pub fn into_filter(self) -> Option<String> {
2392        as_variant!(self, Self::Filter)
2393    }
2394
2395    /// Get this value if it is a user avatar url.
2396    pub fn into_user_avatar_url(self) -> Option<OwnedMxcUri> {
2397        as_variant!(self, Self::UserAvatarUrl)
2398    }
2399
2400    /// Get this value if it is a list of recently visited rooms.
2401    pub fn into_recently_visited_rooms(self) -> Option<Vec<OwnedRoomId>> {
2402        as_variant!(self, Self::RecentlyVisitedRooms)
2403    }
2404
2405    /// Get this value if it is the data for the `UtdHookManager`.
2406    pub fn into_utd_hook_manager_data(self) -> Option<GrowableBloom> {
2407        as_variant!(self, Self::UtdHookManagerData)
2408    }
2409
2410    /// Get this value if it is a composer draft.
2411    pub fn into_composer_draft(self) -> Option<ComposerDraft> {
2412        as_variant!(self, Self::ComposerDraft)
2413    }
2414
2415    /// Get this value if it is the supported versions metadata.
2416    pub fn into_supported_versions(self) -> Option<TtlValue<SupportedVersionsResponse>> {
2417        as_variant!(self, Self::SupportedVersions)
2418    }
2419
2420    /// Get this value if it is the well-known metadata.
2421    pub fn into_well_known(self) -> Option<TtlValue<Option<WellKnownResponse>>> {
2422        as_variant!(self, Self::WellKnown)
2423    }
2424
2425    /// Get this value if it is the data for the ignored join requests.
2426    pub fn into_seen_knock_requests(self) -> Option<BTreeMap<OwnedEventId, OwnedUserId>> {
2427        as_variant!(self, Self::SeenKnockRequests)
2428    }
2429
2430    /// Get this value if it is the data for the thread subscriptions catchup
2431    /// tokens.
2432    pub fn into_thread_subscriptions_catchup_tokens(
2433        self,
2434    ) -> Option<Vec<ThreadSubscriptionCatchupToken>> {
2435        as_variant!(self, Self::ThreadSubscriptionsCatchupTokens)
2436    }
2437
2438    /// Get this value if it is the data for the capabilities the homeserver
2439    /// supports or disables.
2440    pub fn into_homeserver_capabilities(self) -> Option<TtlValue<Capabilities>> {
2441        as_variant!(self, Self::HomeserverCapabilities)
2442    }
2443}
2444
2445/// A key for key-value data.
2446#[derive(Debug, Clone, Copy)]
2447pub enum StateStoreDataKey<'a> {
2448    /// The sync token.
2449    SyncToken,
2450
2451    /// The supported versions of the server,
2452    SupportedVersions,
2453
2454    /// The well-known information of the server,
2455    WellKnown,
2456
2457    /// A filter with the given name.
2458    Filter(&'a str),
2459
2460    /// Avatar URL
2461    UserAvatarUrl(&'a UserId),
2462
2463    /// Recently visited room identifiers
2464    RecentlyVisitedRooms(&'a UserId),
2465
2466    /// Persistent data for
2467    /// `matrix_sdk_ui::unable_to_decrypt_hook::UtdHookManager`.
2468    UtdHookManagerData,
2469
2470    /// Data remembering if the client already reported that it has uploaded
2471    /// duplicate one-time keys.
2472    OneTimeKeyAlreadyUploaded,
2473
2474    /// A composer draft for the room.
2475    /// To learn more, see [`ComposerDraft`].
2476    ///
2477    /// [`ComposerDraft`]: Self::ComposerDraft
2478    ComposerDraft(&'a RoomId, Option<&'a EventId>),
2479
2480    /// A list of knock request ids marked as seen in a room.
2481    SeenKnockRequests(&'a RoomId),
2482
2483    /// A list of thread subscriptions catchup tokens.
2484    ThreadSubscriptionsCatchupTokens,
2485
2486    /// A list of capabilities that the homeserver supports.
2487    HomeserverCapabilities,
2488}
2489
2490impl StateStoreDataKey<'_> {
2491    /// Key to use for the [`SyncToken`][Self::SyncToken] variant.
2492    pub const SYNC_TOKEN: &'static str = "sync_token";
2493
2494    /// Key to use for the [`SupportedVersions`][Self::SupportedVersions]
2495    /// variant.
2496    pub const SUPPORTED_VERSIONS: &'static str = "server_capabilities"; // Note: this is the old name, kept for backwards compatibility.
2497
2498    /// Key to use for the [`WellKnown`][Self::WellKnown]
2499    /// variant.
2500    pub const WELL_KNOWN: &'static str = "well_known";
2501
2502    /// Key prefix to use for the [`Filter`][Self::Filter] variant.
2503    pub const FILTER: &'static str = "filter";
2504
2505    /// Key prefix to use for the [`UserAvatarUrl`][Self::UserAvatarUrl]
2506    /// variant.
2507    pub const USER_AVATAR_URL: &'static str = "user_avatar_url";
2508
2509    /// Key prefix to use for the
2510    /// [`RecentlyVisitedRooms`][Self::RecentlyVisitedRooms] variant.
2511    pub const RECENTLY_VISITED_ROOMS: &'static str = "recently_visited_rooms";
2512
2513    /// Key to use for the [`UtdHookManagerData`][Self::UtdHookManagerData]
2514    /// variant.
2515    pub const UTD_HOOK_MANAGER_DATA: &'static str = "utd_hook_manager_data";
2516
2517    /// Key to use for the flag remembering that we already reported that we
2518    /// uploaded duplicate one-time keys.
2519    pub const ONE_TIME_KEY_ALREADY_UPLOADED: &'static str = "one_time_key_already_uploaded";
2520
2521    /// Key prefix to use for the [`ComposerDraft`][Self::ComposerDraft]
2522    /// variant.
2523    pub const COMPOSER_DRAFT: &'static str = "composer_draft";
2524
2525    /// Key prefix to use for the
2526    /// [`SeenKnockRequests`][Self::SeenKnockRequests] variant.
2527    pub const SEEN_KNOCK_REQUESTS: &'static str = "seen_knock_requests";
2528
2529    /// Key prefix to use for the
2530    /// [`ThreadSubscriptionsCatchupTokens`][Self::ThreadSubscriptionsCatchupTokens] variant.
2531    pub const THREAD_SUBSCRIPTIONS_CATCHUP_TOKENS: &'static str =
2532        "thread_subscriptions_catchup_tokens";
2533
2534    /// Key prefix to use for the homeserver's [`Capabilities`].
2535    pub const HOMESERVER_CAPABILITIES: &'static str = "homeserver_capabilities";
2536}
2537
2538/// Compare two thread subscription changes bump stamps, given a fixed room and
2539/// thread root event id pair.
2540///
2541/// May update the newer one to keep the previous one if needed, under some
2542/// conditions.
2543///
2544/// Returns true if the new subscription should be stored, or false if the new
2545/// subscription should be ignored.
2546pub fn compare_thread_subscription_bump_stamps(
2547    previous: Option<u64>,
2548    new: &mut Option<u64>,
2549) -> bool {
2550    match (previous, &new) {
2551        // If the previous subscription had a bump stamp, and the new one doesn't, keep the
2552        // previous one; it should be updated soon via sync anyways.
2553        (Some(prev_bump), None) => {
2554            *new = Some(prev_bump);
2555        }
2556
2557        // If the previous bump stamp is newer than the new one, don't store the value at all.
2558        (Some(prev_bump), Some(new_bump)) if *new_bump <= prev_bump => {
2559            return false;
2560        }
2561
2562        // In all other cases, keep the new bumpstamp.
2563        _ => {}
2564    }
2565
2566    true
2567}
2568
2569#[cfg(test)]
2570mod tests {
2571    mod save_locked_state_store {
2572        use std::time::Duration;
2573
2574        use assert_matches::assert_matches;
2575        use futures_util::future::{self, Either};
2576        #[cfg(all(target_family = "wasm", target_os = "unknown"))]
2577        use gloo_timers::future::sleep;
2578        use matrix_sdk_common::executor::spawn;
2579        use matrix_sdk_test::async_test;
2580        use ruma::room_id;
2581        use tokio::sync::Mutex;
2582        #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2583        use tokio::time::sleep;
2584
2585        use crate::{
2586            StateChanges, StateStore,
2587            store::{IntoStateStore, MemoryStore, Result, SaveLockedStateStore},
2588        };
2589
2590        async fn get_store() -> Result<impl StateStore> {
2591            Ok(SaveLockedStateStore::new(MemoryStore::new()))
2592        }
2593
2594        statestore_integration_tests!();
2595
2596        #[async_test]
2597        async fn test_save_changes_only_accepts_guard_for_underlying_mutex() {
2598            let state_store = SaveLockedStateStore::new(MemoryStore::new());
2599            let state_changes = StateChanges::default();
2600            state_store
2601                .save_changes_with_guard(&state_store.lock().lock().await, &state_changes)
2602                .await
2603                .expect("state store accepts guard for underlying mutex");
2604
2605            let mutex = Mutex::new(());
2606            state_store
2607                .save_changes_with_guard(&mutex.lock().await, &state_changes)
2608                .await
2609                .expect_err("state store does not accept guard for unknown mutex");
2610        }
2611
2612        #[async_test]
2613        async fn test_remove_room_only_accepts_guard_for_underlying_mutex() {
2614            let state_store = SaveLockedStateStore::new(MemoryStore::new());
2615            let room_id = room_id!("!room");
2616            state_store
2617                .remove_room_with_guard(&state_store.lock().lock().await, room_id)
2618                .await
2619                .expect("state store accepts guard for underlying mutex");
2620
2621            let mutex = Mutex::new(());
2622            state_store
2623                .remove_room_with_guard(&mutex.lock().await, room_id)
2624                .await
2625                .expect_err("state store does not accept guard for unknown mutex");
2626        }
2627
2628        #[derive(Debug)]
2629        struct Elapsed;
2630
2631        async fn timeout<F: Future + Unpin>(
2632            duration: Duration,
2633            f: F,
2634        ) -> Result<F::Output, Elapsed> {
2635            #[cfg(all(target_family = "wasm", target_os = "unknown"))]
2636            {
2637                match future::select(sleep(duration), f).await {
2638                    Either::Left(_) => return Err(Elapsed),
2639                    Either::Right((output, _)) => Ok(output),
2640                }
2641            }
2642            #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
2643            {
2644                tokio::time::timeout(duration, f).await.map_err(|_| Elapsed)
2645            }
2646        }
2647
2648        #[async_test]
2649        async fn test_state_store_waits_to_acquire_lock_before_saving_changes() {
2650            let state_store = SaveLockedStateStore::new(MemoryStore::new().into_state_store());
2651
2652            // Acquire lock and hold it for 5 seconds
2653            let lock_task = spawn({
2654                let state_store = state_store.clone();
2655                async move {
2656                    let lock = state_store.lock();
2657                    let _guard = lock.lock().await;
2658                    sleep(Duration::from_secs(5)).await;
2659                }
2660            });
2661
2662            // Try to save changes to the state store while the lock is held by another task
2663            let save_task =
2664                spawn(async move { state_store.save_changes(&StateChanges::default()).await });
2665
2666            // Ensure that the second task does not progress until the first task has
2667            // completed and therefore release the save lock
2668            assert_matches!(future::select(lock_task, save_task).await, Either::Left((_, save_task)) => {
2669                timeout(Duration::from_millis(100), save_task)
2670                    .await
2671                    .expect("task completes before timeout")
2672                    .expect("task completes successfully")
2673                    .expect("task saves changes");
2674            });
2675        }
2676
2677        #[async_test]
2678        async fn test_state_store_waits_to_acquire_lock_before_removing_room() {
2679            let state_store = SaveLockedStateStore::new(MemoryStore::new().into_state_store());
2680
2681            // Acquire lock and hold it for 5 seconds
2682            let lock_task = spawn({
2683                let state_store = state_store.clone();
2684                async move {
2685                    let lock = state_store.lock();
2686                    let _guard = lock.lock().await;
2687                    sleep(Duration::from_secs(5)).await;
2688                }
2689            });
2690
2691            // Try to remove room from the state store while the lock is held by another
2692            // task
2693            let remove_task =
2694                spawn(async move { state_store.remove_room(room_id!("!room")).await });
2695
2696            // Ensure that the second task does not progress until the first task has
2697            // completed and therefore release the save lock
2698            assert_matches!(future::select(lock_task, remove_task).await, Either::Left((_, remove_task)) => {
2699                timeout(Duration::from_millis(100), remove_task)
2700                    .await
2701                    .expect("task completes before timeout")
2702                    .expect("task completes successfully")
2703                    .expect("task saves changes");
2704            });
2705        }
2706    }
2707}