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}