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