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