Skip to main content

matrix_sdk_base/store/
traits.rs

1// Copyright 2023 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{
16    borrow::Borrow,
17    collections::{BTreeMap, BTreeSet, HashMap},
18    fmt,
19    sync::Arc,
20};
21
22use as_variant::as_variant;
23use async_trait::async_trait;
24use growable_bloom_filter::GrowableBloom;
25use matrix_sdk_common::{AsyncTraitDeps, ttl::TtlValue};
26use ruma::{
27    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId,
28    OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId,
29    api::{
30        MatrixVersion, SupportedVersions,
31        client::discovery::{
32            discover_homeserver::{
33                self, HomeserverInfo, IdentityServerInfo, RtcFocusInfo, TileServerInfo,
34            },
35            get_capabilities::v3::Capabilities,
36        },
37    },
38    events::{
39        AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, EmptyStateKey, GlobalAccountDataEvent,
40        GlobalAccountDataEventContent, GlobalAccountDataEventType, RedactContent,
41        RedactedStateEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
42        RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
43        presence::PresenceEvent,
44        receipt::{Receipt, ReceiptThread, ReceiptType},
45    },
46    serde::Raw,
47};
48use serde::{Deserialize, Serialize};
49
50use super::{
51    ChildTransactionId, DependentQueuedRequest, DependentQueuedRequestKind, QueueWedgeError,
52    QueuedRequest, QueuedRequestKind, RoomLoadSettings, StateChanges, StoreError,
53    send_queue::SentRequestKey,
54};
55use crate::{
56    MinimalRoomMemberEvent, RoomInfo, RoomMemberships,
57    deserialized_responses::{
58        DisplayName, RawAnySyncOrStrippedState, RawMemberEvent, RawSyncOrStrippedState,
59    },
60    store::StoredThreadSubscription,
61};
62
63/// An abstract state store trait that can be used to implement different stores
64/// for the SDK.
65#[cfg_attr(target_family = "wasm", async_trait(?Send))]
66#[cfg_attr(not(target_family = "wasm"), async_trait)]
67pub trait StateStore: AsyncTraitDeps {
68    /// The error type used by this state store.
69    type Error: fmt::Debug + Into<StoreError> + From<serde_json::Error>;
70
71    /// Get key-value data from the store.
72    ///
73    /// # Arguments
74    ///
75    /// * `key` - The key to fetch data for.
76    async fn get_kv_data(
77        &self,
78        key: StateStoreDataKey<'_>,
79    ) -> Result<Option<StateStoreDataValue>, Self::Error>;
80
81    /// Put key-value data into the store.
82    ///
83    /// # Arguments
84    ///
85    /// * `key` - The key to identify the data in the store.
86    ///
87    /// * `value` - The data to insert.
88    ///
89    /// Panics if the key and value variants do not match.
90    async fn set_kv_data(
91        &self,
92        key: StateStoreDataKey<'_>,
93        value: StateStoreDataValue,
94    ) -> Result<(), Self::Error>;
95
96    /// Remove key-value data from the store.
97    ///
98    /// # Arguments
99    ///
100    /// * `key` - The key to remove the data for.
101    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error>;
102
103    /// Save the set of state changes in the store.
104    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error>;
105
106    /// Get the stored presence event for the given user.
107    ///
108    /// # Arguments
109    ///
110    /// * `user_id` - The id of the user for which we wish to fetch the presence
111    /// event for.
112    async fn get_presence_event(
113        &self,
114        user_id: &UserId,
115    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error>;
116
117    /// Get the stored presence events for the given users.
118    ///
119    /// # Arguments
120    ///
121    /// * `user_ids` - The IDs of the users to fetch the presence events for.
122    async fn get_presence_events(
123        &self,
124        user_ids: &[OwnedUserId],
125    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error>;
126
127    /// Get a state event out of the state store.
128    ///
129    /// # Arguments
130    ///
131    /// * `room_id` - The id of the room the state event was received for.
132    ///
133    /// * `event_type` - The event type of the state event.
134    async fn get_state_event(
135        &self,
136        room_id: &RoomId,
137        event_type: StateEventType,
138        state_key: &str,
139    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error>;
140
141    /// Get a list of state events for a given room and `StateEventType`.
142    ///
143    /// # Arguments
144    ///
145    /// * `room_id` - The id of the room to find events for.
146    ///
147    /// * `event_type` - The event type.
148    async fn get_state_events(
149        &self,
150        room_id: &RoomId,
151        event_type: StateEventType,
152    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
153
154    /// Get a list of state events for a given room, `StateEventType`, and the
155    /// given state keys.
156    ///
157    /// # Arguments
158    ///
159    /// * `room_id` - The id of the room to find events for.
160    ///
161    /// * `event_type` - The event type.
162    ///
163    /// * `state_keys` - The list of state keys to find.
164    async fn get_state_events_for_keys(
165        &self,
166        room_id: &RoomId,
167        event_type: StateEventType,
168        state_keys: &[&str],
169    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
170
171    /// Get the current profile for the given user in the given room.
172    ///
173    /// # Arguments
174    ///
175    /// * `room_id` - The room id the profile is used in.
176    ///
177    /// * `user_id` - The id of the user the profile belongs to.
178    async fn get_profile(
179        &self,
180        room_id: &RoomId,
181        user_id: &UserId,
182    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error>;
183
184    /// Get the current profiles for the given users in the given room.
185    ///
186    /// # Arguments
187    ///
188    /// * `room_id` - The ID of the room the profiles are used in.
189    ///
190    /// * `user_ids` - The IDs of the users the profiles belong to.
191    async fn get_profiles<'a>(
192        &self,
193        room_id: &RoomId,
194        user_ids: &'a [OwnedUserId],
195    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error>;
196
197    /// Get the user ids of members for a given room with the given memberships,
198    /// for stripped and regular rooms alike.
199    async fn get_user_ids(
200        &self,
201        room_id: &RoomId,
202        memberships: RoomMemberships,
203    ) -> Result<Vec<OwnedUserId>, Self::Error>;
204
205    /// Get a set of pure `RoomInfo`s the store knows about.
206    async fn get_room_infos(
207        &self,
208        room_load_settings: &RoomLoadSettings,
209    ) -> Result<Vec<RoomInfo>, Self::Error>;
210
211    /// Get all the users that use the given display name in the given room.
212    ///
213    /// # Arguments
214    ///
215    /// * `room_id` - The id of the room for which the display name users should
216    /// be fetched for.
217    ///
218    /// * `display_name` - The display name that the users use.
219    async fn get_users_with_display_name(
220        &self,
221        room_id: &RoomId,
222        display_name: &DisplayName,
223    ) -> Result<BTreeSet<OwnedUserId>, Self::Error>;
224
225    /// Get all the users that use the given display names in the given room.
226    ///
227    /// # Arguments
228    ///
229    /// * `room_id` - The ID of the room to fetch the display names for.
230    ///
231    /// * `display_names` - The display names that the users use.
232    async fn get_users_with_display_names<'a>(
233        &self,
234        room_id: &RoomId,
235        display_names: &'a [DisplayName],
236    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error>;
237
238    /// Get an event out of the account data store.
239    ///
240    /// # Arguments
241    ///
242    /// * `event_type` - The event type of the account data event.
243    async fn get_account_data_event(
244        &self,
245        event_type: GlobalAccountDataEventType,
246    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error>;
247
248    /// Get an event out of the room account data store.
249    ///
250    /// # Arguments
251    ///
252    /// * `room_id` - The id of the room for which the room account data event
253    ///   should
254    /// be fetched.
255    ///
256    /// * `event_type` - The event type of the room account data event.
257    async fn get_room_account_data_event(
258        &self,
259        room_id: &RoomId,
260        event_type: RoomAccountDataEventType,
261    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error>;
262
263    /// Get a user's read receipt for a given room and receipt type and thread.
264    ///
265    /// # Arguments
266    ///
267    /// * `room_id` - The id of the room for which the receipt should be
268    ///   fetched.
269    ///
270    /// * `receipt_type` - The type of the receipt.
271    ///
272    /// * `thread` - The thread containing this receipt.
273    ///
274    /// * `user_id` - The id of the user for whom the receipt should be fetched.
275    async fn get_user_room_receipt_event(
276        &self,
277        room_id: &RoomId,
278        receipt_type: ReceiptType,
279        thread: ReceiptThread,
280        user_id: &UserId,
281    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error>;
282
283    /// Get an event's read receipts for a given room, receipt type, and thread.
284    ///
285    /// # Arguments
286    ///
287    /// * `room_id` - The id of the room for which the receipts should be
288    ///   fetched.
289    ///
290    /// * `receipt_type` - The type of the receipts.
291    ///
292    /// * `thread` - The thread containing this receipt.
293    ///
294    /// * `event_id` - The id of the event for which the receipts should be
295    ///   fetched.
296    async fn get_event_room_receipt_events(
297        &self,
298        room_id: &RoomId,
299        receipt_type: ReceiptType,
300        thread: ReceiptThread,
301        event_id: &EventId,
302    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error>;
303
304    /// Get arbitrary data from the custom store
305    ///
306    /// # Arguments
307    ///
308    /// * `key` - The key to fetch data for
309    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
310
311    /// Put arbitrary data into the custom store, return the data previously
312    /// stored
313    ///
314    /// # Arguments
315    ///
316    /// * `key` - The key to insert data into
317    ///
318    /// * `value` - The value to insert
319    async fn set_custom_value(
320        &self,
321        key: &[u8],
322        value: Vec<u8>,
323    ) -> Result<Option<Vec<u8>>, Self::Error>;
324
325    /// Put arbitrary data into the custom store, do not attempt to read any
326    /// previous data
327    ///
328    /// Optimization option for set_custom_values for stores that would perform
329    /// better withouts the extra read and the caller not needing that data
330    /// returned. Otherwise this just wraps around `set_custom_data` and
331    /// discards the result.
332    ///
333    /// # Arguments
334    ///
335    /// * `key` - The key to insert data into
336    ///
337    /// * `value` - The value to insert
338    async fn set_custom_value_no_read(
339        &self,
340        key: &[u8],
341        value: Vec<u8>,
342    ) -> Result<(), Self::Error> {
343        self.set_custom_value(key, value).await.map(|_| ())
344    }
345
346    /// Remove arbitrary data from the custom store and return it if existed
347    ///
348    /// # Arguments
349    ///
350    /// * `key` - The key to remove data from
351    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
352
353    /// Remove a room and all elements associated from the state store.
354    ///
355    /// # Arguments
356    ///
357    /// * `room_id` - The `RoomId` of the room to delete.
358    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error>;
359
360    /// Save a request to be sent by a send queue later (e.g. sending an event).
361    ///
362    /// # Arguments
363    ///
364    /// * `room_id` - The `RoomId` of the send queue's room.
365    /// * `transaction_id` - The unique key identifying the event to be sent
366    ///   (and its transaction). Note: this is expected to be randomly generated
367    ///   and thus unique.
368    /// * `content` - Serializable event content to be sent.
369    async fn save_send_queue_request(
370        &self,
371        room_id: &RoomId,
372        transaction_id: OwnedTransactionId,
373        created_at: MilliSecondsSinceUnixEpoch,
374        request: QueuedRequestKind,
375        priority: usize,
376    ) -> Result<(), Self::Error>;
377
378    /// Updates a send queue request with the given content, and resets its
379    /// error status.
380    ///
381    /// # Arguments
382    ///
383    /// * `room_id` - The `RoomId` of the send queue's room.
384    /// * `transaction_id` - The unique key identifying the request to be sent
385    ///   (and its transaction).
386    /// * `content` - Serializable event content to replace the original one.
387    ///
388    /// Returns true if a request has been updated, or false otherwise.
389    async fn update_send_queue_request(
390        &self,
391        room_id: &RoomId,
392        transaction_id: &TransactionId,
393        content: QueuedRequestKind,
394    ) -> Result<bool, Self::Error>;
395
396    /// Remove a request previously inserted with
397    /// [`Self::save_send_queue_request`] from the database, based on its
398    /// transaction id.
399    ///
400    /// Returns true if something has been removed, or false otherwise.
401    async fn remove_send_queue_request(
402        &self,
403        room_id: &RoomId,
404        transaction_id: &TransactionId,
405    ) -> Result<bool, Self::Error>;
406
407    /// Loads all the send queue requests for the given room.
408    ///
409    /// The resulting vector of queued requests should be ordered from higher
410    /// priority to lower priority, and respect the insertion order when
411    /// priorities are equal.
412    async fn load_send_queue_requests(
413        &self,
414        room_id: &RoomId,
415    ) -> Result<Vec<QueuedRequest>, Self::Error>;
416
417    /// Updates the send queue error status (wedge) for a given send queue
418    /// request.
419    async fn update_send_queue_request_status(
420        &self,
421        room_id: &RoomId,
422        transaction_id: &TransactionId,
423        error: Option<QueueWedgeError>,
424    ) -> Result<(), Self::Error>;
425
426    /// Loads all the rooms which have any pending requests in their send queue.
427    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error>;
428
429    /// Add a new entry to the list of dependent send queue requests for a
430    /// parent request.
431    async fn save_dependent_queued_request(
432        &self,
433        room_id: &RoomId,
434        parent_txn_id: &TransactionId,
435        own_txn_id: ChildTransactionId,
436        created_at: MilliSecondsSinceUnixEpoch,
437        content: DependentQueuedRequestKind,
438    ) -> Result<(), Self::Error>;
439
440    /// Mark a set of dependent send queue requests as ready, using a key
441    /// identifying the homeserver's response.
442    ///
443    /// ⚠ Beware! There's no verification applied that the parent key type is
444    /// compatible with the dependent event type. The invalid state may be
445    /// lazily filtered out in `load_dependent_queued_requests`.
446    ///
447    /// Returns the number of updated requests.
448    async fn mark_dependent_queued_requests_as_ready(
449        &self,
450        room_id: &RoomId,
451        parent_txn_id: &TransactionId,
452        sent_parent_key: SentRequestKey,
453    ) -> Result<usize, Self::Error>;
454
455    /// Update a dependent send queue request with the new content.
456    ///
457    /// Returns true if the request was found and could be updated.
458    async fn update_dependent_queued_request(
459        &self,
460        room_id: &RoomId,
461        own_transaction_id: &ChildTransactionId,
462        new_content: DependentQueuedRequestKind,
463    ) -> Result<bool, Self::Error>;
464
465    /// Remove a specific dependent send queue request by id.
466    ///
467    /// Returns true if the dependent send queue request has been indeed
468    /// removed.
469    async fn remove_dependent_queued_request(
470        &self,
471        room: &RoomId,
472        own_txn_id: &ChildTransactionId,
473    ) -> Result<bool, Self::Error>;
474
475    /// List all the dependent send queue requests.
476    ///
477    /// This returns absolutely all the dependent send queue requests, whether
478    /// they have a parent event id or not. As a contract for implementors, they
479    /// must be returned in insertion order.
480    async fn load_dependent_queued_requests(
481        &self,
482        room: &RoomId,
483    ) -> Result<Vec<DependentQueuedRequest>, Self::Error>;
484
485    /// Inserts or updates multiple thread subscriptions.
486    ///
487    /// If the new thread subscription hasn't set a bumpstamp, and there was a
488    /// previous subscription in the database with a bumpstamp, the existing
489    /// bumpstamp is kept.
490    ///
491    /// If the new thread subscription has a bumpstamp that's lower than or
492    /// equal to a previous one, the existing subscription is kept, i.e.
493    /// this method must have no effect.
494    async fn upsert_thread_subscriptions(
495        &self,
496        updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
497    ) -> Result<(), Self::Error>;
498
499    /// Remove a previous thread subscription for a given room and thread.
500    ///
501    /// Note: removing an unknown thread subscription is a no-op.
502    async fn remove_thread_subscription(
503        &self,
504        room: &RoomId,
505        thread_id: &EventId,
506    ) -> Result<(), Self::Error>;
507
508    /// Loads the current thread subscription for a given room and thread.
509    ///
510    /// Returns `None` if there was no entry for the given room/thread pair.
511    async fn load_thread_subscription(
512        &self,
513        room: &RoomId,
514        thread_id: &EventId,
515    ) -> Result<Option<StoredThreadSubscription>, Self::Error>;
516
517    /// Perform database optimizations if any are available, i.e. vacuuming in
518    /// SQLite.
519    ///
520    /// /// **Warning:** this was added to check if SQLite fragmentation was the
521    /// source of performance issues, **DO NOT use in production**.
522    #[doc(hidden)]
523    async fn optimize(&self) -> Result<(), Self::Error>;
524
525    /// Returns the size of the store in bytes, if known.
526    async fn get_size(&self) -> Result<Option<usize>, Self::Error>;
527}
528
529#[repr(transparent)]
530struct EraseStateStoreError<T>(T);
531
532#[cfg(not(tarpaulin_include))]
533impl<T: fmt::Debug> fmt::Debug for EraseStateStoreError<T> {
534    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535        self.0.fmt(f)
536    }
537}
538
539#[cfg_attr(target_family = "wasm", async_trait(?Send))]
540#[cfg_attr(not(target_family = "wasm"), async_trait)]
541impl<T: StateStore> StateStore for EraseStateStoreError<T> {
542    type Error = StoreError;
543
544    async fn get_kv_data(
545        &self,
546        key: StateStoreDataKey<'_>,
547    ) -> Result<Option<StateStoreDataValue>, Self::Error> {
548        self.0.get_kv_data(key).await.map_err(Into::into)
549    }
550
551    async fn set_kv_data(
552        &self,
553        key: StateStoreDataKey<'_>,
554        value: StateStoreDataValue,
555    ) -> Result<(), Self::Error> {
556        self.0.set_kv_data(key, value).await.map_err(Into::into)
557    }
558
559    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
560        self.0.remove_kv_data(key).await.map_err(Into::into)
561    }
562
563    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
564        self.0.save_changes(changes).await.map_err(Into::into)
565    }
566
567    async fn get_presence_event(
568        &self,
569        user_id: &UserId,
570    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
571        self.0.get_presence_event(user_id).await.map_err(Into::into)
572    }
573
574    async fn get_presence_events(
575        &self,
576        user_ids: &[OwnedUserId],
577    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
578        self.0.get_presence_events(user_ids).await.map_err(Into::into)
579    }
580
581    async fn get_state_event(
582        &self,
583        room_id: &RoomId,
584        event_type: StateEventType,
585        state_key: &str,
586    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
587        self.0.get_state_event(room_id, event_type, state_key).await.map_err(Into::into)
588    }
589
590    async fn get_state_events(
591        &self,
592        room_id: &RoomId,
593        event_type: StateEventType,
594    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
595        self.0.get_state_events(room_id, event_type).await.map_err(Into::into)
596    }
597
598    async fn get_state_events_for_keys(
599        &self,
600        room_id: &RoomId,
601        event_type: StateEventType,
602        state_keys: &[&str],
603    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
604        self.0.get_state_events_for_keys(room_id, event_type, state_keys).await.map_err(Into::into)
605    }
606
607    async fn get_profile(
608        &self,
609        room_id: &RoomId,
610        user_id: &UserId,
611    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
612        self.0.get_profile(room_id, user_id).await.map_err(Into::into)
613    }
614
615    async fn get_profiles<'a>(
616        &self,
617        room_id: &RoomId,
618        user_ids: &'a [OwnedUserId],
619    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
620        self.0.get_profiles(room_id, user_ids).await.map_err(Into::into)
621    }
622
623    async fn get_user_ids(
624        &self,
625        room_id: &RoomId,
626        memberships: RoomMemberships,
627    ) -> Result<Vec<OwnedUserId>, Self::Error> {
628        self.0.get_user_ids(room_id, memberships).await.map_err(Into::into)
629    }
630
631    async fn get_room_infos(
632        &self,
633        room_load_settings: &RoomLoadSettings,
634    ) -> Result<Vec<RoomInfo>, Self::Error> {
635        self.0.get_room_infos(room_load_settings).await.map_err(Into::into)
636    }
637
638    async fn get_users_with_display_name(
639        &self,
640        room_id: &RoomId,
641        display_name: &DisplayName,
642    ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
643        self.0.get_users_with_display_name(room_id, display_name).await.map_err(Into::into)
644    }
645
646    async fn get_users_with_display_names<'a>(
647        &self,
648        room_id: &RoomId,
649        display_names: &'a [DisplayName],
650    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
651        self.0.get_users_with_display_names(room_id, display_names).await.map_err(Into::into)
652    }
653
654    async fn get_account_data_event(
655        &self,
656        event_type: GlobalAccountDataEventType,
657    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
658        self.0.get_account_data_event(event_type).await.map_err(Into::into)
659    }
660
661    async fn get_room_account_data_event(
662        &self,
663        room_id: &RoomId,
664        event_type: RoomAccountDataEventType,
665    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
666        self.0.get_room_account_data_event(room_id, event_type).await.map_err(Into::into)
667    }
668
669    async fn get_user_room_receipt_event(
670        &self,
671        room_id: &RoomId,
672        receipt_type: ReceiptType,
673        thread: ReceiptThread,
674        user_id: &UserId,
675    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
676        self.0
677            .get_user_room_receipt_event(room_id, receipt_type, thread, user_id)
678            .await
679            .map_err(Into::into)
680    }
681
682    async fn get_event_room_receipt_events(
683        &self,
684        room_id: &RoomId,
685        receipt_type: ReceiptType,
686        thread: ReceiptThread,
687        event_id: &EventId,
688    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
689        self.0
690            .get_event_room_receipt_events(room_id, receipt_type, thread, event_id)
691            .await
692            .map_err(Into::into)
693    }
694
695    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
696        self.0.get_custom_value(key).await.map_err(Into::into)
697    }
698
699    async fn set_custom_value(
700        &self,
701        key: &[u8],
702        value: Vec<u8>,
703    ) -> Result<Option<Vec<u8>>, Self::Error> {
704        self.0.set_custom_value(key, value).await.map_err(Into::into)
705    }
706
707    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
708        self.0.remove_custom_value(key).await.map_err(Into::into)
709    }
710
711    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
712        self.0.remove_room(room_id).await.map_err(Into::into)
713    }
714
715    async fn save_send_queue_request(
716        &self,
717        room_id: &RoomId,
718        transaction_id: OwnedTransactionId,
719        created_at: MilliSecondsSinceUnixEpoch,
720        content: QueuedRequestKind,
721        priority: usize,
722    ) -> Result<(), Self::Error> {
723        self.0
724            .save_send_queue_request(room_id, transaction_id, created_at, content, priority)
725            .await
726            .map_err(Into::into)
727    }
728
729    async fn update_send_queue_request(
730        &self,
731        room_id: &RoomId,
732        transaction_id: &TransactionId,
733        content: QueuedRequestKind,
734    ) -> Result<bool, Self::Error> {
735        self.0.update_send_queue_request(room_id, transaction_id, content).await.map_err(Into::into)
736    }
737
738    async fn remove_send_queue_request(
739        &self,
740        room_id: &RoomId,
741        transaction_id: &TransactionId,
742    ) -> Result<bool, Self::Error> {
743        self.0.remove_send_queue_request(room_id, transaction_id).await.map_err(Into::into)
744    }
745
746    async fn load_send_queue_requests(
747        &self,
748        room_id: &RoomId,
749    ) -> Result<Vec<QueuedRequest>, Self::Error> {
750        self.0.load_send_queue_requests(room_id).await.map_err(Into::into)
751    }
752
753    async fn update_send_queue_request_status(
754        &self,
755        room_id: &RoomId,
756        transaction_id: &TransactionId,
757        error: Option<QueueWedgeError>,
758    ) -> Result<(), Self::Error> {
759        self.0
760            .update_send_queue_request_status(room_id, transaction_id, error)
761            .await
762            .map_err(Into::into)
763    }
764
765    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
766        self.0.load_rooms_with_unsent_requests().await.map_err(Into::into)
767    }
768
769    async fn save_dependent_queued_request(
770        &self,
771        room_id: &RoomId,
772        parent_txn_id: &TransactionId,
773        own_txn_id: ChildTransactionId,
774        created_at: MilliSecondsSinceUnixEpoch,
775        content: DependentQueuedRequestKind,
776    ) -> Result<(), Self::Error> {
777        self.0
778            .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
779            .await
780            .map_err(Into::into)
781    }
782
783    async fn mark_dependent_queued_requests_as_ready(
784        &self,
785        room_id: &RoomId,
786        parent_txn_id: &TransactionId,
787        sent_parent_key: SentRequestKey,
788    ) -> Result<usize, Self::Error> {
789        self.0
790            .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
791            .await
792            .map_err(Into::into)
793    }
794
795    async fn remove_dependent_queued_request(
796        &self,
797        room_id: &RoomId,
798        own_txn_id: &ChildTransactionId,
799    ) -> Result<bool, Self::Error> {
800        self.0.remove_dependent_queued_request(room_id, own_txn_id).await.map_err(Into::into)
801    }
802
803    async fn load_dependent_queued_requests(
804        &self,
805        room_id: &RoomId,
806    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
807        self.0.load_dependent_queued_requests(room_id).await.map_err(Into::into)
808    }
809
810    async fn update_dependent_queued_request(
811        &self,
812        room_id: &RoomId,
813        own_transaction_id: &ChildTransactionId,
814        new_content: DependentQueuedRequestKind,
815    ) -> Result<bool, Self::Error> {
816        self.0
817            .update_dependent_queued_request(room_id, own_transaction_id, new_content)
818            .await
819            .map_err(Into::into)
820    }
821
822    async fn upsert_thread_subscriptions(
823        &self,
824        updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
825    ) -> Result<(), Self::Error> {
826        self.0.upsert_thread_subscriptions(updates).await.map_err(Into::into)
827    }
828
829    async fn load_thread_subscription(
830        &self,
831        room: &RoomId,
832        thread_id: &EventId,
833    ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
834        self.0.load_thread_subscription(room, thread_id).await.map_err(Into::into)
835    }
836
837    async fn remove_thread_subscription(
838        &self,
839        room: &RoomId,
840        thread_id: &EventId,
841    ) -> Result<(), Self::Error> {
842        self.0.remove_thread_subscription(room, thread_id).await.map_err(Into::into)
843    }
844
845    async fn optimize(&self) -> Result<(), Self::Error> {
846        self.0.optimize().await.map_err(Into::into)
847    }
848
849    async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
850        self.0.get_size().await.map_err(Into::into)
851    }
852}
853
854/// Convenience functionality for state stores.
855#[cfg_attr(target_family = "wasm", async_trait(?Send))]
856#[cfg_attr(not(target_family = "wasm"), async_trait)]
857pub trait StateStoreExt: StateStore {
858    /// Get a specific state event of statically-known type.
859    ///
860    /// # Arguments
861    ///
862    /// * `room_id` - The id of the room the state event was received for.
863    async fn get_state_event_static<C>(
864        &self,
865        room_id: &RoomId,
866    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
867    where
868        C: StaticEventContent<IsPrefix = ruma::events::False>
869            + StaticStateEventContent<StateKey = EmptyStateKey>
870            + RedactContent,
871        C::Redacted: RedactedStateEventContent,
872    {
873        Ok(self.get_state_event(room_id, C::TYPE.into(), "").await?.map(|raw| raw.cast()))
874    }
875
876    /// Get a specific state event of statically-known type.
877    ///
878    /// # Arguments
879    ///
880    /// * `room_id` - The id of the room the state event was received for.
881    async fn get_state_event_static_for_key<C, K>(
882        &self,
883        room_id: &RoomId,
884        state_key: &K,
885    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
886    where
887        C: StaticEventContent<IsPrefix = ruma::events::False>
888            + StaticStateEventContent
889            + RedactContent,
890        C::StateKey: Borrow<K>,
891        C::Redacted: RedactedStateEventContent,
892        K: AsRef<str> + ?Sized + Sync,
893    {
894        Ok(self
895            .get_state_event(room_id, C::TYPE.into(), state_key.as_ref())
896            .await?
897            .map(|raw| raw.cast()))
898    }
899
900    /// Get a list of state events of a statically-known type for a given room.
901    ///
902    /// # Arguments
903    ///
904    /// * `room_id` - The id of the room to find events for.
905    async fn get_state_events_static<C>(
906        &self,
907        room_id: &RoomId,
908    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
909    where
910        C: StaticEventContent<IsPrefix = ruma::events::False>
911            + StaticStateEventContent
912            + RedactContent,
913        C::Redacted: RedactedStateEventContent,
914    {
915        // FIXME: Could be more efficient, if we had streaming store accessor functions
916        Ok(self
917            .get_state_events(room_id, C::TYPE.into())
918            .await?
919            .into_iter()
920            .map(|raw| raw.cast())
921            .collect())
922    }
923
924    /// Get a list of state events of a statically-known type for a given room
925    /// and given state keys.
926    ///
927    /// # Arguments
928    ///
929    /// * `room_id` - The id of the room to find events for.
930    ///
931    /// * `state_keys` - The list of state keys to find.
932    async fn get_state_events_for_keys_static<'a, C, K, I>(
933        &self,
934        room_id: &RoomId,
935        state_keys: I,
936    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
937    where
938        C: StaticEventContent<IsPrefix = ruma::events::False>
939            + StaticStateEventContent
940            + RedactContent,
941        C::StateKey: Borrow<K>,
942        C::Redacted: RedactedStateEventContent,
943        K: AsRef<str> + Sized + Sync + 'a,
944        I: IntoIterator<Item = &'a K> + Send,
945        I::IntoIter: Send,
946    {
947        Ok(self
948            .get_state_events_for_keys(
949                room_id,
950                C::TYPE.into(),
951                &state_keys.into_iter().map(|k| k.as_ref()).collect::<Vec<_>>(),
952            )
953            .await?
954            .into_iter()
955            .map(|raw| raw.cast())
956            .collect())
957    }
958
959    /// Get an event of a statically-known type from the account data store.
960    async fn get_account_data_event_static<C>(
961        &self,
962    ) -> Result<Option<Raw<GlobalAccountDataEvent<C>>>, Self::Error>
963    where
964        C: StaticEventContent<IsPrefix = ruma::events::False> + GlobalAccountDataEventContent,
965    {
966        Ok(self.get_account_data_event(C::TYPE.into()).await?.map(Raw::cast_unchecked))
967    }
968
969    /// Get an event of a statically-known type from the room account data
970    /// store.
971    ///
972    /// # Arguments
973    ///
974    /// * `room_id` - The id of the room for which the room account data event
975    ///   should be fetched.
976    async fn get_room_account_data_event_static<C>(
977        &self,
978        room_id: &RoomId,
979    ) -> Result<Option<Raw<RoomAccountDataEvent<C>>>, Self::Error>
980    where
981        C: StaticEventContent<IsPrefix = ruma::events::False> + RoomAccountDataEventContent,
982    {
983        Ok(self
984            .get_room_account_data_event(room_id, C::TYPE.into())
985            .await?
986            .map(Raw::cast_unchecked))
987    }
988
989    /// Get the `MemberEvent` for the given state key in the given room id.
990    ///
991    /// # Arguments
992    ///
993    /// * `room_id` - The room id the member event belongs to.
994    ///
995    /// * `state_key` - The user id that the member event defines the state for.
996    async fn get_member_event(
997        &self,
998        room_id: &RoomId,
999        state_key: &UserId,
1000    ) -> Result<Option<RawMemberEvent>, Self::Error> {
1001        self.get_state_event_static_for_key(room_id, state_key).await
1002    }
1003}
1004
1005#[cfg_attr(target_family = "wasm", async_trait(?Send))]
1006#[cfg_attr(not(target_family = "wasm"), async_trait)]
1007impl<T: StateStore + ?Sized> StateStoreExt for T {}
1008
1009/// A type-erased [`StateStore`].
1010pub type DynStateStore = dyn StateStore<Error = StoreError>;
1011
1012/// A type that can be type-erased into `Arc<dyn StateStore>`.
1013///
1014/// This trait is not meant to be implemented directly outside
1015/// `matrix-sdk-crypto`, but it is automatically implemented for everything that
1016/// implements `StateStore`.
1017pub trait IntoStateStore {
1018    #[doc(hidden)]
1019    fn into_state_store(self) -> Arc<DynStateStore>;
1020}
1021
1022impl<T> IntoStateStore for T
1023where
1024    T: StateStore + Sized + 'static,
1025{
1026    fn into_state_store(self) -> Arc<DynStateStore> {
1027        Arc::new(EraseStateStoreError(self))
1028    }
1029}
1030
1031// Turns a given `Arc<T>` into `Arc<DynStateStore>` by attaching the
1032// StateStore impl vtable of `EraseStateStoreError<T>`.
1033impl<T> IntoStateStore for Arc<T>
1034where
1035    T: StateStore + 'static,
1036{
1037    fn into_state_store(self) -> Arc<DynStateStore> {
1038        let ptr: *const T = Arc::into_raw(self);
1039        let ptr_erased = ptr as *const EraseStateStoreError<T>;
1040        // SAFETY: EraseStateStoreError is repr(transparent) so T and
1041        //         EraseStateStoreError<T> have the same layout and ABI
1042        unsafe { Arc::from_raw(ptr_erased) }
1043    }
1044}
1045
1046/// Serialisable representation of get_supported_versions::Response.
1047#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1048pub struct SupportedVersionsResponse {
1049    /// Versions supported by the remote server.
1050    pub versions: Vec<String>,
1051
1052    /// List of unstable features and their enablement status.
1053    pub unstable_features: BTreeMap<String, bool>,
1054}
1055
1056impl SupportedVersionsResponse {
1057    /// Extracts known Matrix versions and features from the un-typed lists of
1058    /// strings.
1059    ///
1060    /// Note: Matrix versions and features that Ruma cannot parse, or does not
1061    /// know about, are discarded.
1062    pub fn supported_versions(&self) -> SupportedVersions {
1063        let mut supported_versions =
1064            SupportedVersions::from_parts(&self.versions, &self.unstable_features);
1065
1066        // We need at least one supported version to be able to make requests, so we
1067        // default to Matrix 1.0.
1068        if supported_versions.versions.is_empty() {
1069            supported_versions.versions.insert(MatrixVersion::V1_0);
1070        }
1071
1072        supported_versions
1073    }
1074}
1075
1076#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1077/// A serialisable representation of discover_homeserver::Response.
1078pub struct WellKnownResponse {
1079    /// Information about the homeserver to connect to.
1080    pub homeserver: HomeserverInfo,
1081
1082    /// Information about the identity server to connect to.
1083    pub identity_server: Option<IdentityServerInfo>,
1084
1085    /// Information about the tile server to use to display location data.
1086    pub tile_server: Option<TileServerInfo>,
1087
1088    /// A list of the available MatrixRTC foci, ordered by priority.
1089    pub rtc_foci: Vec<RtcFocusInfo>,
1090}
1091
1092impl From<discover_homeserver::Response> for WellKnownResponse {
1093    fn from(response: discover_homeserver::Response) -> Self {
1094        Self {
1095            homeserver: response.homeserver,
1096            identity_server: response.identity_server,
1097            tile_server: response.tile_server,
1098            rtc_foci: response.rtc_foci,
1099        }
1100    }
1101}
1102
1103/// A value for key-value data that should be persisted into the store.
1104#[derive(Debug, Clone)]
1105pub enum StateStoreDataValue {
1106    /// The sync token.
1107    SyncToken(String),
1108
1109    /// The supported versions of the server.
1110    SupportedVersions(TtlValue<SupportedVersionsResponse>),
1111
1112    /// The well-known information of the server.
1113    WellKnown(TtlValue<Option<WellKnownResponse>>),
1114
1115    /// A filter with the given ID.
1116    Filter(String),
1117
1118    /// The user avatar url
1119    UserAvatarUrl(OwnedMxcUri),
1120
1121    /// A list of recently visited room identifiers for the current user
1122    RecentlyVisitedRooms(Vec<OwnedRoomId>),
1123
1124    /// Persistent data for
1125    /// `matrix_sdk_ui::unable_to_decrypt_hook::UtdHookManager`.
1126    UtdHookManagerData(GrowableBloom),
1127
1128    /// A unit value telling us that the client uploaded duplicate one-time
1129    /// keys.
1130    OneTimeKeyAlreadyUploaded,
1131
1132    /// A composer draft for the room.
1133    /// To learn more, see [`ComposerDraft`].
1134    ///
1135    /// [`ComposerDraft`]: Self::ComposerDraft
1136    ComposerDraft(ComposerDraft),
1137
1138    /// A list of knock request ids marked as seen in a room.
1139    SeenKnockRequests(BTreeMap<OwnedEventId, OwnedUserId>),
1140
1141    /// A list of tokens to continue thread subscriptions catchup.
1142    ///
1143    /// See documentation of [`ThreadSubscriptionCatchupToken`] for more
1144    /// details.
1145    ThreadSubscriptionsCatchupTokens(Vec<ThreadSubscriptionCatchupToken>),
1146
1147    /// The capabilities the homeserver supports or disables.
1148    HomeserverCapabilities(TtlValue<Capabilities>),
1149}
1150
1151/// Tokens to use when catching up on thread subscriptions.
1152///
1153/// These tokens are created when the client receives some thread subscriptions
1154/// from sync, but the sync indicates that there are more thread subscriptions
1155/// available on the server. In this case, it's expected that the client will
1156/// call the [MSC4308] companion endpoint to catch up (back-paginate) on
1157/// previous thread subscriptions.
1158///
1159/// [MSC4308]: https://github.com/matrix-org/matrix-spec-proposals/pull/4308
1160#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1161pub struct ThreadSubscriptionCatchupToken {
1162    /// The token to use as the lower bound when fetching new threads
1163    /// subscriptions.
1164    ///
1165    /// In sliding sync, this is the `prev_batch` value of a sliding sync
1166    /// response.
1167    pub from: String,
1168
1169    /// The token to use as the upper bound when fetching new threads
1170    /// subscriptions.
1171    ///
1172    /// In sliding sync, it must be set to the `pos` value of the sliding sync
1173    /// *request*, which response received a `prev_batch` token.
1174    pub to: Option<String>,
1175}
1176
1177/// Current draft of the composer for the room.
1178#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1179pub struct ComposerDraft {
1180    /// The draft content in plain text.
1181    pub plain_text: String,
1182    /// If the message is formatted in HTML, the HTML representation of the
1183    /// message.
1184    pub html_text: Option<String>,
1185    /// The type of draft.
1186    pub draft_type: ComposerDraftType,
1187    /// Attachments associated with this draft.
1188    #[serde(default)]
1189    pub attachments: Vec<DraftAttachment>,
1190}
1191
1192/// An attachment stored with a composer draft.
1193#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1194pub struct DraftAttachment {
1195    /// The filename of the attachment.
1196    pub filename: String,
1197    /// The attachment content with type-specific data.
1198    pub content: DraftAttachmentContent,
1199}
1200
1201/// The content of a draft attachment with type-specific data.
1202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1203#[serde(tag = "type")]
1204pub enum DraftAttachmentContent {
1205    /// Image attachment.
1206    Image {
1207        /// The image file data.
1208        data: Vec<u8>,
1209        /// MIME type.
1210        mimetype: Option<String>,
1211        /// File size in bytes.
1212        size: Option<u64>,
1213        /// Width in pixels.
1214        width: Option<u64>,
1215        /// Height in pixels.
1216        height: Option<u64>,
1217        /// BlurHash string.
1218        blurhash: Option<String>,
1219        /// Optional thumbnail.
1220        thumbnail: Option<DraftThumbnail>,
1221    },
1222    /// Video attachment.
1223    Video {
1224        /// The video file data.
1225        data: Vec<u8>,
1226        /// MIME type.
1227        mimetype: Option<String>,
1228        /// File size in bytes.
1229        size: Option<u64>,
1230        /// Width in pixels.
1231        width: Option<u64>,
1232        /// Height in pixels.
1233        height: Option<u64>,
1234        /// Duration.
1235        duration: Option<std::time::Duration>,
1236        /// BlurHash string.
1237        blurhash: Option<String>,
1238        /// Optional thumbnail.
1239        thumbnail: Option<DraftThumbnail>,
1240    },
1241    /// Audio attachment.
1242    Audio {
1243        /// The audio file data.
1244        data: Vec<u8>,
1245        /// MIME type.
1246        mimetype: Option<String>,
1247        /// File size in bytes.
1248        size: Option<u64>,
1249        /// Duration.
1250        duration: Option<std::time::Duration>,
1251    },
1252    /// Generic file attachment.
1253    File {
1254        /// The file data.
1255        data: Vec<u8>,
1256        /// MIME type.
1257        mimetype: Option<String>,
1258        /// File size in bytes.
1259        size: Option<u64>,
1260    },
1261}
1262
1263/// Thumbnail data for a draft attachment.
1264#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1265pub struct DraftThumbnail {
1266    /// The filename of the thumbnail.
1267    pub filename: String,
1268    /// The thumbnail image data.
1269    pub data: Vec<u8>,
1270    /// MIME type of the thumbnail.
1271    pub mimetype: Option<String>,
1272    /// Width in pixels.
1273    pub width: Option<u64>,
1274    /// Height in pixels.
1275    pub height: Option<u64>,
1276    /// File size in bytes.
1277    pub size: Option<u64>,
1278}
1279
1280/// The type of draft of the composer.
1281#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1282pub enum ComposerDraftType {
1283    /// The draft is a new message.
1284    NewMessage,
1285    /// The draft is a reply to an event.
1286    Reply {
1287        /// The ID of the event being replied to.
1288        event_id: OwnedEventId,
1289    },
1290    /// The draft is an edit of an event.
1291    Edit {
1292        /// The ID of the event being edited.
1293        event_id: OwnedEventId,
1294    },
1295}
1296
1297impl StateStoreDataValue {
1298    /// Get this value if it is a sync token.
1299    pub fn into_sync_token(self) -> Option<String> {
1300        as_variant!(self, Self::SyncToken)
1301    }
1302
1303    /// Get this value if it is a filter.
1304    pub fn into_filter(self) -> Option<String> {
1305        as_variant!(self, Self::Filter)
1306    }
1307
1308    /// Get this value if it is a user avatar url.
1309    pub fn into_user_avatar_url(self) -> Option<OwnedMxcUri> {
1310        as_variant!(self, Self::UserAvatarUrl)
1311    }
1312
1313    /// Get this value if it is a list of recently visited rooms.
1314    pub fn into_recently_visited_rooms(self) -> Option<Vec<OwnedRoomId>> {
1315        as_variant!(self, Self::RecentlyVisitedRooms)
1316    }
1317
1318    /// Get this value if it is the data for the `UtdHookManager`.
1319    pub fn into_utd_hook_manager_data(self) -> Option<GrowableBloom> {
1320        as_variant!(self, Self::UtdHookManagerData)
1321    }
1322
1323    /// Get this value if it is a composer draft.
1324    pub fn into_composer_draft(self) -> Option<ComposerDraft> {
1325        as_variant!(self, Self::ComposerDraft)
1326    }
1327
1328    /// Get this value if it is the supported versions metadata.
1329    pub fn into_supported_versions(self) -> Option<TtlValue<SupportedVersionsResponse>> {
1330        as_variant!(self, Self::SupportedVersions)
1331    }
1332
1333    /// Get this value if it is the well-known metadata.
1334    pub fn into_well_known(self) -> Option<TtlValue<Option<WellKnownResponse>>> {
1335        as_variant!(self, Self::WellKnown)
1336    }
1337
1338    /// Get this value if it is the data for the ignored join requests.
1339    pub fn into_seen_knock_requests(self) -> Option<BTreeMap<OwnedEventId, OwnedUserId>> {
1340        as_variant!(self, Self::SeenKnockRequests)
1341    }
1342
1343    /// Get this value if it is the data for the thread subscriptions catchup
1344    /// tokens.
1345    pub fn into_thread_subscriptions_catchup_tokens(
1346        self,
1347    ) -> Option<Vec<ThreadSubscriptionCatchupToken>> {
1348        as_variant!(self, Self::ThreadSubscriptionsCatchupTokens)
1349    }
1350
1351    /// Get this value if it is the data for the capabilities the homeserver
1352    /// supports or disables.
1353    pub fn into_homeserver_capabilities(self) -> Option<TtlValue<Capabilities>> {
1354        as_variant!(self, Self::HomeserverCapabilities)
1355    }
1356}
1357
1358/// A key for key-value data.
1359#[derive(Debug, Clone, Copy)]
1360pub enum StateStoreDataKey<'a> {
1361    /// The sync token.
1362    SyncToken,
1363
1364    /// The supported versions of the server,
1365    SupportedVersions,
1366
1367    /// The well-known information of the server,
1368    WellKnown,
1369
1370    /// A filter with the given name.
1371    Filter(&'a str),
1372
1373    /// Avatar URL
1374    UserAvatarUrl(&'a UserId),
1375
1376    /// Recently visited room identifiers
1377    RecentlyVisitedRooms(&'a UserId),
1378
1379    /// Persistent data for
1380    /// `matrix_sdk_ui::unable_to_decrypt_hook::UtdHookManager`.
1381    UtdHookManagerData,
1382
1383    /// Data remembering if the client already reported that it has uploaded
1384    /// duplicate one-time keys.
1385    OneTimeKeyAlreadyUploaded,
1386
1387    /// A composer draft for the room.
1388    /// To learn more, see [`ComposerDraft`].
1389    ///
1390    /// [`ComposerDraft`]: Self::ComposerDraft
1391    ComposerDraft(&'a RoomId, Option<&'a EventId>),
1392
1393    /// A list of knock request ids marked as seen in a room.
1394    SeenKnockRequests(&'a RoomId),
1395
1396    /// A list of thread subscriptions catchup tokens.
1397    ThreadSubscriptionsCatchupTokens,
1398
1399    /// A list of capabilities that the homeserver supports.
1400    HomeserverCapabilities,
1401}
1402
1403impl StateStoreDataKey<'_> {
1404    /// Key to use for the [`SyncToken`][Self::SyncToken] variant.
1405    pub const SYNC_TOKEN: &'static str = "sync_token";
1406
1407    /// Key to use for the [`SupportedVersions`][Self::SupportedVersions]
1408    /// variant.
1409    pub const SUPPORTED_VERSIONS: &'static str = "server_capabilities"; // Note: this is the old name, kept for backwards compatibility.
1410
1411    /// Key to use for the [`WellKnown`][Self::WellKnown]
1412    /// variant.
1413    pub const WELL_KNOWN: &'static str = "well_known";
1414
1415    /// Key prefix to use for the [`Filter`][Self::Filter] variant.
1416    pub const FILTER: &'static str = "filter";
1417
1418    /// Key prefix to use for the [`UserAvatarUrl`][Self::UserAvatarUrl]
1419    /// variant.
1420    pub const USER_AVATAR_URL: &'static str = "user_avatar_url";
1421
1422    /// Key prefix to use for the
1423    /// [`RecentlyVisitedRooms`][Self::RecentlyVisitedRooms] variant.
1424    pub const RECENTLY_VISITED_ROOMS: &'static str = "recently_visited_rooms";
1425
1426    /// Key to use for the [`UtdHookManagerData`][Self::UtdHookManagerData]
1427    /// variant.
1428    pub const UTD_HOOK_MANAGER_DATA: &'static str = "utd_hook_manager_data";
1429
1430    /// Key to use for the flag remembering that we already reported that we
1431    /// uploaded duplicate one-time keys.
1432    pub const ONE_TIME_KEY_ALREADY_UPLOADED: &'static str = "one_time_key_already_uploaded";
1433
1434    /// Key prefix to use for the [`ComposerDraft`][Self::ComposerDraft]
1435    /// variant.
1436    pub const COMPOSER_DRAFT: &'static str = "composer_draft";
1437
1438    /// Key prefix to use for the
1439    /// [`SeenKnockRequests`][Self::SeenKnockRequests] variant.
1440    pub const SEEN_KNOCK_REQUESTS: &'static str = "seen_knock_requests";
1441
1442    /// Key prefix to use for the
1443    /// [`ThreadSubscriptionsCatchupTokens`][Self::ThreadSubscriptionsCatchupTokens] variant.
1444    pub const THREAD_SUBSCRIPTIONS_CATCHUP_TOKENS: &'static str =
1445        "thread_subscriptions_catchup_tokens";
1446
1447    /// Key prefix to use for the homeserver's [`Capabilities`].
1448    pub const HOMESERVER_CAPABILITIES: &'static str = "homeserver_capabilities";
1449}
1450
1451/// Compare two thread subscription changes bump stamps, given a fixed room and
1452/// thread root event id pair.
1453///
1454/// May update the newer one to keep the previous one if needed, under some
1455/// conditions.
1456///
1457/// Returns true if the new subscription should be stored, or false if the new
1458/// subscription should be ignored.
1459pub fn compare_thread_subscription_bump_stamps(
1460    previous: Option<u64>,
1461    new: &mut Option<u64>,
1462) -> bool {
1463    match (previous, &new) {
1464        // If the previous subscription had a bump stamp, and the new one doesn't, keep the
1465        // previous one; it should be updated soon via sync anyways.
1466        (Some(prev_bump), None) => {
1467            *new = Some(prev_bump);
1468        }
1469
1470        // If the previous bump stamp is newer than the new one, don't store the value at all.
1471        (Some(prev_bump), Some(new_bump)) if *new_bump <= prev_bump => {
1472            return false;
1473        }
1474
1475        // In all other cases, keep the new bumpstamp.
1476        _ => {}
1477    }
1478
1479    true
1480}