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::{
28 client::discovery::discover_homeserver::{
29 self, HomeserverInfo, IdentityServerInfo, RtcFocusInfo, TileServerInfo,
30 },
31 SupportedVersions,
32 },
33 events::{
34 presence::PresenceEvent,
35 receipt::{Receipt, ReceiptThread, ReceiptType},
36 AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, EmptyStateKey, GlobalAccountDataEvent,
37 GlobalAccountDataEventContent, GlobalAccountDataEventType, RedactContent,
38 RedactedStateEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
39 RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
40 },
41 serde::Raw,
42 time::SystemTime,
43 EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedRoomId,
44 OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId,
45};
46use serde::{Deserialize, Serialize};
47
48use super::{
49 send_queue::SentRequestKey, ChildTransactionId, DependentQueuedRequest,
50 DependentQueuedRequestKind, QueueWedgeError, QueuedRequest, QueuedRequestKind,
51 RoomLoadSettings, StateChanges, StoreError,
52};
53use crate::{
54 deserialized_responses::{
55 DisplayName, RawAnySyncOrStrippedState, RawMemberEvent, RawSyncOrStrippedState,
56 },
57 MinimalRoomMemberEvent, RoomInfo, RoomMemberships,
58};
59
60#[cfg_attr(target_family = "wasm", async_trait(?Send))]
63#[cfg_attr(not(target_family = "wasm"), async_trait)]
64pub trait StateStore: AsyncTraitDeps {
65 type Error: fmt::Debug + Into<StoreError> + From<serde_json::Error>;
67
68 async fn get_kv_data(
74 &self,
75 key: StateStoreDataKey<'_>,
76 ) -> Result<Option<StateStoreDataValue>, Self::Error>;
77
78 async fn set_kv_data(
88 &self,
89 key: StateStoreDataKey<'_>,
90 value: StateStoreDataValue,
91 ) -> Result<(), Self::Error>;
92
93 async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error>;
99
100 async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error>;
102
103 async fn get_presence_event(
110 &self,
111 user_id: &UserId,
112 ) -> Result<Option<Raw<PresenceEvent>>, Self::Error>;
113
114 async fn get_presence_events(
120 &self,
121 user_ids: &[OwnedUserId],
122 ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error>;
123
124 async fn get_state_event(
132 &self,
133 room_id: &RoomId,
134 event_type: StateEventType,
135 state_key: &str,
136 ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error>;
137
138 async fn get_state_events(
146 &self,
147 room_id: &RoomId,
148 event_type: StateEventType,
149 ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
150
151 async fn get_state_events_for_keys(
162 &self,
163 room_id: &RoomId,
164 event_type: StateEventType,
165 state_keys: &[&str],
166 ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
167
168 async fn get_profile(
176 &self,
177 room_id: &RoomId,
178 user_id: &UserId,
179 ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error>;
180
181 async fn get_profiles<'a>(
189 &self,
190 room_id: &RoomId,
191 user_ids: &'a [OwnedUserId],
192 ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error>;
193
194 async fn get_user_ids(
197 &self,
198 room_id: &RoomId,
199 memberships: RoomMemberships,
200 ) -> Result<Vec<OwnedUserId>, Self::Error>;
201
202 async fn get_room_infos(
204 &self,
205 room_load_settings: &RoomLoadSettings,
206 ) -> Result<Vec<RoomInfo>, Self::Error>;
207
208 async fn get_users_with_display_name(
217 &self,
218 room_id: &RoomId,
219 display_name: &DisplayName,
220 ) -> Result<BTreeSet<OwnedUserId>, Self::Error>;
221
222 async fn get_users_with_display_names<'a>(
230 &self,
231 room_id: &RoomId,
232 display_names: &'a [DisplayName],
233 ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error>;
234
235 async fn get_account_data_event(
241 &self,
242 event_type: GlobalAccountDataEventType,
243 ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error>;
244
245 async fn get_room_account_data_event(
255 &self,
256 room_id: &RoomId,
257 event_type: RoomAccountDataEventType,
258 ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error>;
259
260 async fn get_user_room_receipt_event(
273 &self,
274 room_id: &RoomId,
275 receipt_type: ReceiptType,
276 thread: ReceiptThread,
277 user_id: &UserId,
278 ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error>;
279
280 async fn get_event_room_receipt_events(
294 &self,
295 room_id: &RoomId,
296 receipt_type: ReceiptType,
297 thread: ReceiptThread,
298 event_id: &EventId,
299 ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error>;
300
301 async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
307
308 async fn set_custom_value(
317 &self,
318 key: &[u8],
319 value: Vec<u8>,
320 ) -> Result<Option<Vec<u8>>, Self::Error>;
321
322 async fn set_custom_value_no_read(
336 &self,
337 key: &[u8],
338 value: Vec<u8>,
339 ) -> Result<(), Self::Error> {
340 self.set_custom_value(key, value).await.map(|_| ())
341 }
342
343 async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error>;
349
350 async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error>;
356
357 async fn save_send_queue_request(
367 &self,
368 room_id: &RoomId,
369 transaction_id: OwnedTransactionId,
370 created_at: MilliSecondsSinceUnixEpoch,
371 request: QueuedRequestKind,
372 priority: usize,
373 ) -> Result<(), Self::Error>;
374
375 async fn update_send_queue_request(
387 &self,
388 room_id: &RoomId,
389 transaction_id: &TransactionId,
390 content: QueuedRequestKind,
391 ) -> Result<bool, Self::Error>;
392
393 async fn remove_send_queue_request(
399 &self,
400 room_id: &RoomId,
401 transaction_id: &TransactionId,
402 ) -> Result<bool, Self::Error>;
403
404 async fn load_send_queue_requests(
410 &self,
411 room_id: &RoomId,
412 ) -> Result<Vec<QueuedRequest>, Self::Error>;
413
414 async fn update_send_queue_request_status(
417 &self,
418 room_id: &RoomId,
419 transaction_id: &TransactionId,
420 error: Option<QueueWedgeError>,
421 ) -> Result<(), Self::Error>;
422
423 async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error>;
425
426 async fn save_dependent_queued_request(
429 &self,
430 room_id: &RoomId,
431 parent_txn_id: &TransactionId,
432 own_txn_id: ChildTransactionId,
433 created_at: MilliSecondsSinceUnixEpoch,
434 content: DependentQueuedRequestKind,
435 ) -> Result<(), Self::Error>;
436
437 async fn mark_dependent_queued_requests_as_ready(
446 &self,
447 room_id: &RoomId,
448 parent_txn_id: &TransactionId,
449 sent_parent_key: SentRequestKey,
450 ) -> Result<usize, Self::Error>;
451
452 async fn update_dependent_queued_request(
456 &self,
457 room_id: &RoomId,
458 own_transaction_id: &ChildTransactionId,
459 new_content: DependentQueuedRequestKind,
460 ) -> Result<bool, Self::Error>;
461
462 async fn remove_dependent_queued_request(
467 &self,
468 room: &RoomId,
469 own_txn_id: &ChildTransactionId,
470 ) -> Result<bool, Self::Error>;
471
472 async fn load_dependent_queued_requests(
478 &self,
479 room: &RoomId,
480 ) -> Result<Vec<DependentQueuedRequest>, Self::Error>;
481}
482
483#[repr(transparent)]
484struct EraseStateStoreError<T>(T);
485
486#[cfg(not(tarpaulin_include))]
487impl<T: fmt::Debug> fmt::Debug for EraseStateStoreError<T> {
488 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489 self.0.fmt(f)
490 }
491}
492
493#[cfg_attr(target_family = "wasm", async_trait(?Send))]
494#[cfg_attr(not(target_family = "wasm"), async_trait)]
495impl<T: StateStore> StateStore for EraseStateStoreError<T> {
496 type Error = StoreError;
497
498 async fn get_kv_data(
499 &self,
500 key: StateStoreDataKey<'_>,
501 ) -> Result<Option<StateStoreDataValue>, Self::Error> {
502 self.0.get_kv_data(key).await.map_err(Into::into)
503 }
504
505 async fn set_kv_data(
506 &self,
507 key: StateStoreDataKey<'_>,
508 value: StateStoreDataValue,
509 ) -> Result<(), Self::Error> {
510 self.0.set_kv_data(key, value).await.map_err(Into::into)
511 }
512
513 async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<(), Self::Error> {
514 self.0.remove_kv_data(key).await.map_err(Into::into)
515 }
516
517 async fn save_changes(&self, changes: &StateChanges) -> Result<(), Self::Error> {
518 self.0.save_changes(changes).await.map_err(Into::into)
519 }
520
521 async fn get_presence_event(
522 &self,
523 user_id: &UserId,
524 ) -> Result<Option<Raw<PresenceEvent>>, Self::Error> {
525 self.0.get_presence_event(user_id).await.map_err(Into::into)
526 }
527
528 async fn get_presence_events(
529 &self,
530 user_ids: &[OwnedUserId],
531 ) -> Result<Vec<Raw<PresenceEvent>>, Self::Error> {
532 self.0.get_presence_events(user_ids).await.map_err(Into::into)
533 }
534
535 async fn get_state_event(
536 &self,
537 room_id: &RoomId,
538 event_type: StateEventType,
539 state_key: &str,
540 ) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
541 self.0.get_state_event(room_id, event_type, state_key).await.map_err(Into::into)
542 }
543
544 async fn get_state_events(
545 &self,
546 room_id: &RoomId,
547 event_type: StateEventType,
548 ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
549 self.0.get_state_events(room_id, event_type).await.map_err(Into::into)
550 }
551
552 async fn get_state_events_for_keys(
553 &self,
554 room_id: &RoomId,
555 event_type: StateEventType,
556 state_keys: &[&str],
557 ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
558 self.0.get_state_events_for_keys(room_id, event_type, state_keys).await.map_err(Into::into)
559 }
560
561 async fn get_profile(
562 &self,
563 room_id: &RoomId,
564 user_id: &UserId,
565 ) -> Result<Option<MinimalRoomMemberEvent>, Self::Error> {
566 self.0.get_profile(room_id, user_id).await.map_err(Into::into)
567 }
568
569 async fn get_profiles<'a>(
570 &self,
571 room_id: &RoomId,
572 user_ids: &'a [OwnedUserId],
573 ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>, Self::Error> {
574 self.0.get_profiles(room_id, user_ids).await.map_err(Into::into)
575 }
576
577 async fn get_user_ids(
578 &self,
579 room_id: &RoomId,
580 memberships: RoomMemberships,
581 ) -> Result<Vec<OwnedUserId>, Self::Error> {
582 self.0.get_user_ids(room_id, memberships).await.map_err(Into::into)
583 }
584
585 async fn get_room_infos(
586 &self,
587 room_load_settings: &RoomLoadSettings,
588 ) -> Result<Vec<RoomInfo>, Self::Error> {
589 self.0.get_room_infos(room_load_settings).await.map_err(Into::into)
590 }
591
592 async fn get_users_with_display_name(
593 &self,
594 room_id: &RoomId,
595 display_name: &DisplayName,
596 ) -> Result<BTreeSet<OwnedUserId>, Self::Error> {
597 self.0.get_users_with_display_name(room_id, display_name).await.map_err(Into::into)
598 }
599
600 async fn get_users_with_display_names<'a>(
601 &self,
602 room_id: &RoomId,
603 display_names: &'a [DisplayName],
604 ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>, Self::Error> {
605 self.0.get_users_with_display_names(room_id, display_names).await.map_err(Into::into)
606 }
607
608 async fn get_account_data_event(
609 &self,
610 event_type: GlobalAccountDataEventType,
611 ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>, Self::Error> {
612 self.0.get_account_data_event(event_type).await.map_err(Into::into)
613 }
614
615 async fn get_room_account_data_event(
616 &self,
617 room_id: &RoomId,
618 event_type: RoomAccountDataEventType,
619 ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>, Self::Error> {
620 self.0.get_room_account_data_event(room_id, event_type).await.map_err(Into::into)
621 }
622
623 async fn get_user_room_receipt_event(
624 &self,
625 room_id: &RoomId,
626 receipt_type: ReceiptType,
627 thread: ReceiptThread,
628 user_id: &UserId,
629 ) -> Result<Option<(OwnedEventId, Receipt)>, Self::Error> {
630 self.0
631 .get_user_room_receipt_event(room_id, receipt_type, thread, user_id)
632 .await
633 .map_err(Into::into)
634 }
635
636 async fn get_event_room_receipt_events(
637 &self,
638 room_id: &RoomId,
639 receipt_type: ReceiptType,
640 thread: ReceiptThread,
641 event_id: &EventId,
642 ) -> Result<Vec<(OwnedUserId, Receipt)>, Self::Error> {
643 self.0
644 .get_event_room_receipt_events(room_id, receipt_type, thread, event_id)
645 .await
646 .map_err(Into::into)
647 }
648
649 async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
650 self.0.get_custom_value(key).await.map_err(Into::into)
651 }
652
653 async fn set_custom_value(
654 &self,
655 key: &[u8],
656 value: Vec<u8>,
657 ) -> Result<Option<Vec<u8>>, Self::Error> {
658 self.0.set_custom_value(key, value).await.map_err(Into::into)
659 }
660
661 async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
662 self.0.remove_custom_value(key).await.map_err(Into::into)
663 }
664
665 async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
666 self.0.remove_room(room_id).await.map_err(Into::into)
667 }
668
669 async fn save_send_queue_request(
670 &self,
671 room_id: &RoomId,
672 transaction_id: OwnedTransactionId,
673 created_at: MilliSecondsSinceUnixEpoch,
674 content: QueuedRequestKind,
675 priority: usize,
676 ) -> Result<(), Self::Error> {
677 self.0
678 .save_send_queue_request(room_id, transaction_id, created_at, content, priority)
679 .await
680 .map_err(Into::into)
681 }
682
683 async fn update_send_queue_request(
684 &self,
685 room_id: &RoomId,
686 transaction_id: &TransactionId,
687 content: QueuedRequestKind,
688 ) -> Result<bool, Self::Error> {
689 self.0.update_send_queue_request(room_id, transaction_id, content).await.map_err(Into::into)
690 }
691
692 async fn remove_send_queue_request(
693 &self,
694 room_id: &RoomId,
695 transaction_id: &TransactionId,
696 ) -> Result<bool, Self::Error> {
697 self.0.remove_send_queue_request(room_id, transaction_id).await.map_err(Into::into)
698 }
699
700 async fn load_send_queue_requests(
701 &self,
702 room_id: &RoomId,
703 ) -> Result<Vec<QueuedRequest>, Self::Error> {
704 self.0.load_send_queue_requests(room_id).await.map_err(Into::into)
705 }
706
707 async fn update_send_queue_request_status(
708 &self,
709 room_id: &RoomId,
710 transaction_id: &TransactionId,
711 error: Option<QueueWedgeError>,
712 ) -> Result<(), Self::Error> {
713 self.0
714 .update_send_queue_request_status(room_id, transaction_id, error)
715 .await
716 .map_err(Into::into)
717 }
718
719 async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
720 self.0.load_rooms_with_unsent_requests().await.map_err(Into::into)
721 }
722
723 async fn save_dependent_queued_request(
724 &self,
725 room_id: &RoomId,
726 parent_txn_id: &TransactionId,
727 own_txn_id: ChildTransactionId,
728 created_at: MilliSecondsSinceUnixEpoch,
729 content: DependentQueuedRequestKind,
730 ) -> Result<(), Self::Error> {
731 self.0
732 .save_dependent_queued_request(room_id, parent_txn_id, own_txn_id, created_at, content)
733 .await
734 .map_err(Into::into)
735 }
736
737 async fn mark_dependent_queued_requests_as_ready(
738 &self,
739 room_id: &RoomId,
740 parent_txn_id: &TransactionId,
741 sent_parent_key: SentRequestKey,
742 ) -> Result<usize, Self::Error> {
743 self.0
744 .mark_dependent_queued_requests_as_ready(room_id, parent_txn_id, sent_parent_key)
745 .await
746 .map_err(Into::into)
747 }
748
749 async fn remove_dependent_queued_request(
750 &self,
751 room_id: &RoomId,
752 own_txn_id: &ChildTransactionId,
753 ) -> Result<bool, Self::Error> {
754 self.0.remove_dependent_queued_request(room_id, own_txn_id).await.map_err(Into::into)
755 }
756
757 async fn load_dependent_queued_requests(
758 &self,
759 room_id: &RoomId,
760 ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
761 self.0.load_dependent_queued_requests(room_id).await.map_err(Into::into)
762 }
763
764 async fn update_dependent_queued_request(
765 &self,
766 room_id: &RoomId,
767 own_transaction_id: &ChildTransactionId,
768 new_content: DependentQueuedRequestKind,
769 ) -> Result<bool, Self::Error> {
770 self.0
771 .update_dependent_queued_request(room_id, own_transaction_id, new_content)
772 .await
773 .map_err(Into::into)
774 }
775}
776
777#[cfg_attr(target_family = "wasm", async_trait(?Send))]
779#[cfg_attr(not(target_family = "wasm"), async_trait)]
780pub trait StateStoreExt: StateStore {
781 async fn get_state_event_static<C>(
787 &self,
788 room_id: &RoomId,
789 ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
790 where
791 C: StaticEventContent + StaticStateEventContent<StateKey = EmptyStateKey> + RedactContent,
792 C::Redacted: RedactedStateEventContent,
793 {
794 Ok(self.get_state_event(room_id, C::TYPE.into(), "").await?.map(|raw| raw.cast()))
795 }
796
797 async fn get_state_event_static_for_key<C, K>(
803 &self,
804 room_id: &RoomId,
805 state_key: &K,
806 ) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
807 where
808 C: StaticEventContent + StaticStateEventContent + RedactContent,
809 C::StateKey: Borrow<K>,
810 C::Redacted: RedactedStateEventContent,
811 K: AsRef<str> + ?Sized + Sync,
812 {
813 Ok(self
814 .get_state_event(room_id, C::TYPE.into(), state_key.as_ref())
815 .await?
816 .map(|raw| raw.cast()))
817 }
818
819 async fn get_state_events_static<C>(
825 &self,
826 room_id: &RoomId,
827 ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
828 where
829 C: StaticEventContent + StaticStateEventContent + RedactContent,
830 C::Redacted: RedactedStateEventContent,
831 {
832 Ok(self
834 .get_state_events(room_id, C::TYPE.into())
835 .await?
836 .into_iter()
837 .map(|raw| raw.cast())
838 .collect())
839 }
840
841 async fn get_state_events_for_keys_static<'a, C, K, I>(
850 &self,
851 room_id: &RoomId,
852 state_keys: I,
853 ) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
854 where
855 C: StaticEventContent + StaticStateEventContent + RedactContent,
856 C::StateKey: Borrow<K>,
857 C::Redacted: RedactedStateEventContent,
858 K: AsRef<str> + Sized + Sync + 'a,
859 I: IntoIterator<Item = &'a K> + Send,
860 I::IntoIter: Send,
861 {
862 Ok(self
863 .get_state_events_for_keys(
864 room_id,
865 C::TYPE.into(),
866 &state_keys.into_iter().map(|k| k.as_ref()).collect::<Vec<_>>(),
867 )
868 .await?
869 .into_iter()
870 .map(|raw| raw.cast())
871 .collect())
872 }
873
874 async fn get_account_data_event_static<C>(
876 &self,
877 ) -> Result<Option<Raw<GlobalAccountDataEvent<C>>>, Self::Error>
878 where
879 C: StaticEventContent + GlobalAccountDataEventContent,
880 {
881 Ok(self.get_account_data_event(C::TYPE.into()).await?.map(Raw::cast))
882 }
883
884 async fn get_room_account_data_event_static<C>(
892 &self,
893 room_id: &RoomId,
894 ) -> Result<Option<Raw<RoomAccountDataEvent<C>>>, Self::Error>
895 where
896 C: StaticEventContent + RoomAccountDataEventContent,
897 {
898 Ok(self.get_room_account_data_event(room_id, C::TYPE.into()).await?.map(Raw::cast))
899 }
900
901 async fn get_member_event(
909 &self,
910 room_id: &RoomId,
911 state_key: &UserId,
912 ) -> Result<Option<RawMemberEvent>, Self::Error> {
913 self.get_state_event_static_for_key(room_id, state_key).await
914 }
915}
916
917#[cfg_attr(target_family = "wasm", async_trait(?Send))]
918#[cfg_attr(not(target_family = "wasm"), async_trait)]
919impl<T: StateStore + ?Sized> StateStoreExt for T {}
920
921pub type DynStateStore = dyn StateStore<Error = StoreError>;
923
924pub trait IntoStateStore {
930 #[doc(hidden)]
931 fn into_state_store(self) -> Arc<DynStateStore>;
932}
933
934impl<T> IntoStateStore for T
935where
936 T: StateStore + Sized + 'static,
937{
938 fn into_state_store(self) -> Arc<DynStateStore> {
939 Arc::new(EraseStateStoreError(self))
940 }
941}
942
943impl<T> IntoStateStore for Arc<T>
946where
947 T: StateStore + 'static,
948{
949 fn into_state_store(self) -> Arc<DynStateStore> {
950 let ptr: *const T = Arc::into_raw(self);
951 let ptr_erased = ptr as *const EraseStateStoreError<T>;
952 unsafe { Arc::from_raw(ptr_erased) }
955 }
956}
957
958#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
961pub struct ServerInfo {
962 pub versions: Vec<String>,
964
965 pub unstable_features: BTreeMap<String, bool>,
967
968 #[serde(skip_serializing_if = "Option::is_none")]
970 pub well_known: Option<WellKnownResponse>,
971
972 last_fetch_ts: f64,
975}
976
977impl ServerInfo {
978 pub const STALE_THRESHOLD: f64 = (1000 * 60 * 60 * 24 * 7) as _; pub fn new(
983 versions: Vec<String>,
984 unstable_features: BTreeMap<String, bool>,
985 well_known: Option<WellKnownResponse>,
986 ) -> Self {
987 Self { versions, unstable_features, well_known, last_fetch_ts: now_timestamp_ms() }
988 }
989
990 pub fn maybe_decode(&self) -> Option<Self> {
996 if now_timestamp_ms() - self.last_fetch_ts >= Self::STALE_THRESHOLD {
997 None
998 } else {
999 Some(self.clone())
1000 }
1001 }
1002
1003 pub fn supported_versions(&self) -> SupportedVersions {
1009 SupportedVersions::from_parts(&self.versions, &self.unstable_features)
1010 }
1011}
1012
1013#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1014pub struct WellKnownResponse {
1016 pub homeserver: HomeserverInfo,
1018
1019 pub identity_server: Option<IdentityServerInfo>,
1021
1022 pub tile_server: Option<TileServerInfo>,
1024
1025 pub rtc_foci: Vec<RtcFocusInfo>,
1027}
1028
1029impl From<discover_homeserver::Response> for WellKnownResponse {
1030 fn from(response: discover_homeserver::Response) -> Self {
1031 Self {
1032 homeserver: response.homeserver,
1033 identity_server: response.identity_server,
1034 tile_server: response.tile_server,
1035 rtc_foci: response.rtc_foci,
1036 }
1037 }
1038}
1039
1040fn now_timestamp_ms() -> f64 {
1042 SystemTime::now()
1043 .duration_since(SystemTime::UNIX_EPOCH)
1044 .expect("System clock was before 1970.")
1045 .as_secs_f64()
1046 * 1000.0
1047}
1048
1049#[derive(Debug, Clone)]
1051pub enum StateStoreDataValue {
1052 SyncToken(String),
1054
1055 ServerInfo(ServerInfo),
1057
1058 Filter(String),
1060
1061 UserAvatarUrl(OwnedMxcUri),
1063
1064 RecentlyVisitedRooms(Vec<OwnedRoomId>),
1066
1067 UtdHookManagerData(GrowableBloom),
1070
1071 ComposerDraft(ComposerDraft),
1076
1077 SeenKnockRequests(BTreeMap<OwnedEventId, OwnedUserId>),
1079}
1080
1081#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1083pub struct ComposerDraft {
1084 pub plain_text: String,
1086 pub html_text: Option<String>,
1089 pub draft_type: ComposerDraftType,
1091}
1092
1093#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1095pub enum ComposerDraftType {
1096 NewMessage,
1098 Reply {
1100 event_id: OwnedEventId,
1102 },
1103 Edit {
1105 event_id: OwnedEventId,
1107 },
1108}
1109
1110impl StateStoreDataValue {
1111 pub fn into_sync_token(self) -> Option<String> {
1113 as_variant!(self, Self::SyncToken)
1114 }
1115
1116 pub fn into_filter(self) -> Option<String> {
1118 as_variant!(self, Self::Filter)
1119 }
1120
1121 pub fn into_user_avatar_url(self) -> Option<OwnedMxcUri> {
1123 as_variant!(self, Self::UserAvatarUrl)
1124 }
1125
1126 pub fn into_recently_visited_rooms(self) -> Option<Vec<OwnedRoomId>> {
1128 as_variant!(self, Self::RecentlyVisitedRooms)
1129 }
1130
1131 pub fn into_utd_hook_manager_data(self) -> Option<GrowableBloom> {
1133 as_variant!(self, Self::UtdHookManagerData)
1134 }
1135
1136 pub fn into_composer_draft(self) -> Option<ComposerDraft> {
1138 as_variant!(self, Self::ComposerDraft)
1139 }
1140
1141 pub fn into_server_info(self) -> Option<ServerInfo> {
1143 as_variant!(self, Self::ServerInfo)
1144 }
1145
1146 pub fn into_seen_knock_requests(self) -> Option<BTreeMap<OwnedEventId, OwnedUserId>> {
1148 as_variant!(self, Self::SeenKnockRequests)
1149 }
1150}
1151
1152#[derive(Debug, Clone, Copy)]
1154pub enum StateStoreDataKey<'a> {
1155 SyncToken,
1157
1158 ServerInfo,
1160
1161 Filter(&'a str),
1163
1164 UserAvatarUrl(&'a UserId),
1166
1167 RecentlyVisitedRooms(&'a UserId),
1169
1170 UtdHookManagerData,
1173
1174 ComposerDraft(&'a RoomId, Option<&'a EventId>),
1179
1180 SeenKnockRequests(&'a RoomId),
1182}
1183
1184impl StateStoreDataKey<'_> {
1185 pub const SYNC_TOKEN: &'static str = "sync_token";
1187 pub const SERVER_INFO: &'static str = "server_capabilities"; pub const FILTER: &'static str = "filter";
1192 pub const USER_AVATAR_URL: &'static str = "user_avatar_url";
1195
1196 pub const RECENTLY_VISITED_ROOMS: &'static str = "recently_visited_rooms";
1199
1200 pub const UTD_HOOK_MANAGER_DATA: &'static str = "utd_hook_manager_data";
1203
1204 pub const COMPOSER_DRAFT: &'static str = "composer_draft";
1207
1208 pub const SEEN_KNOCK_REQUESTS: &'static str = "seen_knock_requests";
1211}
1212
1213#[cfg(test)]
1214mod tests {
1215 use super::{now_timestamp_ms, ServerInfo};
1216
1217 #[test]
1218 fn test_stale_server_info() {
1219 let mut server_info = ServerInfo {
1220 versions: Default::default(),
1221 unstable_features: Default::default(),
1222 well_known: Default::default(),
1223 last_fetch_ts: now_timestamp_ms() - ServerInfo::STALE_THRESHOLD - 1.0,
1224 };
1225
1226 assert!(server_info.maybe_decode().is_none());
1228
1229 server_info.last_fetch_ts = now_timestamp_ms() - 1.0;
1231 assert!(server_info.maybe_decode().is_some());
1232 }
1233}