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    sync::Arc,
20};
21
22use as_variant::as_variant;
23use async_trait::async_trait;
24use growable_bloom_filter::GrowableBloom;
25use matrix_sdk_common::AsyncTraitDeps;
26use ruma::{
27    api::MatrixVersion,
28    events::{
29        presence::PresenceEvent,
30        receipt::{Receipt, ReceiptThread, ReceiptType},
31        AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, EmptyStateKey, GlobalAccountDataEvent,
32        GlobalAccountDataEventContent, GlobalAccountDataEventType, RedactContent,
33        RedactedStateEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
34        RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
35    },
36    serde::Raw,
37    time::SystemTime,
38    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId,
39    OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId,
40};
41use serde::{Deserialize, Serialize};
42
43use super::{
44    send_queue::SentRequestKey, ChildTransactionId, DependentQueuedRequest,
45    DependentQueuedRequestKind, QueueWedgeError, QueuedRequest, QueuedRequestKind, StateChanges,
46    StoreError,
47};
48use crate::{
49    deserialized_responses::{
50        DisplayName, RawAnySyncOrStrippedState, RawMemberEvent, RawSyncOrStrippedState,
51    },
52    MinimalRoomMemberEvent, RoomInfo, RoomMemberships,
53};
54
55/// An abstract state store trait that can be used to implement different stores
56/// for the SDK.
57#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
58#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
59pub trait StateStore: AsyncTraitDeps {
60    /// The error type used by this state store.
61    type Error: fmt::Debug + Into<StoreError> + From<serde_json::Error>;
62
63    /// Get key-value data from the store.
64    ///
65    /// # Arguments
66    ///
67    /// * `key` - The key to fetch data for.
68    async fn get_kv_data(
69        &self,
70        key: StateStoreDataKey<'_>,
71    ) -> Result<Option<StateStoreDataValue>, Self::Error>;
72
73    /// Put key-value data into the store.
74    ///
75    /// # Arguments
76    ///
77    /// * `key` - The key to identify the data in the store.
78    ///
79    /// * `value` - The data to insert.
80    ///
81    /// Panics if the key and value variants do not match.
82    async fn set_kv_data(
83        &self,
84        key: StateStoreDataKey<'_>,
85        value: StateStoreDataValue,
86    ) -> Result<(), Self::Error>;
87
88    /// Remove key-value data from the store.
89    ///
90    /// # Arguments
91    ///
92    /// * `key` - The key to remove the data for.
93    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error>;
94
95    /// Save the set of state changes in the store.
96    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error>;
97
98    /// Get the stored presence event for the given user.
99    ///
100    /// # Arguments
101    ///
102    /// * `user_id` - The id of the user for which we wish to fetch the presence
103    /// event for.
104    async fn get_presence_event(
105        &self,
106        user_id: &UserId,
107    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error>;
108
109    /// Get the stored presence events for the given users.
110    ///
111    /// # Arguments
112    ///
113    /// * `user_ids` - The IDs of the users to fetch the presence events for.
114    async fn get_presence_events(
115        &self,
116        user_ids: &[OwnedUserId],
117    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error>;
118
119    /// Get a state event out of the state store.
120    ///
121    /// # Arguments
122    ///
123    /// * `room_id` - The id of the room the state event was received for.
124    ///
125    /// * `event_type` - The event type of the state event.
126    async fn get_state_event(
127        &self,
128        room_id: &RoomId,
129        event_type: StateEventType,
130        state_key: &str,
131    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error>;
132
133    /// Get a list of state events for a given room and `StateEventType`.
134    ///
135    /// # Arguments
136    ///
137    /// * `room_id` - The id of the room to find events for.
138    ///
139    /// * `event_type` - The event type.
140    async fn get_state_events(
141        &self,
142        room_id: &RoomId,
143        event_type: StateEventType,
144    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
145
146    /// Get a list of state events for a given room, `StateEventType`, and the
147    /// given state keys.
148    ///
149    /// # Arguments
150    ///
151    /// * `room_id` - The id of the room to find events for.
152    ///
153    /// * `event_type` - The event type.
154    ///
155    /// * `state_keys` - The list of state keys to find.
156    async fn get_state_events_for_keys(
157        &self,
158        room_id: &RoomId,
159        event_type: StateEventType,
160        state_keys: &[&str],
161    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
162
163    /// Get the current profile for the given user in the given room.
164    ///
165    /// # Arguments
166    ///
167    /// * `room_id` - The room id the profile is used in.
168    ///
169    /// * `user_id` - The id of the user the profile belongs to.
170    async fn get_profile(
171        &self,
172        room_id: &RoomId,
173        user_id: &UserId,
174    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error>;
175
176    /// Get the current profiles for the given users in the given room.
177    ///
178    /// # Arguments
179    ///
180    /// * `room_id` - The ID of the room the profiles are used in.
181    ///
182    /// * `user_ids` - The IDs of the users the profiles belong to.
183    async fn get_profiles<'a>(
184        &self,
185        room_id: &RoomId,
186        user_ids: &'a [OwnedUserId],
187    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error>;
188
189    /// Get the user ids of members for a given room with the given memberships,
190    /// for stripped and regular rooms alike.
191    async fn get_user_ids(
192        &self,
193        room_id: &RoomId,
194        memberships: RoomMemberships,
195    ) -> Result<Vec<OwnedUserId>, Self::Error>;
196
197    /// Get all the pure `RoomInfo`s the store knows about.
198    async fn get_room_infos(&self) -> Result<Vec<RoomInfo>, Self::Error>;
199
200    /// Get all the users that use the given display name in the given room.
201    ///
202    /// # Arguments
203    ///
204    /// * `room_id` - The id of the room for which the display name users should
205    /// be fetched for.
206    ///
207    /// * `display_name` - The display name that the users use.
208    async fn get_users_with_display_name(
209        &self,
210        room_id: &RoomId,
211        display_name: &DisplayName,
212    ) -> Result<BTreeSet<OwnedUserId>, Self::Error>;
213
214    /// Get all the users that use the given display names in the given room.
215    ///
216    /// # Arguments
217    ///
218    /// * `room_id` - The ID of the room to fetch the display names for.
219    ///
220    /// * `display_names` - The display names that the users use.
221    async fn get_users_with_display_names<'a>(
222        &self,
223        room_id: &RoomId,
224        display_names: &'a [DisplayName],
225    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error>;
226
227    /// Get an event out of the account data store.
228    ///
229    /// # Arguments
230    ///
231    /// * `event_type` - The event type of the account data event.
232    async fn get_account_data_event(
233        &self,
234        event_type: GlobalAccountDataEventType,
235    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error>;
236
237    /// Get an event out of the room account data store.
238    ///
239    /// # Arguments
240    ///
241    /// * `room_id` - The id of the room for which the room account data event
242    ///   should
243    /// be fetched.
244    ///
245    /// * `event_type` - The event type of the room account data event.
246    async fn get_room_account_data_event(
247        &self,
248        room_id: &RoomId,
249        event_type: RoomAccountDataEventType,
250    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error>;
251
252    /// Get an event out of the user room receipt store.
253    ///
254    /// # Arguments
255    ///
256    /// * `room_id` - The id of the room for which the receipt should be
257    ///   fetched.
258    ///
259    /// * `receipt_type` - The type of the receipt.
260    ///
261    /// * `thread` - The thread containing this receipt.
262    ///
263    /// * `user_id` - The id of the user for who the receipt should be fetched.
264    async fn get_user_room_receipt_event(
265        &self,
266        room_id: &RoomId,
267        receipt_type: ReceiptType,
268        thread: ReceiptThread,
269        user_id: &UserId,
270    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error>;
271
272    /// Get events out of the event room receipt store.
273    ///
274    /// # Arguments
275    ///
276    /// * `room_id` - The id of the room for which the receipts should be
277    ///   fetched.
278    ///
279    /// * `receipt_type` - The type of the receipts.
280    ///
281    /// * `thread` - The thread containing this receipt.
282    ///
283    /// * `event_id` - The id of the event for which the receipts should be
284    ///   fetched.
285    async fn get_event_room_receipt_events(
286        &self,
287        room_id: &RoomId,
288        receipt_type: ReceiptType,
289        thread: ReceiptThread,
290        event_id: &EventId,
291    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error>;
292
293    /// Get arbitrary data from the custom store
294    ///
295    /// # Arguments
296    ///
297    /// * `key` - The key to fetch data for
298    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
299
300    /// Put arbitrary data into the custom store, return the data previously
301    /// stored
302    ///
303    /// # Arguments
304    ///
305    /// * `key` - The key to insert data into
306    ///
307    /// * `value` - The value to insert
308    async fn set_custom_value(
309        &self,
310        key: &[u8],
311        value: Vec<u8>,
312    ) -> Result<Option<Vec<u8>>, Self::Error>;
313
314    /// Put arbitrary data into the custom store, do not attempt to read any
315    /// previous data
316    ///
317    /// Optimization option for set_custom_values for stores that would perform
318    /// better withouts the extra read and the caller not needing that data
319    /// returned. Otherwise this just wraps around `set_custom_data` and
320    /// discards the result.
321    ///
322    /// # Arguments
323    ///
324    /// * `key` - The key to insert data into
325    ///
326    /// * `value` - The value to insert
327    async fn set_custom_value_no_read(
328        &self,
329        key: &[u8],
330        value: Vec<u8>,
331    ) -> Result<(), Self::Error> {
332        self.set_custom_value(key, value).await.map(|_| ())
333    }
334
335    /// Remove arbitrary data from the custom store and return it if existed
336    ///
337    /// # Arguments
338    ///
339    /// * `key` - The key to remove data from
340    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
341
342    /// Remove a room and all elements associated from the state store.
343    ///
344    /// # Arguments
345    ///
346    /// * `room_id` - The `RoomId` of the room to delete.
347    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error>;
348
349    /// Save a request to be sent by a send queue later (e.g. sending an event).
350    ///
351    /// # Arguments
352    ///
353    /// * `room_id` - The `RoomId` of the send queue's room.
354    /// * `transaction_id` - The unique key identifying the event to be sent
355    ///   (and its transaction). Note: this is expected to be randomly generated
356    ///   and thus unique.
357    /// * `content` - Serializable event content to be sent.
358    async fn save_send_queue_request(
359        &self,
360        room_id: &RoomId,
361        transaction_id: OwnedTransactionId,
362        created_at: MilliSecondsSinceUnixEpoch,
363        request: QueuedRequestKind,
364        priority: usize,
365    ) -> Result<(), Self::Error>;
366
367    /// Updates a send queue request with the given content, and resets its
368    /// error status.
369    ///
370    /// # Arguments
371    ///
372    /// * `room_id` - The `RoomId` of the send queue's room.
373    /// * `transaction_id` - The unique key identifying the request to be sent
374    ///   (and its transaction).
375    /// * `content` - Serializable event content to replace the original one.
376    ///
377    /// Returns true if a request has been updated, or false otherwise.
378    async fn update_send_queue_request(
379        &self,
380        room_id: &RoomId,
381        transaction_id: &TransactionId,
382        content: QueuedRequestKind,
383    ) -> Result<bool, Self::Error>;
384
385    /// Remove a request previously inserted with
386    /// [`Self::save_send_queue_request`] from the database, based on its
387    /// transaction id.
388    ///
389    /// Returns true if something has been removed, or false otherwise.
390    async fn remove_send_queue_request(
391        &self,
392        room_id: &RoomId,
393        transaction_id: &TransactionId,
394    ) -> Result<bool, Self::Error>;
395
396    /// Loads all the send queue requests for the given room.
397    ///
398    /// The resulting vector of queued requests should be ordered from higher
399    /// priority to lower priority, and respect the insertion order when
400    /// priorities are equal.
401    async fn load_send_queue_requests(
402        &self,
403        room_id: &RoomId,
404    ) -> Result<Vec<QueuedRequest>, Self::Error>;
405
406    /// Updates the send queue error status (wedge) for a given send queue
407    /// request.
408    async fn update_send_queue_request_status(
409        &self,
410        room_id: &RoomId,
411        transaction_id: &TransactionId,
412        error: Option<QueueWedgeError>,
413    ) -> Result<(), Self::Error>;
414
415    /// Loads all the rooms which have any pending requests in their send queue.
416    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error>;
417
418    /// Add a new entry to the list of dependent send queue requests for a
419    /// parent request.
420    async fn save_dependent_queued_request(
421        &self,
422        room_id: &RoomId,
423        parent_txn_id: &TransactionId,
424        own_txn_id: ChildTransactionId,
425        created_at: MilliSecondsSinceUnixEpoch,
426        content: DependentQueuedRequestKind,
427    ) -> Result<(), Self::Error>;
428
429    /// Mark a set of dependent send queue requests as ready, using a key
430    /// identifying the homeserver's response.
431    ///
432    /// ⚠ Beware! There's no verification applied that the parent key type is
433    /// compatible with the dependent event type. The invalid state may be
434    /// lazily filtered out in `load_dependent_queued_requests`.
435    ///
436    /// Returns the number of updated requests.
437    async fn mark_dependent_queued_requests_as_ready(
438        &self,
439        room_id: &RoomId,
440        parent_txn_id: &TransactionId,
441        sent_parent_key: SentRequestKey,
442    ) -> Result<usize, Self::Error>;
443
444    /// Update a dependent send queue request with the new content.
445    ///
446    /// Returns true if the request was found and could be updated.
447    async fn update_dependent_queued_request(
448        &self,
449        room_id: &RoomId,
450        own_transaction_id: &ChildTransactionId,
451        new_content: DependentQueuedRequestKind,
452    ) -> Result<bool, Self::Error>;
453
454    /// Remove a specific dependent send queue request by id.
455    ///
456    /// Returns true if the dependent send queue request has been indeed
457    /// removed.
458    async fn remove_dependent_queued_request(
459        &self,
460        room: &RoomId,
461        own_txn_id: &ChildTransactionId,
462    ) -> Result<bool, Self::Error>;
463
464    /// List all the dependent send queue requests.
465    ///
466    /// This returns absolutely all the dependent send queue requests, whether
467    /// they have a parent event id or not. As a contract for implementors, they
468    /// must be returned in insertion order.
469    async fn load_dependent_queued_requests(
470        &self,
471        room: &RoomId,
472    ) -> Result<Vec<DependentQueuedRequest>, Self::Error>;
473}
474
475#[repr(transparent)]
476struct EraseStateStoreError<T>(T);
477
478#[cfg(not(tarpaulin_include))]
479impl<T: fmt::Debug> fmt::Debug for EraseStateStoreError<T> {
480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481        self.0.fmt(f)
482    }
483}
484
485#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
486#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
487impl<T: StateStore> StateStore for EraseStateStoreError<T> {
488    type Error = StoreError;
489
490    async fn get_kv_data(
491        &self,
492        key: StateStoreDataKey<'_>,
493    ) -> Result<Option<StateStoreDataValue>, Self::Error> {
494        self.0.get_kv_data(key).await.map_err(Into::into)
495    }
496
497    async fn set_kv_data(
498        &self,
499        key: StateStoreDataKey<'_>,
500        value: StateStoreDataValue,
501    ) -> Result<(), Self::Error> {
502        self.0.set_kv_data(key, value).await.map_err(Into::into)
503    }
504
505    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
506        self.0.remove_kv_data(key).await.map_err(Into::into)
507    }
508
509    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
510        self.0.save_changes(changes).await.map_err(Into::into)
511    }
512
513    async fn get_presence_event(
514        &self,
515        user_id: &UserId,
516    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
517        self.0.get_presence_event(user_id).await.map_err(Into::into)
518    }
519
520    async fn get_presence_events(
521        &self,
522        user_ids: &[OwnedUserId],
523    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
524        self.0.get_presence_events(user_ids).await.map_err(Into::into)
525    }
526
527    async fn get_state_event(
528        &self,
529        room_id: &RoomId,
530        event_type: StateEventType,
531        state_key: &str,
532    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
533        self.0.get_state_event(room_id, event_type, state_key).await.map_err(Into::into)
534    }
535
536    async fn get_state_events(
537        &self,
538        room_id: &RoomId,
539        event_type: StateEventType,
540    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
541        self.0.get_state_events(room_id, event_type).await.map_err(Into::into)
542    }
543
544    async fn get_state_events_for_keys(
545        &self,
546        room_id: &RoomId,
547        event_type: StateEventType,
548        state_keys: &[&str],
549    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
550        self.0.get_state_events_for_keys(room_id, event_type, state_keys).await.map_err(Into::into)
551    }
552
553    async fn get_profile(
554        &self,
555        room_id: &RoomId,
556        user_id: &UserId,
557    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
558        self.0.get_profile(room_id, user_id).await.map_err(Into::into)
559    }
560
561    async fn get_profiles<'a>(
562        &self,
563        room_id: &RoomId,
564        user_ids: &'a [OwnedUserId],
565    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
566        self.0.get_profiles(room_id, user_ids).await.map_err(Into::into)
567    }
568
569    async fn get_user_ids(
570        &self,
571        room_id: &RoomId,
572        memberships: RoomMemberships,
573    ) -> Result<Vec<OwnedUserId>, Self::Error> {
574        self.0.get_user_ids(room_id, memberships).await.map_err(Into::into)
575    }
576
577    async fn get_room_infos(&self) -> Result<Vec<RoomInfo>, Self::Error> {
578        self.0.get_room_infos().await.map_err(Into::into)
579    }
580
581    async fn get_users_with_display_name(
582        &self,
583        room_id: &RoomId,
584        display_name: &DisplayName,
585    ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
586        self.0.get_users_with_display_name(room_id, display_name).await.map_err(Into::into)
587    }
588
589    async fn get_users_with_display_names<'a>(
590        &self,
591        room_id: &RoomId,
592        display_names: &'a [DisplayName],
593    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
594        self.0.get_users_with_display_names(room_id, display_names).await.map_err(Into::into)
595    }
596
597    async fn get_account_data_event(
598        &self,
599        event_type: GlobalAccountDataEventType,
600    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
601        self.0.get_account_data_event(event_type).await.map_err(Into::into)
602    }
603
604    async fn get_room_account_data_event(
605        &self,
606        room_id: &RoomId,
607        event_type: RoomAccountDataEventType,
608    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
609        self.0.get_room_account_data_event(room_id, event_type).await.map_err(Into::into)
610    }
611
612    async fn get_user_room_receipt_event(
613        &self,
614        room_id: &RoomId,
615        receipt_type: ReceiptType,
616        thread: ReceiptThread,
617        user_id: &UserId,
618    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
619        self.0
620            .get_user_room_receipt_event(room_id, receipt_type, thread, user_id)
621            .await
622            .map_err(Into::into)
623    }
624
625    async fn get_event_room_receipt_events(
626        &self,
627        room_id: &RoomId,
628        receipt_type: ReceiptType,
629        thread: ReceiptThread,
630        event_id: &EventId,
631    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
632        self.0
633            .get_event_room_receipt_events(room_id, receipt_type, thread, event_id)
634            .await
635            .map_err(Into::into)
636    }
637
638    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
639        self.0.get_custom_value(key).await.map_err(Into::into)
640    }
641
642    async fn set_custom_value(
643        &self,
644        key: &[u8],
645        value: Vec<u8>,
646    ) -> Result<Option<Vec<u8>>, Self::Error> {
647        self.0.set_custom_value(key, value).await.map_err(Into::into)
648    }
649
650    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
651        self.0.remove_custom_value(key).await.map_err(Into::into)
652    }
653
654    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
655        self.0.remove_room(room_id).await.map_err(Into::into)
656    }
657
658    async fn save_send_queue_request(
659        &self,
660        room_id: &RoomId,
661        transaction_id: OwnedTransactionId,
662        created_at: MilliSecondsSinceUnixEpoch,
663        content: QueuedRequestKind,
664        priority: usize,
665    ) -> Result<(), Self::Error> {
666        self.0
667            .save_send_queue_request(room_id, transaction_id, created_at, content, priority)
668            .await
669            .map_err(Into::into)
670    }
671
672    async fn update_send_queue_request(
673        &self,
674        room_id: &RoomId,
675        transaction_id: &TransactionId,
676        content: QueuedRequestKind,
677    ) -> Result<bool, Self::Error> {
678        self.0.update_send_queue_request(room_id, transaction_id, content).await.map_err(Into::into)
679    }
680
681    async fn remove_send_queue_request(
682        &self,
683        room_id: &RoomId,
684        transaction_id: &TransactionId,
685    ) -> Result<bool, Self::Error> {
686        self.0.remove_send_queue_request(room_id, transaction_id).await.map_err(Into::into)
687    }
688
689    async fn load_send_queue_requests(
690        &self,
691        room_id: &RoomId,
692    ) -> Result<Vec<QueuedRequest>, Self::Error> {
693        self.0.load_send_queue_requests(room_id).await.map_err(Into::into)
694    }
695
696    async fn update_send_queue_request_status(
697        &self,
698        room_id: &RoomId,
699        transaction_id: &TransactionId,
700        error: Option<QueueWedgeError>,
701    ) -> Result<(), Self::Error> {
702        self.0
703            .update_send_queue_request_status(room_id, transaction_id, error)
704            .await
705            .map_err(Into::into)
706    }
707
708    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
709        self.0.load_rooms_with_unsent_requests().await.map_err(Into::into)
710    }
711
712    async fn save_dependent_queued_request(
713        &self,
714        room_id: &RoomId,
715        parent_txn_id: &TransactionId,
716        own_txn_id: ChildTransactionId,
717        created_at: MilliSecondsSinceUnixEpoch,
718        content: DependentQueuedRequestKind,
719    ) -> Result<(), Self::Error> {
720        self.0
721            .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
722            .await
723            .map_err(Into::into)
724    }
725
726    async fn mark_dependent_queued_requests_as_ready(
727        &self,
728        room_id: &RoomId,
729        parent_txn_id: &TransactionId,
730        sent_parent_key: SentRequestKey,
731    ) -> Result<usize, Self::Error> {
732        self.0
733            .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
734            .await
735            .map_err(Into::into)
736    }
737
738    async fn remove_dependent_queued_request(
739        &self,
740        room_id: &RoomId,
741        own_txn_id: &ChildTransactionId,
742    ) -> Result<bool, Self::Error> {
743        self.0.remove_dependent_queued_request(room_id, own_txn_id).await.map_err(Into::into)
744    }
745
746    async fn load_dependent_queued_requests(
747        &self,
748        room_id: &RoomId,
749    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
750        self.0.load_dependent_queued_requests(room_id).await.map_err(Into::into)
751    }
752
753    async fn update_dependent_queued_request(
754        &self,
755        room_id: &RoomId,
756        own_transaction_id: &ChildTransactionId,
757        new_content: DependentQueuedRequestKind,
758    ) -> Result<bool, Self::Error> {
759        self.0
760            .update_dependent_queued_request(room_id, own_transaction_id, new_content)
761            .await
762            .map_err(Into::into)
763    }
764}
765
766/// Convenience functionality for state stores.
767#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
768#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
769pub trait StateStoreExt: StateStore {
770    /// Get a specific state event of statically-known type.
771    ///
772    /// # Arguments
773    ///
774    /// * `room_id` - The id of the room the state event was received for.
775    async fn get_state_event_static<C>(
776        &self,
777        room_id: &RoomId,
778    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
779    where
780        C: StaticEventContent + StaticStateEventContent<StateKey = EmptyStateKey> + RedactContent,
781        C::Redacted: RedactedStateEventContent,
782    {
783        Ok(self.get_state_event(room_id, C::TYPE.into(), "").await?.map(|raw| raw.cast()))
784    }
785
786    /// Get a specific state event of statically-known type.
787    ///
788    /// # Arguments
789    ///
790    /// * `room_id` - The id of the room the state event was received for.
791    async fn get_state_event_static_for_key<C, K>(
792        &self,
793        room_id: &RoomId,
794        state_key: &K,
795    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
796    where
797        C: StaticEventContent + StaticStateEventContent + RedactContent,
798        C::StateKey: Borrow<K>,
799        C::Redacted: RedactedStateEventContent,
800        K: AsRef<str> + ?Sized + Sync,
801    {
802        Ok(self
803            .get_state_event(room_id, C::TYPE.into(), state_key.as_ref())
804            .await?
805            .map(|raw| raw.cast()))
806    }
807
808    /// Get a list of state events of a statically-known type for a given room.
809    ///
810    /// # Arguments
811    ///
812    /// * `room_id` - The id of the room to find events for.
813    async fn get_state_events_static<C>(
814        &self,
815        room_id: &RoomId,
816    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
817    where
818        C: StaticEventContent + StaticStateEventContent + RedactContent,
819        C::Redacted: RedactedStateEventContent,
820    {
821        // FIXME: Could be more efficient, if we had streaming store accessor functions
822        Ok(self
823            .get_state_events(room_id, C::TYPE.into())
824            .await?
825            .into_iter()
826            .map(|raw| raw.cast())
827            .collect())
828    }
829
830    /// Get a list of state events of a statically-known type for a given room
831    /// and given state keys.
832    ///
833    /// # Arguments
834    ///
835    /// * `room_id` - The id of the room to find events for.
836    ///
837    /// * `state_keys` - The list of state keys to find.
838    async fn get_state_events_for_keys_static<'a, C, K, I>(
839        &self,
840        room_id: &RoomId,
841        state_keys: I,
842    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
843    where
844        C: StaticEventContent + StaticStateEventContent + RedactContent,
845        C::StateKey: Borrow<K>,
846        C::Redacted: RedactedStateEventContent,
847        K: AsRef<str> + Sized + Sync + 'a,
848        I: IntoIterator<Item = &'a K> + Send,
849        I::IntoIter: Send,
850    {
851        Ok(self
852            .get_state_events_for_keys(
853                room_id,
854                C::TYPE.into(),
855                &state_keys.into_iter().map(|k| k.as_ref()).collect::<Vec<_>>(),
856            )
857            .await?
858            .into_iter()
859            .map(|raw| raw.cast())
860            .collect())
861    }
862
863    /// Get an event of a statically-known type from the account data store.
864    async fn get_account_data_event_static<C>(
865        &self,
866    ) -> Result<Option<Raw<GlobalAccountDataEvent<C>>>, Self::Error>
867    where
868        C: StaticEventContent + GlobalAccountDataEventContent,
869    {
870        Ok(self.get_account_data_event(C::TYPE.into()).await?.map(Raw::cast))
871    }
872
873    /// Get an event of a statically-known type from the room account data
874    /// store.
875    ///
876    /// # Arguments
877    ///
878    /// * `room_id` - The id of the room for which the room account data event
879    ///   should be fetched.
880    async fn get_room_account_data_event_static<C>(
881        &self,
882        room_id: &RoomId,
883    ) -> Result<Option<Raw<RoomAccountDataEvent<C>>>, Self::Error>
884    where
885        C: StaticEventContent + RoomAccountDataEventContent,
886    {
887        Ok(self.get_room_account_data_event(room_id, C::TYPE.into()).await?.map(Raw::cast))
888    }
889
890    /// Get the `MemberEvent` for the given state key in the given room id.
891    ///
892    /// # Arguments
893    ///
894    /// * `room_id` - The room id the member event belongs to.
895    ///
896    /// * `state_key` - The user id that the member event defines the state for.
897    async fn get_member_event(
898        &self,
899        room_id: &RoomId,
900        state_key: &UserId,
901    ) -> Result<Option<RawMemberEvent>, Self::Error> {
902        self.get_state_event_static_for_key(room_id, state_key).await
903    }
904}
905
906#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
907#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
908impl<T: StateStore + ?Sized> StateStoreExt for T {}
909
910/// A type-erased [`StateStore`].
911pub type DynStateStore = dyn StateStore<Error = StoreError>;
912
913/// A type that can be type-erased into `Arc<dyn StateStore>`.
914///
915/// This trait is not meant to be implemented directly outside
916/// `matrix-sdk-crypto`, but it is automatically implemented for everything that
917/// implements `StateStore`.
918pub trait IntoStateStore {
919    #[doc(hidden)]
920    fn into_state_store(self) -> Arc<DynStateStore>;
921}
922
923impl<T> IntoStateStore for T
924where
925    T: StateStore + Sized + 'static,
926{
927    fn into_state_store(self) -> Arc<DynStateStore> {
928        Arc::new(EraseStateStoreError(self))
929    }
930}
931
932// Turns a given `Arc<T>` into `Arc<DynStateStore>` by attaching the
933// StateStore impl vtable of `EraseStateStoreError<T>`.
934impl<T> IntoStateStore for Arc<T>
935where
936    T: StateStore + 'static,
937{
938    fn into_state_store(self) -> Arc<DynStateStore> {
939        let ptr: *const T = Arc::into_raw(self);
940        let ptr_erased = ptr as *const EraseStateStoreError<T>;
941        // SAFETY: EraseStateStoreError is repr(transparent) so T and
942        //         EraseStateStoreError<T> have the same layout and ABI
943        unsafe { Arc::from_raw(ptr_erased) }
944    }
945}
946
947/// Server capabilities returned by the /client/versions endpoint.
948#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
949pub struct ServerCapabilities {
950    /// Versions supported by the remote server.
951    ///
952    /// This contains [`MatrixVersion`]s converted to strings.
953    pub versions: Vec<String>,
954
955    /// List of unstable features and their enablement status.
956    pub unstable_features: BTreeMap<String, bool>,
957
958    /// Last time we fetched this data from the server, in milliseconds since
959    /// epoch.
960    last_fetch_ts: f64,
961}
962
963impl ServerCapabilities {
964    /// The number of milliseconds after which the data is considered stale.
965    pub const STALE_THRESHOLD: f64 = (1000 * 60 * 60 * 24 * 7) as _; // seven days
966
967    /// Encode server capabilities into this serializable struct.
968    pub fn new(versions: &[MatrixVersion], unstable_features: BTreeMap<String, bool>) -> Self {
969        Self {
970            versions: versions.iter().map(|item| item.to_string()).collect(),
971            unstable_features,
972            last_fetch_ts: now_timestamp_ms(),
973        }
974    }
975
976    /// Decode server capabilities from this serializable struct.
977    ///
978    /// May return `None` if the data is considered stale, after
979    /// [`Self::STALE_THRESHOLD`] milliseconds since the last time we stored
980    /// it.
981    pub fn maybe_decode(&self) -> Option<(Vec<MatrixVersion>, BTreeMap<String, bool>)> {
982        if now_timestamp_ms() - self.last_fetch_ts >= Self::STALE_THRESHOLD {
983            None
984        } else {
985            Some((
986                self.versions.iter().filter_map(|item| item.parse().ok()).collect(),
987                self.unstable_features.clone(),
988            ))
989        }
990    }
991}
992
993/// Get the current timestamp as the number of milliseconds since Unix Epoch.
994fn now_timestamp_ms() -> f64 {
995    SystemTime::now()
996        .duration_since(SystemTime::UNIX_EPOCH)
997        .expect("System clock was before 1970.")
998        .as_secs_f64()
999        * 1000.0
1000}
1001
1002/// A value for key-value data that should be persisted into the store.
1003#[derive(Debug, Clone)]
1004pub enum StateStoreDataValue {
1005    /// The sync token.
1006    SyncToken(String),
1007
1008    /// The server capabilities.
1009    ServerCapabilities(ServerCapabilities),
1010
1011    /// A filter with the given ID.
1012    Filter(String),
1013
1014    /// The user avatar url
1015    UserAvatarUrl(OwnedMxcUri),
1016
1017    /// A list of recently visited room identifiers for the current user
1018    RecentlyVisitedRooms(Vec<OwnedRoomId>),
1019
1020    /// Persistent data for
1021    /// `matrix_sdk_ui::unable_to_decrypt_hook::UtdHookManager`.
1022    UtdHookManagerData(GrowableBloom),
1023
1024    /// A composer draft for the room.
1025    /// To learn more, see [`ComposerDraft`].
1026    ///
1027    /// [`ComposerDraft`]: Self::ComposerDraft
1028    ComposerDraft(ComposerDraft),
1029
1030    /// A list of knock request ids marked as seen in a room.
1031    SeenKnockRequests(BTreeMap<OwnedEventId, OwnedUserId>),
1032}
1033
1034/// Current draft of the composer for the room.
1035#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1036pub struct ComposerDraft {
1037    /// The draft content in plain text.
1038    pub plain_text: String,
1039    /// If the message is formatted in HTML, the HTML representation of the
1040    /// message.
1041    pub html_text: Option<String>,
1042    /// The type of draft.
1043    pub draft_type: ComposerDraftType,
1044}
1045
1046/// The type of draft of the composer.
1047#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1048pub enum ComposerDraftType {
1049    /// The draft is a new message.
1050    NewMessage,
1051    /// The draft is a reply to an event.
1052    Reply {
1053        /// The ID of the event being replied to.
1054        event_id: OwnedEventId,
1055    },
1056    /// The draft is an edit of an event.
1057    Edit {
1058        /// The ID of the event being edited.
1059        event_id: OwnedEventId,
1060    },
1061}
1062
1063impl StateStoreDataValue {
1064    /// Get this value if it is a sync token.
1065    pub fn into_sync_token(self) -> Option<String> {
1066        as_variant!(self, Self::SyncToken)
1067    }
1068
1069    /// Get this value if it is a filter.
1070    pub fn into_filter(self) -> Option<String> {
1071        as_variant!(self, Self::Filter)
1072    }
1073
1074    /// Get this value if it is a user avatar url.
1075    pub fn into_user_avatar_url(self) -> Option<OwnedMxcUri> {
1076        as_variant!(self, Self::UserAvatarUrl)
1077    }
1078
1079    /// Get this value if it is a list of recently visited rooms.
1080    pub fn into_recently_visited_rooms(self) -> Option<Vec<OwnedRoomId>> {
1081        as_variant!(self, Self::RecentlyVisitedRooms)
1082    }
1083
1084    /// Get this value if it is the data for the `UtdHookManager`.
1085    pub fn into_utd_hook_manager_data(self) -> Option<GrowableBloom> {
1086        as_variant!(self, Self::UtdHookManagerData)
1087    }
1088
1089    /// Get this value if it is a composer draft.
1090    pub fn into_composer_draft(self) -> Option<ComposerDraft> {
1091        as_variant!(self, Self::ComposerDraft)
1092    }
1093
1094    /// Get this value if it is the server capabilities metadata.
1095    pub fn into_server_capabilities(self) -> Option<ServerCapabilities> {
1096        as_variant!(self, Self::ServerCapabilities)
1097    }
1098
1099    /// Get this value if it is the data for the ignored join requests.
1100    pub fn into_seen_knock_requests(self) -> Option<BTreeMap<OwnedEventId, OwnedUserId>> {
1101        as_variant!(self, Self::SeenKnockRequests)
1102    }
1103}
1104
1105/// A key for key-value data.
1106#[derive(Debug, Clone, Copy)]
1107pub enum StateStoreDataKey<'a> {
1108    /// The sync token.
1109    SyncToken,
1110
1111    /// The server capabilities,
1112    ServerCapabilities,
1113
1114    /// A filter with the given name.
1115    Filter(&'a str),
1116
1117    /// Avatar URL
1118    UserAvatarUrl(&'a UserId),
1119
1120    /// Recently visited room identifiers
1121    RecentlyVisitedRooms(&'a UserId),
1122
1123    /// Persistent data for
1124    /// `matrix_sdk_ui::unable_to_decrypt_hook::UtdHookManager`.
1125    UtdHookManagerData,
1126
1127    /// A composer draft for the room.
1128    /// To learn more, see [`ComposerDraft`].
1129    ///
1130    /// [`ComposerDraft`]: Self::ComposerDraft
1131    ComposerDraft(&'a RoomId),
1132
1133    /// A list of knock request ids marked as seen in a room.
1134    SeenKnockRequests(&'a RoomId),
1135}
1136
1137impl StateStoreDataKey<'_> {
1138    /// Key to use for the [`SyncToken`][Self::SyncToken] variant.
1139    pub const SYNC_TOKEN: &'static str = "sync_token";
1140    /// Key to use for the [`ServerCapabilities`][Self::ServerCapabilities]
1141    /// variant.
1142    pub const SERVER_CAPABILITIES: &'static str = "server_capabilities";
1143    /// Key prefix to use for the [`Filter`][Self::Filter] variant.
1144    pub const FILTER: &'static str = "filter";
1145    /// Key prefix to use for the [`UserAvatarUrl`][Self::UserAvatarUrl]
1146    /// variant.
1147    pub const USER_AVATAR_URL: &'static str = "user_avatar_url";
1148
1149    /// Key prefix to use for the
1150    /// [`RecentlyVisitedRooms`][Self::RecentlyVisitedRooms] variant.
1151    pub const RECENTLY_VISITED_ROOMS: &'static str = "recently_visited_rooms";
1152
1153    /// Key to use for the [`UtdHookManagerData`][Self::UtdHookManagerData]
1154    /// variant.
1155    pub const UTD_HOOK_MANAGER_DATA: &'static str = "utd_hook_manager_data";
1156
1157    /// Key prefix to use for the [`ComposerDraft`][Self::ComposerDraft]
1158    /// variant.
1159    pub const COMPOSER_DRAFT: &'static str = "composer_draft";
1160
1161    /// Key prefix to use for the
1162    /// [`SeenKnockRequests`][Self::SeenKnockRequests] variant.
1163    pub const SEEN_KNOCK_REQUESTS: &'static str = "seen_knock_requests";
1164}
1165
1166#[cfg(test)]
1167mod tests {
1168    use super::{now_timestamp_ms, ServerCapabilities};
1169
1170    #[test]
1171    fn test_stale_server_capabilities() {
1172        let mut caps = ServerCapabilities {
1173            versions: Default::default(),
1174            unstable_features: Default::default(),
1175            last_fetch_ts: now_timestamp_ms() - ServerCapabilities::STALE_THRESHOLD - 1.0,
1176        };
1177
1178        // Definitely stale.
1179        assert!(caps.maybe_decode().is_none());
1180
1181        // Definitely not stale.
1182        caps.last_fetch_ts = now_timestamp_ms() - 1.0;
1183        assert!(caps.maybe_decode().is_some());
1184    }
1185}