1use std::{
16 cmp::Reverse,
17 collections::{BTreeMap, BTreeSet, HashMap},
18 sync::RwLock,
19};
20
21use async_trait::async_trait;
22use growable_bloom_filter::GrowableBloom;
23use matrix_sdk_common::{ROOM_VERSION_FALLBACK, ROOM_VERSION_RULES_FALLBACK, ttl::TtlValue};
24use ruma::{
25 CanonicalJsonObject, EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri,
26 OwnedRoomId, OwnedTransactionId, OwnedUserId, RoomId, TransactionId, UserId,
27 api::client::discovery::get_capabilities::v3::Capabilities,
28 canonical_json::{RedactedBecause, redact},
29 events::{
30 AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent,
31 AnySyncStateEvent, GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType,
32 presence::PresenceEvent,
33 receipt::{Receipt, ReceiptThread, ReceiptType},
34 room::member::{MembershipState, StrippedRoomMemberEvent, SyncRoomMemberEvent},
35 },
36 profile::{UserProfile, UserProfileUpdate},
37 serde::Raw,
38 time::Instant,
39};
40use tracing::{debug, instrument, warn};
41
42use super::{
43 DependentQueuedRequest, DependentQueuedRequestKind, QueuedRequestKind, Result, RoomInfo,
44 RoomLoadSettings, StateChanges, StateStore, StoreError, SupportedVersionsResponse,
45 WellKnownResponse,
46 send_queue::{ChildTransactionId, QueuedRequest, SentRequestKey},
47 traits::ComposerDraft,
48};
49use crate::{
50 MinimalRoomMemberEvent, RoomMemberships, StateStoreDataKey, StateStoreDataValue,
51 deserialized_responses::{DisplayName, RawAnySyncOrStrippedState},
52 store::{
53 QueueWedgeError, StoredThreadSubscription,
54 traits::{ThreadSubscriptionCatchupToken, compare_thread_subscription_bump_stamps},
55 },
56};
57
58#[derive(Debug, Default)]
59#[allow(clippy::type_complexity)]
60struct MemoryStoreInner {
61 recently_visited_rooms: HashMap<OwnedUserId, Vec<OwnedRoomId>>,
62 composer_drafts: HashMap<(OwnedRoomId, Option<OwnedEventId>), ComposerDraft>,
63 user_avatar_url: HashMap<OwnedUserId, OwnedMxcUri>,
64 sync_token: Option<String>,
65 supported_versions: Option<TtlValue<SupportedVersionsResponse>>,
66 well_known: Option<TtlValue<Option<WellKnownResponse>>>,
67 filters: HashMap<String, String>,
68 utd_hook_manager_data: Option<GrowableBloom>,
69 one_time_key_uploaded_error: bool,
70 account_data: HashMap<GlobalAccountDataEventType, Raw<AnyGlobalAccountDataEvent>>,
71 profiles: HashMap<OwnedRoomId, HashMap<OwnedUserId, MinimalRoomMemberEvent>>,
72 display_names: HashMap<OwnedRoomId, HashMap<DisplayName, BTreeSet<OwnedUserId>>>,
73 members: HashMap<OwnedRoomId, HashMap<OwnedUserId, MembershipState>>,
74 room_info: HashMap<OwnedRoomId, RoomInfo>,
75 room_state:
76 HashMap<OwnedRoomId, HashMap<StateEventType, HashMap<String, Raw<AnySyncStateEvent>>>>,
77 room_account_data:
78 HashMap<OwnedRoomId, HashMap<RoomAccountDataEventType, Raw<AnyRoomAccountDataEvent>>>,
79 stripped_room_state:
80 HashMap<OwnedRoomId, HashMap<StateEventType, HashMap<String, Raw<AnyStrippedStateEvent>>>>,
81 stripped_members: HashMap<OwnedRoomId, HashMap<OwnedUserId, MembershipState>>,
82 presence: HashMap<OwnedUserId, Raw<PresenceEvent>>,
83 room_user_receipts: HashMap<
84 OwnedRoomId,
85 HashMap<(String, Option<String>), HashMap<OwnedUserId, (OwnedEventId, Receipt)>>,
86 >,
87 room_event_receipts: HashMap<
88 OwnedRoomId,
89 HashMap<(String, Option<String>), HashMap<OwnedEventId, HashMap<OwnedUserId, Receipt>>>,
90 >,
91 custom: HashMap<Vec<u8>, Vec<u8>>,
92 send_queue_events: BTreeMap<OwnedRoomId, Vec<QueuedRequest>>,
93 dependent_send_queue_events: BTreeMap<OwnedRoomId, Vec<DependentQueuedRequest>>,
94 seen_knock_requests: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, OwnedUserId>>,
95 thread_subscriptions: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, StoredThreadSubscription>>,
96 thread_subscriptions_catchup_tokens: Option<Vec<ThreadSubscriptionCatchupToken>>,
97 global_profiles: HashMap<OwnedUserId, UserProfile>,
98 homeserver_capabilities: Option<TtlValue<Capabilities>>,
99}
100
101#[derive(Debug, Default)]
105pub struct MemoryStore {
106 inner: RwLock<MemoryStoreInner>,
107}
108
109impl MemoryStore {
110 pub fn new() -> Self {
112 Self::default()
113 }
114
115 fn get_user_room_receipt_event_impl(
116 &self,
117 room_id: &RoomId,
118 receipt_type: ReceiptType,
119 receipt_thread: &ReceiptThread,
120 user_id: &UserId,
121 ) -> Option<(OwnedEventId, Receipt)> {
122 self.inner
123 .read()
124 .unwrap()
125 .room_user_receipts
126 .get(room_id)?
127 .get(&(receipt_type.to_string(), receipt_thread.as_str().map(ToOwned::to_owned)))?
128 .get(user_id)
129 .cloned()
130 }
131
132 fn get_event_room_receipt_events_impl(
133 &self,
134 room_id: &RoomId,
135 receipt_type: ReceiptType,
136 receipt_thread: &ReceiptThread,
137 event_id: &EventId,
138 ) -> Option<Vec<(OwnedUserId, Receipt)>> {
139 Some(
140 self.inner
141 .read()
142 .unwrap()
143 .room_event_receipts
144 .get(room_id)?
145 .get(&(receipt_type.to_string(), receipt_thread.as_str().map(ToOwned::to_owned)))?
146 .get(event_id)?
147 .iter()
148 .map(|(key, value)| (key.clone(), value.clone()))
149 .collect(),
150 )
151 }
152}
153
154#[cfg_attr(target_family = "wasm", async_trait(?Send))]
155#[cfg_attr(not(target_family = "wasm"), async_trait)]
156impl StateStore for MemoryStore {
157 type Error = StoreError;
158
159 async fn close(&self) -> Result<(), Self::Error> {
160 Ok(())
161 }
162
163 async fn reopen(&self) -> Result<(), Self::Error> {
164 Ok(())
165 }
166
167 async fn get_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<Option<StateStoreDataValue>> {
168 let inner = self.inner.read().unwrap();
169
170 Ok(match key {
171 StateStoreDataKey::SyncToken => {
172 inner.sync_token.clone().map(StateStoreDataValue::SyncToken)
173 }
174 StateStoreDataKey::SupportedVersions => {
175 inner.supported_versions.clone().map(StateStoreDataValue::SupportedVersions)
176 }
177 StateStoreDataKey::WellKnown => {
178 inner.well_known.clone().map(StateStoreDataValue::WellKnown)
179 }
180 StateStoreDataKey::Filter(filter_name) => {
181 inner.filters.get(filter_name).cloned().map(StateStoreDataValue::Filter)
182 }
183 StateStoreDataKey::UserAvatarUrl(user_id) => {
184 inner.user_avatar_url.get(user_id).cloned().map(StateStoreDataValue::UserAvatarUrl)
185 }
186 StateStoreDataKey::RecentlyVisitedRooms(user_id) => inner
187 .recently_visited_rooms
188 .get(user_id)
189 .cloned()
190 .map(StateStoreDataValue::RecentlyVisitedRooms),
191 StateStoreDataKey::UtdHookManagerData => {
192 inner.utd_hook_manager_data.clone().map(StateStoreDataValue::UtdHookManagerData)
193 }
194 StateStoreDataKey::OneTimeKeyAlreadyUploaded => inner
195 .one_time_key_uploaded_error
196 .then_some(StateStoreDataValue::OneTimeKeyAlreadyUploaded),
197 StateStoreDataKey::ComposerDraft(room_id, thread_root) => {
198 let key = (room_id.to_owned(), thread_root.map(ToOwned::to_owned));
199 inner.composer_drafts.get(&key).cloned().map(StateStoreDataValue::ComposerDraft)
200 }
201 StateStoreDataKey::SeenKnockRequests(room_id) => inner
202 .seen_knock_requests
203 .get(room_id)
204 .cloned()
205 .map(StateStoreDataValue::SeenKnockRequests),
206 StateStoreDataKey::ThreadSubscriptionsCatchupTokens => inner
207 .thread_subscriptions_catchup_tokens
208 .clone()
209 .map(StateStoreDataValue::ThreadSubscriptionsCatchupTokens),
210 StateStoreDataKey::HomeserverCapabilities => inner
211 .homeserver_capabilities
212 .clone()
213 .map(StateStoreDataValue::HomeserverCapabilities),
214 })
215 }
216
217 async fn set_kv_data(
218 &self,
219 key: StateStoreDataKey<'_>,
220 value: StateStoreDataValue,
221 ) -> Result<()> {
222 let mut inner = self.inner.write().unwrap();
223 match key {
224 StateStoreDataKey::SyncToken => {
225 inner.sync_token =
226 Some(value.into_sync_token().expect("Session data not a sync token"))
227 }
228 StateStoreDataKey::Filter(filter_name) => {
229 inner.filters.insert(
230 filter_name.to_owned(),
231 value.into_filter().expect("Session data not a filter"),
232 );
233 }
234 StateStoreDataKey::UserAvatarUrl(user_id) => {
235 inner.user_avatar_url.insert(
236 user_id.to_owned(),
237 value.into_user_avatar_url().expect("Session data not a user avatar url"),
238 );
239 }
240 StateStoreDataKey::RecentlyVisitedRooms(user_id) => {
241 inner.recently_visited_rooms.insert(
242 user_id.to_owned(),
243 value
244 .into_recently_visited_rooms()
245 .expect("Session data not a list of recently visited rooms"),
246 );
247 }
248 StateStoreDataKey::UtdHookManagerData => {
249 inner.utd_hook_manager_data = Some(
250 value
251 .into_utd_hook_manager_data()
252 .expect("Session data not the hook manager data"),
253 );
254 }
255 StateStoreDataKey::OneTimeKeyAlreadyUploaded => {
256 inner.one_time_key_uploaded_error = true;
257 }
258 StateStoreDataKey::ComposerDraft(room_id, thread_root) => {
259 inner.composer_drafts.insert(
260 (room_id.to_owned(), thread_root.map(ToOwned::to_owned)),
261 value.into_composer_draft().expect("Session data not a composer draft"),
262 );
263 }
264 StateStoreDataKey::SupportedVersions => {
265 inner.supported_versions = Some(
266 value
267 .into_supported_versions()
268 .expect("Session data not containing supported versions"),
269 );
270 }
271 StateStoreDataKey::WellKnown => {
272 inner.well_known =
273 Some(value.into_well_known().expect("Session data not containing well-known"));
274 }
275 StateStoreDataKey::SeenKnockRequests(room_id) => {
276 inner.seen_knock_requests.insert(
277 room_id.to_owned(),
278 value
279 .into_seen_knock_requests()
280 .expect("Session data is not a set of seen join request ids"),
281 );
282 }
283 StateStoreDataKey::ThreadSubscriptionsCatchupTokens => {
284 inner.thread_subscriptions_catchup_tokens =
285 Some(value.into_thread_subscriptions_catchup_tokens().expect(
286 "Session data is not a list of thread subscription catchup tokens",
287 ));
288 }
289 StateStoreDataKey::HomeserverCapabilities => {
290 inner.homeserver_capabilities = Some(
291 value
292 .into_homeserver_capabilities()
293 .expect("Session data is not a homeserver capabilities"),
294 );
295 }
296 }
297
298 Ok(())
299 }
300
301 async fn remove_kv_data(&self, key: StateStoreDataKey<'_>) -> Result<()> {
302 let mut inner = self.inner.write().unwrap();
303 match key {
304 StateStoreDataKey::SyncToken => inner.sync_token = None,
305 StateStoreDataKey::SupportedVersions => inner.supported_versions = None,
306 StateStoreDataKey::WellKnown => inner.well_known = None,
307 StateStoreDataKey::Filter(filter_name) => {
308 inner.filters.remove(filter_name);
309 }
310 StateStoreDataKey::UserAvatarUrl(user_id) => {
311 inner.user_avatar_url.remove(user_id);
312 }
313 StateStoreDataKey::RecentlyVisitedRooms(user_id) => {
314 inner.recently_visited_rooms.remove(user_id);
315 }
316 StateStoreDataKey::UtdHookManagerData => inner.utd_hook_manager_data = None,
317 StateStoreDataKey::OneTimeKeyAlreadyUploaded => {
318 inner.one_time_key_uploaded_error = false
319 }
320 StateStoreDataKey::ComposerDraft(room_id, thread_root) => {
321 let key = (room_id.to_owned(), thread_root.map(ToOwned::to_owned));
322 inner.composer_drafts.remove(&key);
323 }
324 StateStoreDataKey::SeenKnockRequests(room_id) => {
325 inner.seen_knock_requests.remove(room_id);
326 }
327 StateStoreDataKey::ThreadSubscriptionsCatchupTokens => {
328 inner.thread_subscriptions_catchup_tokens = None;
329 }
330 StateStoreDataKey::HomeserverCapabilities => inner.homeserver_capabilities = None,
331 }
332 Ok(())
333 }
334
335 #[instrument(skip(self, changes))]
336 async fn save_changes(&self, changes: &StateChanges) -> Result<()> {
337 let now = Instant::now();
338
339 let mut inner = self.inner.write().unwrap();
340
341 if let Some(s) = &changes.sync_token {
342 inner.sync_token = Some(s.to_owned());
343 }
344
345 for (room, users) in &changes.profiles_to_delete {
346 let Some(room_profiles) = inner.profiles.get_mut(room) else {
347 continue;
348 };
349 for user in users {
350 room_profiles.remove(user);
351 }
352 }
353
354 for (room, users) in &changes.profiles {
355 for (user_id, profile) in users {
356 inner
357 .profiles
358 .entry(room.clone())
359 .or_default()
360 .insert(user_id.clone(), profile.clone());
361 }
362 }
363
364 for (room, map) in &changes.ambiguity_maps {
365 for (display_name, display_names) in map {
366 inner
367 .display_names
368 .entry(room.clone())
369 .or_default()
370 .insert(display_name.clone(), display_names.clone());
371 }
372 }
373
374 for (event_type, event) in &changes.account_data {
375 inner.account_data.insert(event_type.clone(), event.clone());
376 }
377
378 for (room, events) in &changes.room_account_data {
379 for (event_type, event) in events {
380 inner
381 .room_account_data
382 .entry(room.clone())
383 .or_default()
384 .insert(event_type.clone(), event.clone());
385 }
386 }
387
388 for (room, event_types) in &changes.state {
389 for (event_type, events) in event_types {
390 for (state_key, raw_event) in events {
391 inner
392 .room_state
393 .entry(room.clone())
394 .or_default()
395 .entry(event_type.clone())
396 .or_default()
397 .insert(state_key.to_owned(), raw_event.clone());
398 inner.stripped_room_state.remove(room);
399
400 if *event_type == StateEventType::RoomMember {
401 let event =
402 match raw_event.deserialize_as_unchecked::<SyncRoomMemberEvent>() {
403 Ok(ev) => ev,
404 Err(e) => {
405 let event_id: Option<String> =
406 raw_event.get_field("event_id").ok().flatten();
407 debug!(event_id, "Failed to deserialize member event: {e}");
408 continue;
409 }
410 };
411
412 inner.stripped_members.remove(room);
413
414 inner
415 .members
416 .entry(room.clone())
417 .or_default()
418 .insert(event.state_key().to_owned(), event.membership().clone());
419 }
420 }
421 }
422 }
423
424 for (room_id, info) in &changes.room_infos {
425 inner.room_info.insert(room_id.clone(), info.clone());
426 }
427
428 for (sender, event) in &changes.presence {
429 inner.presence.insert(sender.clone(), event.clone());
430 }
431
432 for (room, event_types) in &changes.stripped_state {
433 for (event_type, events) in event_types {
434 for (state_key, raw_event) in events {
435 inner
436 .stripped_room_state
437 .entry(room.clone())
438 .or_default()
439 .entry(event_type.clone())
440 .or_default()
441 .insert(state_key.to_owned(), raw_event.clone());
442
443 if *event_type == StateEventType::RoomMember {
444 let event =
445 match raw_event.deserialize_as_unchecked::<StrippedRoomMemberEvent>() {
446 Ok(ev) => ev,
447 Err(e) => {
448 let event_id: Option<String> =
449 raw_event.get_field("event_id").ok().flatten();
450 debug!(
451 event_id,
452 "Failed to deserialize stripped member event: {e}"
453 );
454 continue;
455 }
456 };
457
458 inner
459 .stripped_members
460 .entry(room.clone())
461 .or_default()
462 .insert(event.state_key, event.content.membership);
463 }
464 }
465 }
466 }
467
468 for (room, content) in &changes.receipts {
469 for (event_id, receipts) in &content.0 {
470 for (receipt_type, receipts) in receipts {
471 for (user_id, receipt) in receipts {
472 let thread = receipt.thread.as_str().map(ToOwned::to_owned);
473 if let Some((old_event, _)) = inner
475 .room_user_receipts
476 .entry(room.clone())
477 .or_default()
478 .entry((receipt_type.to_string(), thread.clone()))
479 .or_default()
480 .insert(user_id.clone(), (event_id.clone(), receipt.clone()))
481 {
482 if let Some(receipt_map) = inner.room_event_receipts.get_mut(room)
485 && let Some(event_map) =
486 receipt_map.get_mut(&(receipt_type.to_string(), thread.clone()))
487 && let Some(user_map) = event_map.get_mut(&old_event)
488 {
489 user_map.remove(user_id);
490 }
491 }
492
493 inner
495 .room_event_receipts
496 .entry(room.clone())
497 .or_default()
498 .entry((receipt_type.to_string(), thread))
499 .or_default()
500 .entry(event_id.clone())
501 .or_default()
502 .insert(user_id.clone(), receipt.clone());
503 }
504 }
505 }
506 }
507
508 let make_redaction_rules = |room_info: &HashMap<OwnedRoomId, RoomInfo>, room_id| {
509 room_info.get(room_id).map(|info| info.room_version_rules_or_default()).unwrap_or_else(|| {
510 warn!(
511 ?room_id,
512 "Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}"
513 );
514 ROOM_VERSION_RULES_FALLBACK
515 }).redaction
516 };
517
518 let inner = &mut *inner;
519 for (room_id, redactions) in &changes.redactions {
520 let mut redaction_rules = None;
521
522 if let Some(room) = inner.room_state.get_mut(room_id) {
523 for ref_room_mu in room.values_mut() {
524 for raw_evt in ref_room_mu.values_mut() {
525 if let Ok(Some(event_id)) = raw_evt.get_field::<OwnedEventId>("event_id")
526 && let Some(redaction) = redactions.get(&event_id)
527 {
528 let redacted = redact(
529 raw_evt.deserialize_as::<CanonicalJsonObject>()?,
530 redaction_rules.get_or_insert_with(|| {
531 make_redaction_rules(&inner.room_info, room_id)
532 }),
533 Some(RedactedBecause::from_raw_event(redaction)?),
534 )
535 .map_err(StoreError::Redaction)?;
536 *raw_evt = Raw::new(&redacted)?.cast_unchecked();
537 }
538 }
539 }
540 }
541 }
542
543 for (user_id, profile_update) in &changes.global_profiles {
544 match profile_update {
545 UserProfileUpdate::Updated(profile_changes) => {
546 inner
547 .global_profiles
548 .entry(user_id.clone())
549 .or_default()
550 .apply(profile_changes.clone());
551 }
552 UserProfileUpdate::Dropped => {
553 inner.global_profiles.remove(user_id);
554 }
555 _ => {
556 warn!(%user_id, "Unhandled UserProfileUpdate variant; ignoring");
557 }
558 }
559 }
560
561 debug!("Saved changes in {:?}", now.elapsed());
562
563 Ok(())
564 }
565
566 async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
567 Ok(self.inner.read().unwrap().presence.get(user_id).cloned())
568 }
569
570 async fn get_presence_events(
571 &self,
572 user_ids: &[OwnedUserId],
573 ) -> Result<Vec<Raw<PresenceEvent>>> {
574 let presence = &self.inner.read().unwrap().presence;
575 Ok(user_ids.iter().filter_map(|user_id| presence.get(user_id).cloned()).collect())
576 }
577
578 async fn get_state_event(
579 &self,
580 room_id: &RoomId,
581 event_type: StateEventType,
582 state_key: &str,
583 ) -> Result<Option<RawAnySyncOrStrippedState>> {
584 Ok(self
585 .get_state_events_for_keys(room_id, event_type, &[state_key])
586 .await?
587 .into_iter()
588 .next())
589 }
590
591 async fn get_state_events(
592 &self,
593 room_id: &RoomId,
594 event_type: StateEventType,
595 ) -> Result<Vec<RawAnySyncOrStrippedState>> {
596 fn get_events<T>(
597 state_map: &HashMap<OwnedRoomId, HashMap<StateEventType, HashMap<String, Raw<T>>>>,
598 room_id: &RoomId,
599 event_type: &StateEventType,
600 to_enum: fn(Raw<T>) -> RawAnySyncOrStrippedState,
601 ) -> Option<Vec<RawAnySyncOrStrippedState>> {
602 let state_events = state_map.get(room_id)?.get(event_type)?;
603 Some(state_events.values().cloned().map(to_enum).collect())
604 }
605
606 let inner = self.inner.read().unwrap();
607 Ok(get_events(
608 &inner.stripped_room_state,
609 room_id,
610 &event_type,
611 RawAnySyncOrStrippedState::Stripped,
612 )
613 .or_else(|| {
614 get_events(&inner.room_state, room_id, &event_type, RawAnySyncOrStrippedState::Sync)
615 })
616 .unwrap_or_default())
617 }
618
619 async fn get_state_events_for_keys(
620 &self,
621 room_id: &RoomId,
622 event_type: StateEventType,
623 state_keys: &[&str],
624 ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
625 let inner = self.inner.read().unwrap();
626
627 if let Some(stripped_state_events) =
628 inner.stripped_room_state.get(room_id).and_then(|events| events.get(&event_type))
629 {
630 Ok(state_keys
631 .iter()
632 .filter_map(|k| {
633 stripped_state_events
634 .get(*k)
635 .map(|e| RawAnySyncOrStrippedState::Stripped(e.clone()))
636 })
637 .collect())
638 } else if let Some(sync_state_events) =
639 inner.room_state.get(room_id).and_then(|events| events.get(&event_type))
640 {
641 Ok(state_keys
642 .iter()
643 .filter_map(|k| {
644 sync_state_events.get(*k).map(|e| RawAnySyncOrStrippedState::Sync(e.clone()))
645 })
646 .collect())
647 } else {
648 Ok(Vec::new())
649 }
650 }
651
652 async fn get_profile(
653 &self,
654 room_id: &RoomId,
655 user_id: &UserId,
656 ) -> Result<Option<MinimalRoomMemberEvent>> {
657 Ok(self
658 .inner
659 .read()
660 .unwrap()
661 .profiles
662 .get(room_id)
663 .and_then(|room_profiles| room_profiles.get(user_id))
664 .cloned())
665 }
666
667 async fn get_profiles<'a>(
668 &self,
669 room_id: &RoomId,
670 user_ids: &'a [OwnedUserId],
671 ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>> {
672 if user_ids.is_empty() {
673 return Ok(BTreeMap::new());
674 }
675
676 let profiles = &self.inner.read().unwrap().profiles;
677 let Some(room_profiles) = profiles.get(room_id) else {
678 return Ok(BTreeMap::new());
679 };
680
681 Ok(user_ids
682 .iter()
683 .filter_map(|user_id| room_profiles.get(user_id).map(|p| (&**user_id, p.clone())))
684 .collect())
685 }
686
687 #[instrument(skip(self, memberships))]
688 async fn get_user_ids(
689 &self,
690 room_id: &RoomId,
691 memberships: RoomMemberships,
692 ) -> Result<Vec<OwnedUserId>> {
693 fn get_user_ids_inner(
699 members: &HashMap<OwnedRoomId, HashMap<OwnedUserId, MembershipState>>,
700 room_id: &RoomId,
701 memberships: RoomMemberships,
702 ) -> Vec<OwnedUserId> {
703 members
704 .get(room_id)
705 .map(|members| {
706 members
707 .iter()
708 .filter_map(|(user_id, membership)| {
709 memberships.matches(membership).then_some(user_id)
710 })
711 .cloned()
712 .collect()
713 })
714 .unwrap_or_default()
715 }
716 let inner = self.inner.read().unwrap();
717 let v = get_user_ids_inner(&inner.stripped_members, room_id, memberships);
718 if !v.is_empty() {
719 return Ok(v);
720 }
721 Ok(get_user_ids_inner(&inner.members, room_id, memberships))
722 }
723
724 async fn get_room_infos(&self, room_load_settings: &RoomLoadSettings) -> Result<Vec<RoomInfo>> {
725 let memory_store_inner = self.inner.read().unwrap();
726 let room_infos = &memory_store_inner.room_info;
727
728 Ok(match room_load_settings {
729 RoomLoadSettings::All => room_infos.values().cloned().collect(),
730
731 RoomLoadSettings::One(room_id) => match room_infos.get(room_id) {
732 Some(room_info) => vec![room_info.clone()],
733 None => vec![],
734 },
735 })
736 }
737
738 async fn get_users_with_display_name(
739 &self,
740 room_id: &RoomId,
741 display_name: &DisplayName,
742 ) -> Result<BTreeSet<OwnedUserId>> {
743 Ok(self
744 .inner
745 .read()
746 .unwrap()
747 .display_names
748 .get(room_id)
749 .and_then(|room_names| room_names.get(display_name).cloned())
750 .unwrap_or_default())
751 }
752
753 async fn get_users_with_display_names<'a>(
754 &self,
755 room_id: &RoomId,
756 display_names: &'a [DisplayName],
757 ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>> {
758 if display_names.is_empty() {
759 return Ok(HashMap::new());
760 }
761
762 let inner = self.inner.read().unwrap();
763 let Some(room_names) = inner.display_names.get(room_id) else {
764 return Ok(HashMap::new());
765 };
766
767 Ok(display_names.iter().filter_map(|n| room_names.get(n).map(|d| (n, d.clone()))).collect())
768 }
769
770 async fn get_account_data_event(
771 &self,
772 event_type: GlobalAccountDataEventType,
773 ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>> {
774 Ok(self.inner.read().unwrap().account_data.get(&event_type).cloned())
775 }
776
777 async fn get_room_account_data_event(
778 &self,
779 room_id: &RoomId,
780 event_type: RoomAccountDataEventType,
781 ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>> {
782 Ok(self
783 .inner
784 .read()
785 .unwrap()
786 .room_account_data
787 .get(room_id)
788 .and_then(|m| m.get(&event_type))
789 .cloned())
790 }
791
792 async fn get_user_room_receipt_event(
793 &self,
794 room_id: &RoomId,
795 receipt_type: ReceiptType,
796 receipt_thread: &ReceiptThread,
797 user_id: &UserId,
798 ) -> Result<Option<(OwnedEventId, Receipt)>> {
799 Ok(self.get_user_room_receipt_event_impl(room_id, receipt_type, receipt_thread, user_id))
800 }
801
802 async fn get_event_room_receipt_events(
803 &self,
804 room_id: &RoomId,
805 receipt_type: ReceiptType,
806 receipt_thread: &ReceiptThread,
807 event_id: &EventId,
808 ) -> Result<Vec<(OwnedUserId, Receipt)>> {
809 Ok(self
810 .get_event_room_receipt_events_impl(room_id, receipt_type, receipt_thread, event_id)
811 .unwrap_or_default())
812 }
813
814 async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
815 Ok(self.inner.read().unwrap().custom.get(key).cloned())
816 }
817
818 async fn set_custom_value(&self, key: &[u8], value: Vec<u8>) -> Result<Option<Vec<u8>>> {
819 Ok(self.inner.write().unwrap().custom.insert(key.to_vec(), value))
820 }
821
822 async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
823 Ok(self.inner.write().unwrap().custom.remove(key))
824 }
825
826 async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
827 let mut inner = self.inner.write().unwrap();
828
829 inner.profiles.remove(room_id);
830 inner.display_names.remove(room_id);
831 inner.members.remove(room_id);
832 inner.room_info.remove(room_id);
833 inner.room_state.remove(room_id);
834 inner.room_account_data.remove(room_id);
835 inner.stripped_room_state.remove(room_id);
836 inner.stripped_members.remove(room_id);
837 inner.room_user_receipts.remove(room_id);
838 inner.room_event_receipts.remove(room_id);
839 inner.send_queue_events.remove(room_id);
840 inner.dependent_send_queue_events.remove(room_id);
841 inner.thread_subscriptions.remove(room_id);
842
843 Ok(())
844 }
845
846 async fn save_send_queue_request(
847 &self,
848 room_id: &RoomId,
849 transaction_id: OwnedTransactionId,
850 created_at: MilliSecondsSinceUnixEpoch,
851 kind: QueuedRequestKind,
852 priority: usize,
853 ) -> Result<(), Self::Error> {
854 self.inner
855 .write()
856 .unwrap()
857 .send_queue_events
858 .entry(room_id.to_owned())
859 .or_default()
860 .push(QueuedRequest { kind, transaction_id, error: None, priority, created_at });
861 Ok(())
862 }
863
864 async fn update_send_queue_request(
865 &self,
866 room_id: &RoomId,
867 transaction_id: &TransactionId,
868 kind: QueuedRequestKind,
869 ) -> Result<bool, Self::Error> {
870 if let Some(entry) = self
871 .inner
872 .write()
873 .unwrap()
874 .send_queue_events
875 .entry(room_id.to_owned())
876 .or_default()
877 .iter_mut()
878 .find(|item| item.transaction_id == transaction_id)
879 {
880 entry.kind = kind;
881 entry.error = None;
882 Ok(true)
883 } else {
884 Ok(false)
885 }
886 }
887
888 async fn remove_send_queue_request(
889 &self,
890 room_id: &RoomId,
891 transaction_id: &TransactionId,
892 ) -> Result<bool, Self::Error> {
893 let mut inner = self.inner.write().unwrap();
894 let q = &mut inner.send_queue_events;
895
896 let entry = q.get_mut(room_id);
897 if let Some(entry) = entry {
898 if let Some(pos) = entry.iter().position(|item| item.transaction_id == transaction_id) {
900 entry.remove(pos);
901 if entry.is_empty() {
904 q.remove(room_id);
905 }
906 return Ok(true);
907 }
908 }
909
910 Ok(false)
911 }
912
913 async fn load_send_queue_requests(
914 &self,
915 room_id: &RoomId,
916 ) -> Result<Vec<QueuedRequest>, Self::Error> {
917 let mut ret = self
918 .inner
919 .write()
920 .unwrap()
921 .send_queue_events
922 .entry(room_id.to_owned())
923 .or_default()
924 .clone();
925 ret.sort_by_key(|item| Reverse(item.priority));
927 Ok(ret)
928 }
929
930 async fn update_send_queue_request_status(
931 &self,
932 room_id: &RoomId,
933 transaction_id: &TransactionId,
934 error: Option<QueueWedgeError>,
935 ) -> Result<(), Self::Error> {
936 if let Some(entry) = self
937 .inner
938 .write()
939 .unwrap()
940 .send_queue_events
941 .entry(room_id.to_owned())
942 .or_default()
943 .iter_mut()
944 .find(|item| item.transaction_id == transaction_id)
945 {
946 entry.error = error;
947 }
948 Ok(())
949 }
950
951 async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
952 Ok(self.inner.read().unwrap().send_queue_events.keys().cloned().collect())
953 }
954
955 async fn save_dependent_queued_request(
956 &self,
957 room: &RoomId,
958 parent_transaction_id: &TransactionId,
959 own_transaction_id: ChildTransactionId,
960 created_at: MilliSecondsSinceUnixEpoch,
961 content: DependentQueuedRequestKind,
962 ) -> Result<(), Self::Error> {
963 self.inner
964 .write()
965 .unwrap()
966 .dependent_send_queue_events
967 .entry(room.to_owned())
968 .or_default()
969 .push(DependentQueuedRequest {
970 kind: content,
971 parent_transaction_id: parent_transaction_id.to_owned(),
972 own_transaction_id,
973 parent_key: None,
974 created_at,
975 });
976 Ok(())
977 }
978
979 async fn mark_dependent_queued_requests_as_ready(
980 &self,
981 room: &RoomId,
982 parent_txn_id: &TransactionId,
983 sent_parent_key: SentRequestKey,
984 ) -> Result<usize, Self::Error> {
985 let mut inner = self.inner.write().unwrap();
986 let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
987 let mut num_updated = 0;
988 for d in dependents.iter_mut().filter(|item| item.parent_transaction_id == parent_txn_id) {
989 d.parent_key = Some(sent_parent_key.clone());
990 num_updated += 1;
991 }
992 Ok(num_updated)
993 }
994
995 async fn update_dependent_queued_request(
996 &self,
997 room: &RoomId,
998 own_transaction_id: &ChildTransactionId,
999 new_content: DependentQueuedRequestKind,
1000 ) -> Result<bool, Self::Error> {
1001 let mut inner = self.inner.write().unwrap();
1002 let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
1003 for d in dependents.iter_mut() {
1004 if d.own_transaction_id == *own_transaction_id {
1005 d.kind = new_content;
1006 return Ok(true);
1007 }
1008 }
1009 Ok(false)
1010 }
1011
1012 async fn remove_dependent_queued_request(
1013 &self,
1014 room: &RoomId,
1015 txn_id: &ChildTransactionId,
1016 ) -> Result<bool, Self::Error> {
1017 let mut inner = self.inner.write().unwrap();
1018 let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
1019 if let Some(pos) = dependents.iter().position(|item| item.own_transaction_id == *txn_id) {
1020 dependents.remove(pos);
1021 Ok(true)
1022 } else {
1023 Ok(false)
1024 }
1025 }
1026
1027 async fn load_dependent_queued_requests(
1028 &self,
1029 room: &RoomId,
1030 ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
1031 Ok(self
1032 .inner
1033 .read()
1034 .unwrap()
1035 .dependent_send_queue_events
1036 .get(room)
1037 .cloned()
1038 .unwrap_or_default())
1039 }
1040
1041 async fn upsert_thread_subscriptions(
1042 &self,
1043 updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
1044 ) -> Result<(), Self::Error> {
1045 let mut inner = self.inner.write().unwrap();
1046
1047 for (room_id, thread_id, mut new) in updates {
1048 let room_subs = inner.thread_subscriptions.entry(room_id.to_owned()).or_default();
1049
1050 if let Some(previous) = room_subs.get(thread_id) {
1051 if *previous == new {
1052 continue;
1053 }
1054 if !compare_thread_subscription_bump_stamps(
1055 previous.bump_stamp,
1056 &mut new.bump_stamp,
1057 ) {
1058 continue;
1059 }
1060 }
1061
1062 room_subs.insert(thread_id.to_owned(), new);
1063 }
1064
1065 Ok(())
1066 }
1067
1068 async fn load_thread_subscription(
1069 &self,
1070 room: &RoomId,
1071 thread_id: &EventId,
1072 ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
1073 let inner = self.inner.read().unwrap();
1074 Ok(inner
1075 .thread_subscriptions
1076 .get(room)
1077 .and_then(|subscriptions| subscriptions.get(thread_id))
1078 .copied())
1079 }
1080
1081 async fn remove_thread_subscription(
1082 &self,
1083 room: &RoomId,
1084 thread_id: &EventId,
1085 ) -> Result<(), Self::Error> {
1086 let mut inner = self.inner.write().unwrap();
1087
1088 let Some(room_subs) = inner.thread_subscriptions.get_mut(room) else {
1089 return Ok(());
1090 };
1091
1092 room_subs.remove(thread_id);
1093
1094 if room_subs.is_empty() {
1095 inner.thread_subscriptions.remove(room);
1098 }
1099
1100 Ok(())
1101 }
1102
1103 async fn get_global_profile(
1104 &self,
1105 user_id: &UserId,
1106 ) -> Result<Option<UserProfile>, Self::Error> {
1107 let inner = self.inner.read().unwrap();
1108 Ok(inner.global_profiles.get(user_id).cloned())
1109 }
1110
1111 async fn get_global_profiles<'a>(
1112 &self,
1113 user_ids: &'a [OwnedUserId],
1114 ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error> {
1115 let inner = self.inner.read().unwrap();
1116 Ok(user_ids
1117 .iter()
1118 .filter_map(|user_id| {
1119 inner.global_profiles.get(user_id).map(|profile| (&**user_id, profile.clone()))
1120 })
1121 .collect())
1122 }
1123
1124 async fn optimize(&self) -> Result<(), Self::Error> {
1125 Ok(())
1126 }
1127
1128 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1129 Ok(None)
1130 }
1131}
1132
1133#[cfg(test)]
1134mod tests {
1135 use super::{MemoryStore, Result, StateStore};
1136
1137 async fn get_store() -> Result<impl StateStore> {
1138 Ok(MemoryStore::new())
1139 }
1140
1141 statestore_integration_tests!();
1142}