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