1use std::{
16    borrow::Borrow,
17    collections::{BTreeMap, BTreeSet, HashMap},
18    fmt,
19    sync::Arc,
20};
21
22use as_variant::as_variant;
23use async_trait::async_trait;
24use growable_bloom_filter::GrowableBloom;
25use matrix_sdk_common::AsyncTraitDeps;
26use ruma::{
27    api::MatrixVersion,
28    events::{
29        presence::PresenceEvent,
30        receipt::{Receipt, ReceiptThread, ReceiptType},
31        AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, EmptyStateKey, GlobalAccountDataEvent,
32        GlobalAccountDataEventContent, GlobalAccountDataEventType, RedactContent,
33        RedactedStateEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
34        RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
35    },
36    serde::Raw,
37    time::SystemTime,
38    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId,
39    OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId,
40};
41use serde::{Deserialize, Serialize};
42
43use super::{
44    send_queue::SentRequestKey, ChildTransactionId, DependentQueuedRequest,
45    DependentQueuedRequestKind, QueueWedgeError, QueuedRequest, QueuedRequestKind, StateChanges,
46    StoreError,
47};
48use crate::{
49    deserialized_responses::{
50        DisplayName, RawAnySyncOrStrippedState, RawMemberEvent, RawSyncOrStrippedState,
51    },
52    MinimalRoomMemberEvent, RoomInfo, RoomMemberships,
53};
54
55#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
58#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
59pub trait StateStore: AsyncTraitDeps {
60    type Error: fmt::Debug + Into<StoreError> + From<serde_json::Error>;
62
63    async fn get_kv_data(
69        &self,
70        key: StateStoreDataKey<'_>,
71    ) -> Result<Option<StateStoreDataValue>, Self::Error>;
72
73    async fn set_kv_data(
83        &self,
84        key: StateStoreDataKey<'_>,
85        value: StateStoreDataValue,
86    ) -> Result<(), Self::Error>;
87
88    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error>;
94
95    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error>;
97
98    async fn get_presence_event(
105        &self,
106        user_id: &UserId,
107    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error>;
108
109    async fn get_presence_events(
115        &self,
116        user_ids: &[OwnedUserId],
117    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error>;
118
119    async fn get_state_event(
127        &self,
128        room_id: &RoomId,
129        event_type: StateEventType,
130        state_key: &str,
131    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error>;
132
133    async fn get_state_events(
141        &self,
142        room_id: &RoomId,
143        event_type: StateEventType,
144    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
145
146    async fn get_state_events_for_keys(
157        &self,
158        room_id: &RoomId,
159        event_type: StateEventType,
160        state_keys: &[&str],
161    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
162
163    async fn get_profile(
171        &self,
172        room_id: &RoomId,
173        user_id: &UserId,
174    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error>;
175
176    async fn get_profiles<'a>(
184        &self,
185        room_id: &RoomId,
186        user_ids: &'a [OwnedUserId],
187    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error>;
188
189    async fn get_user_ids(
192        &self,
193        room_id: &RoomId,
194        memberships: RoomMemberships,
195    ) -> Result<Vec<OwnedUserId>, Self::Error>;
196
197    async fn get_room_infos(&self) -> Result<Vec<RoomInfo>, Self::Error>;
199
200    async fn get_users_with_display_name(
209        &self,
210        room_id: &RoomId,
211        display_name: &DisplayName,
212    ) -> Result<BTreeSet<OwnedUserId>, Self::Error>;
213
214    async fn get_users_with_display_names<'a>(
222        &self,
223        room_id: &RoomId,
224        display_names: &'a [DisplayName],
225    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error>;
226
227    async fn get_account_data_event(
233        &self,
234        event_type: GlobalAccountDataEventType,
235    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error>;
236
237    async fn get_room_account_data_event(
247        &self,
248        room_id: &RoomId,
249        event_type: RoomAccountDataEventType,
250    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error>;
251
252    async fn get_user_room_receipt_event(
265        &self,
266        room_id: &RoomId,
267        receipt_type: ReceiptType,
268        thread: ReceiptThread,
269        user_id: &UserId,
270    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error>;
271
272    async fn get_event_room_receipt_events(
286        &self,
287        room_id: &RoomId,
288        receipt_type: ReceiptType,
289        thread: ReceiptThread,
290        event_id: &EventId,
291    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error>;
292
293    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
299
300    async fn set_custom_value(
309        &self,
310        key: &[u8],
311        value: Vec<u8>,
312    ) -> Result<Option<Vec<u8>>, Self::Error>;
313
314    async fn set_custom_value_no_read(
328        &self,
329        key: &[u8],
330        value: Vec<u8>,
331    ) -> Result<(), Self::Error> {
332        self.set_custom_value(key, value).await.map(|_| ())
333    }
334
335    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
341
342    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error>;
348
349    async fn save_send_queue_request(
359        &self,
360        room_id: &RoomId,
361        transaction_id: OwnedTransactionId,
362        created_at: MilliSecondsSinceUnixEpoch,
363        request: QueuedRequestKind,
364        priority: usize,
365    ) -> Result<(), Self::Error>;
366
367    async fn update_send_queue_request(
379        &self,
380        room_id: &RoomId,
381        transaction_id: &TransactionId,
382        content: QueuedRequestKind,
383    ) -> Result<bool, Self::Error>;
384
385    async fn remove_send_queue_request(
391        &self,
392        room_id: &RoomId,
393        transaction_id: &TransactionId,
394    ) -> Result<bool, Self::Error>;
395
396    async fn load_send_queue_requests(
402        &self,
403        room_id: &RoomId,
404    ) -> Result<Vec<QueuedRequest>, Self::Error>;
405
406    async fn update_send_queue_request_status(
409        &self,
410        room_id: &RoomId,
411        transaction_id: &TransactionId,
412        error: Option<QueueWedgeError>,
413    ) -> Result<(), Self::Error>;
414
415    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error>;
417
418    async fn save_dependent_queued_request(
421        &self,
422        room_id: &RoomId,
423        parent_txn_id: &TransactionId,
424        own_txn_id: ChildTransactionId,
425        created_at: MilliSecondsSinceUnixEpoch,
426        content: DependentQueuedRequestKind,
427    ) -> Result<(), Self::Error>;
428
429    async fn mark_dependent_queued_requests_as_ready(
438        &self,
439        room_id: &RoomId,
440        parent_txn_id: &TransactionId,
441        sent_parent_key: SentRequestKey,
442    ) -> Result<usize, Self::Error>;
443
444    async fn update_dependent_queued_request(
448        &self,
449        room_id: &RoomId,
450        own_transaction_id: &ChildTransactionId,
451        new_content: DependentQueuedRequestKind,
452    ) -> Result<bool, Self::Error>;
453
454    async fn remove_dependent_queued_request(
459        &self,
460        room: &RoomId,
461        own_txn_id: &ChildTransactionId,
462    ) -> Result<bool, Self::Error>;
463
464    async fn load_dependent_queued_requests(
470        &self,
471        room: &RoomId,
472    ) -> Result<Vec<DependentQueuedRequest>, Self::Error>;
473}
474
475#[repr(transparent)]
476struct EraseStateStoreError<T>(T);
477
478#[cfg(not(tarpaulin_include))]
479impl<T: fmt::Debug> fmt::Debug for EraseStateStoreError<T> {
480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481        self.0.fmt(f)
482    }
483}
484
485#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
486#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
487impl<T: StateStore> StateStore for EraseStateStoreError<T> {
488    type Error = StoreError;
489
490    async fn get_kv_data(
491        &self,
492        key: StateStoreDataKey<'_>,
493    ) -> Result<Option<StateStoreDataValue>, Self::Error> {
494        self.0.get_kv_data(key).await.map_err(Into::into)
495    }
496
497    async fn set_kv_data(
498        &self,
499        key: StateStoreDataKey<'_>,
500        value: StateStoreDataValue,
501    ) -> Result<(), Self::Error> {
502        self.0.set_kv_data(key, value).await.map_err(Into::into)
503    }
504
505    async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
506        self.0.remove_kv_data(key).await.map_err(Into::into)
507    }
508
509    async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
510        self.0.save_changes(changes).await.map_err(Into::into)
511    }
512
513    async fn get_presence_event(
514        &self,
515        user_id: &UserId,
516    ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
517        self.0.get_presence_event(user_id).await.map_err(Into::into)
518    }
519
520    async fn get_presence_events(
521        &self,
522        user_ids: &[OwnedUserId],
523    ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
524        self.0.get_presence_events(user_ids).await.map_err(Into::into)
525    }
526
527    async fn get_state_event(
528        &self,
529        room_id: &RoomId,
530        event_type: StateEventType,
531        state_key: &str,
532    ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
533        self.0.get_state_event(room_id, event_type, state_key).await.map_err(Into::into)
534    }
535
536    async fn get_state_events(
537        &self,
538        room_id: &RoomId,
539        event_type: StateEventType,
540    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
541        self.0.get_state_events(room_id, event_type).await.map_err(Into::into)
542    }
543
544    async fn get_state_events_for_keys(
545        &self,
546        room_id: &RoomId,
547        event_type: StateEventType,
548        state_keys: &[&str],
549    ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
550        self.0.get_state_events_for_keys(room_id, event_type, state_keys).await.map_err(Into::into)
551    }
552
553    async fn get_profile(
554        &self,
555        room_id: &RoomId,
556        user_id: &UserId,
557    ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
558        self.0.get_profile(room_id, user_id).await.map_err(Into::into)
559    }
560
561    async fn get_profiles<'a>(
562        &self,
563        room_id: &RoomId,
564        user_ids: &'a [OwnedUserId],
565    ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
566        self.0.get_profiles(room_id, user_ids).await.map_err(Into::into)
567    }
568
569    async fn get_user_ids(
570        &self,
571        room_id: &RoomId,
572        memberships: RoomMemberships,
573    ) -> Result<Vec<OwnedUserId>, Self::Error> {
574        self.0.get_user_ids(room_id, memberships).await.map_err(Into::into)
575    }
576
577    async fn get_room_infos(&self) -> Result<Vec<RoomInfo>, Self::Error> {
578        self.0.get_room_infos().await.map_err(Into::into)
579    }
580
581    async fn get_users_with_display_name(
582        &self,
583        room_id: &RoomId,
584        display_name: &DisplayName,
585    ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
586        self.0.get_users_with_display_name(room_id, display_name).await.map_err(Into::into)
587    }
588
589    async fn get_users_with_display_names<'a>(
590        &self,
591        room_id: &RoomId,
592        display_names: &'a [DisplayName],
593    ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
594        self.0.get_users_with_display_names(room_id, display_names).await.map_err(Into::into)
595    }
596
597    async fn get_account_data_event(
598        &self,
599        event_type: GlobalAccountDataEventType,
600    ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
601        self.0.get_account_data_event(event_type).await.map_err(Into::into)
602    }
603
604    async fn get_room_account_data_event(
605        &self,
606        room_id: &RoomId,
607        event_type: RoomAccountDataEventType,
608    ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
609        self.0.get_room_account_data_event(room_id, event_type).await.map_err(Into::into)
610    }
611
612    async fn get_user_room_receipt_event(
613        &self,
614        room_id: &RoomId,
615        receipt_type: ReceiptType,
616        thread: ReceiptThread,
617        user_id: &UserId,
618    ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
619        self.0
620            .get_user_room_receipt_event(room_id, receipt_type, thread, user_id)
621            .await
622            .map_err(Into::into)
623    }
624
625    async fn get_event_room_receipt_events(
626        &self,
627        room_id: &RoomId,
628        receipt_type: ReceiptType,
629        thread: ReceiptThread,
630        event_id: &EventId,
631    ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
632        self.0
633            .get_event_room_receipt_events(room_id, receipt_type, thread, event_id)
634            .await
635            .map_err(Into::into)
636    }
637
638    async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
639        self.0.get_custom_value(key).await.map_err(Into::into)
640    }
641
642    async fn set_custom_value(
643        &self,
644        key: &[u8],
645        value: Vec<u8>,
646    ) -> Result<Option<Vec<u8>>, Self::Error> {
647        self.0.set_custom_value(key, value).await.map_err(Into::into)
648    }
649
650    async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
651        self.0.remove_custom_value(key).await.map_err(Into::into)
652    }
653
654    async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
655        self.0.remove_room(room_id).await.map_err(Into::into)
656    }
657
658    async fn save_send_queue_request(
659        &self,
660        room_id: &RoomId,
661        transaction_id: OwnedTransactionId,
662        created_at: MilliSecondsSinceUnixEpoch,
663        content: QueuedRequestKind,
664        priority: usize,
665    ) -> Result<(), Self::Error> {
666        self.0
667            .save_send_queue_request(room_id, transaction_id, created_at, content, priority)
668            .await
669            .map_err(Into::into)
670    }
671
672    async fn update_send_queue_request(
673        &self,
674        room_id: &RoomId,
675        transaction_id: &TransactionId,
676        content: QueuedRequestKind,
677    ) -> Result<bool, Self::Error> {
678        self.0.update_send_queue_request(room_id, transaction_id, content).await.map_err(Into::into)
679    }
680
681    async fn remove_send_queue_request(
682        &self,
683        room_id: &RoomId,
684        transaction_id: &TransactionId,
685    ) -> Result<bool, Self::Error> {
686        self.0.remove_send_queue_request(room_id, transaction_id).await.map_err(Into::into)
687    }
688
689    async fn load_send_queue_requests(
690        &self,
691        room_id: &RoomId,
692    ) -> Result<Vec<QueuedRequest>, Self::Error> {
693        self.0.load_send_queue_requests(room_id).await.map_err(Into::into)
694    }
695
696    async fn update_send_queue_request_status(
697        &self,
698        room_id: &RoomId,
699        transaction_id: &TransactionId,
700        error: Option<QueueWedgeError>,
701    ) -> Result<(), Self::Error> {
702        self.0
703            .update_send_queue_request_status(room_id, transaction_id, error)
704            .await
705            .map_err(Into::into)
706    }
707
708    async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
709        self.0.load_rooms_with_unsent_requests().await.map_err(Into::into)
710    }
711
712    async fn save_dependent_queued_request(
713        &self,
714        room_id: &RoomId,
715        parent_txn_id: &TransactionId,
716        own_txn_id: ChildTransactionId,
717        created_at: MilliSecondsSinceUnixEpoch,
718        content: DependentQueuedRequestKind,
719    ) -> Result<(), Self::Error> {
720        self.0
721            .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
722            .await
723            .map_err(Into::into)
724    }
725
726    async fn mark_dependent_queued_requests_as_ready(
727        &self,
728        room_id: &RoomId,
729        parent_txn_id: &TransactionId,
730        sent_parent_key: SentRequestKey,
731    ) -> Result<usize, Self::Error> {
732        self.0
733            .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
734            .await
735            .map_err(Into::into)
736    }
737
738    async fn remove_dependent_queued_request(
739        &self,
740        room_id: &RoomId,
741        own_txn_id: &ChildTransactionId,
742    ) -> Result<bool, Self::Error> {
743        self.0.remove_dependent_queued_request(room_id, own_txn_id).await.map_err(Into::into)
744    }
745
746    async fn load_dependent_queued_requests(
747        &self,
748        room_id: &RoomId,
749    ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
750        self.0.load_dependent_queued_requests(room_id).await.map_err(Into::into)
751    }
752
753    async fn update_dependent_queued_request(
754        &self,
755        room_id: &RoomId,
756        own_transaction_id: &ChildTransactionId,
757        new_content: DependentQueuedRequestKind,
758    ) -> Result<bool, Self::Error> {
759        self.0
760            .update_dependent_queued_request(room_id, own_transaction_id, new_content)
761            .await
762            .map_err(Into::into)
763    }
764}
765
766#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
768#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
769pub trait StateStoreExt: StateStore {
770    async fn get_state_event_static<C>(
776        &self,
777        room_id: &RoomId,
778    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
779    where
780        C: StaticEventContent + StaticStateEventContent<StateKey = EmptyStateKey> + RedactContent,
781        C::Redacted: RedactedStateEventContent,
782    {
783        Ok(self.get_state_event(room_id, C::TYPE.into(), "").await?.map(|raw| raw.cast()))
784    }
785
786    async fn get_state_event_static_for_key<C, K>(
792        &self,
793        room_id: &RoomId,
794        state_key: &K,
795    ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
796    where
797        C: StaticEventContent + StaticStateEventContent + RedactContent,
798        C::StateKey: Borrow<K>,
799        C::Redacted: RedactedStateEventContent,
800        K: AsRef<str> + ?Sized + Sync,
801    {
802        Ok(self
803            .get_state_event(room_id, C::TYPE.into(), state_key.as_ref())
804            .await?
805            .map(|raw| raw.cast()))
806    }
807
808    async fn get_state_events_static<C>(
814        &self,
815        room_id: &RoomId,
816    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
817    where
818        C: StaticEventContent + StaticStateEventContent + RedactContent,
819        C::Redacted: RedactedStateEventContent,
820    {
821        Ok(self
823            .get_state_events(room_id, C::TYPE.into())
824            .await?
825            .into_iter()
826            .map(|raw| raw.cast())
827            .collect())
828    }
829
830    async fn get_state_events_for_keys_static<'a, C, K, I>(
839        &self,
840        room_id: &RoomId,
841        state_keys: I,
842    ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
843    where
844        C: StaticEventContent + StaticStateEventContent + RedactContent,
845        C::StateKey: Borrow<K>,
846        C::Redacted: RedactedStateEventContent,
847        K: AsRef<str> + Sized + Sync + 'a,
848        I: IntoIterator<Item = &'a K> + Send,
849        I::IntoIter: Send,
850    {
851        Ok(self
852            .get_state_events_for_keys(
853                room_id,
854                C::TYPE.into(),
855                &state_keys.into_iter().map(|k| k.as_ref()).collect::<Vec<_>>(),
856            )
857            .await?
858            .into_iter()
859            .map(|raw| raw.cast())
860            .collect())
861    }
862
863    async fn get_account_data_event_static<C>(
865        &self,
866    ) -> Result<Option<Raw<GlobalAccountDataEvent<C>>>, Self::Error>
867    where
868        C: StaticEventContent + GlobalAccountDataEventContent,
869    {
870        Ok(self.get_account_data_event(C::TYPE.into()).await?.map(Raw::cast))
871    }
872
873    async fn get_room_account_data_event_static<C>(
881        &self,
882        room_id: &RoomId,
883    ) -> Result<Option<Raw<RoomAccountDataEvent<C>>>, Self::Error>
884    where
885        C: StaticEventContent + RoomAccountDataEventContent,
886    {
887        Ok(self.get_room_account_data_event(room_id, C::TYPE.into()).await?.map(Raw::cast))
888    }
889
890    async fn get_member_event(
898        &self,
899        room_id: &RoomId,
900        state_key: &UserId,
901    ) -> Result<Option<RawMemberEvent>, Self::Error> {
902        self.get_state_event_static_for_key(room_id, state_key).await
903    }
904}
905
906#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
907#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
908impl<T: StateStore + ?Sized> StateStoreExt for T {}
909
910pub type DynStateStore = dyn StateStore<Error = StoreError>;
912
913pub trait IntoStateStore {
919    #[doc(hidden)]
920    fn into_state_store(self) -> Arc<DynStateStore>;
921}
922
923impl<T> IntoStateStore for T
924where
925    T: StateStore + Sized + 'static,
926{
927    fn into_state_store(self) -> Arc<DynStateStore> {
928        Arc::new(EraseStateStoreError(self))
929    }
930}
931
932impl<T> IntoStateStore for Arc<T>
935where
936    T: StateStore + 'static,
937{
938    fn into_state_store(self) -> Arc<DynStateStore> {
939        let ptr: *const T = Arc::into_raw(self);
940        let ptr_erased = ptr as *const EraseStateStoreError<T>;
941        unsafe { Arc::from_raw(ptr_erased) }
944    }
945}
946
947#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
949pub struct ServerCapabilities {
950    pub versions: Vec<String>,
954
955    pub unstable_features: BTreeMap<String, bool>,
957
958    last_fetch_ts: f64,
961}
962
963impl ServerCapabilities {
964    pub const STALE_THRESHOLD: f64 = (1000 * 60 * 60 * 24 * 7) as _; pub fn new(versions: &[MatrixVersion], unstable_features: BTreeMap<String, bool>) -> Self {
969        Self {
970            versions: versions.iter().map(|item| item.to_string()).collect(),
971            unstable_features,
972            last_fetch_ts: now_timestamp_ms(),
973        }
974    }
975
976    pub fn maybe_decode(&self) -> Option<(Vec<MatrixVersion>, BTreeMap<String, bool>)> {
982        if now_timestamp_ms() - self.last_fetch_ts >= Self::STALE_THRESHOLD {
983            None
984        } else {
985            Some((
986                self.versions.iter().filter_map(|item| item.parse().ok()).collect(),
987                self.unstable_features.clone(),
988            ))
989        }
990    }
991}
992
993fn now_timestamp_ms() -> f64 {
995    SystemTime::now()
996        .duration_since(SystemTime::UNIX_EPOCH)
997        .expect("System clock was before 1970.")
998        .as_secs_f64()
999        * 1000.0
1000}
1001
1002#[derive(Debug, Clone)]
1004pub enum StateStoreDataValue {
1005    SyncToken(String),
1007
1008    ServerCapabilities(ServerCapabilities),
1010
1011    Filter(String),
1013
1014    UserAvatarUrl(OwnedMxcUri),
1016
1017    RecentlyVisitedRooms(Vec<OwnedRoomId>),
1019
1020    UtdHookManagerData(GrowableBloom),
1023
1024    ComposerDraft(ComposerDraft),
1029
1030    SeenKnockRequests(BTreeMap<OwnedEventId, OwnedUserId>),
1032}
1033
1034#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1036pub struct ComposerDraft {
1037    pub plain_text: String,
1039    pub html_text: Option<String>,
1042    pub draft_type: ComposerDraftType,
1044}
1045
1046#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1048pub enum ComposerDraftType {
1049    NewMessage,
1051    Reply {
1053        event_id: OwnedEventId,
1055    },
1056    Edit {
1058        event_id: OwnedEventId,
1060    },
1061}
1062
1063impl StateStoreDataValue {
1064    pub fn into_sync_token(self) -> Option<String> {
1066        as_variant!(self, Self::SyncToken)
1067    }
1068
1069    pub fn into_filter(self) -> Option<String> {
1071        as_variant!(self, Self::Filter)
1072    }
1073
1074    pub fn into_user_avatar_url(self) -> Option<OwnedMxcUri> {
1076        as_variant!(self, Self::UserAvatarUrl)
1077    }
1078
1079    pub fn into_recently_visited_rooms(self) -> Option<Vec<OwnedRoomId>> {
1081        as_variant!(self, Self::RecentlyVisitedRooms)
1082    }
1083
1084    pub fn into_utd_hook_manager_data(self) -> Option<GrowableBloom> {
1086        as_variant!(self, Self::UtdHookManagerData)
1087    }
1088
1089    pub fn into_composer_draft(self) -> Option<ComposerDraft> {
1091        as_variant!(self, Self::ComposerDraft)
1092    }
1093
1094    pub fn into_server_capabilities(self) -> Option<ServerCapabilities> {
1096        as_variant!(self, Self::ServerCapabilities)
1097    }
1098
1099    pub fn into_seen_knock_requests(self) -> Option<BTreeMap<OwnedEventId, OwnedUserId>> {
1101        as_variant!(self, Self::SeenKnockRequests)
1102    }
1103}
1104
1105#[derive(Debug, Clone, Copy)]
1107pub enum StateStoreDataKey<'a> {
1108    SyncToken,
1110
1111    ServerCapabilities,
1113
1114    Filter(&'a str),
1116
1117    UserAvatarUrl(&'a UserId),
1119
1120    RecentlyVisitedRooms(&'a UserId),
1122
1123    UtdHookManagerData,
1126
1127    ComposerDraft(&'a RoomId),
1132
1133    SeenKnockRequests(&'a RoomId),
1135}
1136
1137impl StateStoreDataKey<'_> {
1138    pub const SYNC_TOKEN: &'static str = "sync_token";
1140    pub const SERVER_CAPABILITIES: &'static str = "server_capabilities";
1143    pub const FILTER: &'static str = "filter";
1145    pub const USER_AVATAR_URL: &'static str = "user_avatar_url";
1148
1149    pub const RECENTLY_VISITED_ROOMS: &'static str = "recently_visited_rooms";
1152
1153    pub const UTD_HOOK_MANAGER_DATA: &'static str = "utd_hook_manager_data";
1156
1157    pub const COMPOSER_DRAFT: &'static str = "composer_draft";
1160
1161    pub const SEEN_KNOCK_REQUESTS: &'static str = "seen_knock_requests";
1164}
1165
1166#[cfg(test)]
1167mod tests {
1168    use super::{now_timestamp_ms, ServerCapabilities};
1169
1170    #[test]
1171    fn test_stale_server_capabilities() {
1172        let mut caps = ServerCapabilities {
1173            versions: Default::default(),
1174            unstable_features: Default::default(),
1175            last_fetch_ts: now_timestamp_ms() - ServerCapabilities::STALE_THRESHOLD - 1.0,
1176        };
1177
1178        assert!(caps.maybe_decode().is_none());
1180
1181        caps.last_fetch_ts = now_timestamp_ms() - 1.0;
1183        assert!(caps.maybe_decode().is_some());
1184    }
1185}