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,
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 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(), 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 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(), 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.clone());
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)
484 && let Some(event_map) =
485 receipt_map.get_mut(&(receipt_type.to_string(), thread.clone()))
486 && let Some(user_map) = event_map.get_mut(&old_event)
487 {
488 user_map.remove(user_id);
489 }
490 }
491
492 inner
494 .room_event_receipts
495 .entry(room.clone())
496 .or_default()
497 .entry((receipt_type.to_string(), thread))
498 .or_default()
499 .entry(event_id.clone())
500 .or_default()
501 .insert(user_id.clone(), receipt.clone());
502 }
503 }
504 }
505 }
506
507 let make_redaction_rules = |room_info: &HashMap<OwnedRoomId, RoomInfo>, room_id| {
508 room_info.get(room_id).map(|info| info.room_version_rules_or_default()).unwrap_or_else(|| {
509 warn!(
510 ?room_id,
511 "Unable to get the room version rules, defaulting to rules for room version {ROOM_VERSION_FALLBACK}"
512 );
513 ROOM_VERSION_RULES_FALLBACK
514 }).redaction
515 };
516
517 let inner = &mut *inner;
518 for (room_id, redactions) in &changes.redactions {
519 let mut redaction_rules = None;
520
521 if let Some(room) = inner.room_state.get_mut(room_id) {
522 for ref_room_mu in room.values_mut() {
523 for raw_evt in ref_room_mu.values_mut() {
524 if let Ok(Some(event_id)) = raw_evt.get_field::<OwnedEventId>("event_id")
525 && let Some(redaction) = redactions.get(&event_id)
526 {
527 let redacted = redact(
528 raw_evt.deserialize_as::<CanonicalJsonObject>()?,
529 redaction_rules.get_or_insert_with(|| {
530 make_redaction_rules(&inner.room_info, room_id)
531 }),
532 Some(RedactedBecause::from_raw_event(redaction)?),
533 )
534 .map_err(StoreError::Redaction)?;
535 *raw_evt = Raw::new(&redacted)?.cast_unchecked();
536 }
537 }
538 }
539 }
540 }
541
542 for (user_id, profile_update) in &changes.global_profiles {
543 let mut profile = inner.global_profiles.get(user_id).cloned().unwrap_or_default();
544 profile.merge(profile_update.clone());
545 inner.global_profiles.insert(user_id.clone(), profile);
546 }
547
548 debug!("Saved changes in {:?}", now.elapsed());
549
550 Ok(())
551 }
552
553 async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
554 Ok(self.inner.read().unwrap().presence.get(user_id).cloned())
555 }
556
557 async fn get_presence_events(
558 &self,
559 user_ids: &[OwnedUserId],
560 ) -> Result<Vec<Raw<PresenceEvent>>> {
561 let presence = &self.inner.read().unwrap().presence;
562 Ok(user_ids.iter().filter_map(|user_id| presence.get(user_id).cloned()).collect())
563 }
564
565 async fn get_state_event(
566 &self,
567 room_id: &RoomId,
568 event_type: StateEventType,
569 state_key: &str,
570 ) -> Result<Option<RawAnySyncOrStrippedState>> {
571 Ok(self
572 .get_state_events_for_keys(room_id, event_type, &[state_key])
573 .await?
574 .into_iter()
575 .next())
576 }
577
578 async fn get_state_events(
579 &self,
580 room_id: &RoomId,
581 event_type: StateEventType,
582 ) -> Result<Vec<RawAnySyncOrStrippedState>> {
583 fn get_events<T>(
584 state_map: &HashMap<OwnedRoomId, HashMap<StateEventType, HashMap<String, Raw<T>>>>,
585 room_id: &RoomId,
586 event_type: &StateEventType,
587 to_enum: fn(Raw<T>) -> RawAnySyncOrStrippedState,
588 ) -> Option<Vec<RawAnySyncOrStrippedState>> {
589 let state_events = state_map.get(room_id)?.get(event_type)?;
590 Some(state_events.values().cloned().map(to_enum).collect())
591 }
592
593 let inner = self.inner.read().unwrap();
594 Ok(get_events(
595 &inner.stripped_room_state,
596 room_id,
597 &event_type,
598 RawAnySyncOrStrippedState::Stripped,
599 )
600 .or_else(|| {
601 get_events(&inner.room_state, room_id, &event_type, RawAnySyncOrStrippedState::Sync)
602 })
603 .unwrap_or_default())
604 }
605
606 async fn get_state_events_for_keys(
607 &self,
608 room_id: &RoomId,
609 event_type: StateEventType,
610 state_keys: &[&str],
611 ) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
612 let inner = self.inner.read().unwrap();
613
614 if let Some(stripped_state_events) =
615 inner.stripped_room_state.get(room_id).and_then(|events| events.get(&event_type))
616 {
617 Ok(state_keys
618 .iter()
619 .filter_map(|k| {
620 stripped_state_events
621 .get(*k)
622 .map(|e| RawAnySyncOrStrippedState::Stripped(e.clone()))
623 })
624 .collect())
625 } else if let Some(sync_state_events) =
626 inner.room_state.get(room_id).and_then(|events| events.get(&event_type))
627 {
628 Ok(state_keys
629 .iter()
630 .filter_map(|k| {
631 sync_state_events.get(*k).map(|e| RawAnySyncOrStrippedState::Sync(e.clone()))
632 })
633 .collect())
634 } else {
635 Ok(Vec::new())
636 }
637 }
638
639 async fn get_profile(
640 &self,
641 room_id: &RoomId,
642 user_id: &UserId,
643 ) -> Result<Option<MinimalRoomMemberEvent>> {
644 Ok(self
645 .inner
646 .read()
647 .unwrap()
648 .profiles
649 .get(room_id)
650 .and_then(|room_profiles| room_profiles.get(user_id))
651 .cloned())
652 }
653
654 async fn get_profiles<'a>(
655 &self,
656 room_id: &RoomId,
657 user_ids: &'a [OwnedUserId],
658 ) -> Result<BTreeMap<&'a UserId, MinimalRoomMemberEvent>> {
659 if user_ids.is_empty() {
660 return Ok(BTreeMap::new());
661 }
662
663 let profiles = &self.inner.read().unwrap().profiles;
664 let Some(room_profiles) = profiles.get(room_id) else {
665 return Ok(BTreeMap::new());
666 };
667
668 Ok(user_ids
669 .iter()
670 .filter_map(|user_id| room_profiles.get(user_id).map(|p| (&**user_id, p.clone())))
671 .collect())
672 }
673
674 #[instrument(skip(self, memberships))]
675 async fn get_user_ids(
676 &self,
677 room_id: &RoomId,
678 memberships: RoomMemberships,
679 ) -> Result<Vec<OwnedUserId>> {
680 fn get_user_ids_inner(
686 members: &HashMap<OwnedRoomId, HashMap<OwnedUserId, MembershipState>>,
687 room_id: &RoomId,
688 memberships: RoomMemberships,
689 ) -> Vec<OwnedUserId> {
690 members
691 .get(room_id)
692 .map(|members| {
693 members
694 .iter()
695 .filter_map(|(user_id, membership)| {
696 memberships.matches(membership).then_some(user_id)
697 })
698 .cloned()
699 .collect()
700 })
701 .unwrap_or_default()
702 }
703 let inner = self.inner.read().unwrap();
704 let v = get_user_ids_inner(&inner.stripped_members, room_id, memberships);
705 if !v.is_empty() {
706 return Ok(v);
707 }
708 Ok(get_user_ids_inner(&inner.members, room_id, memberships))
709 }
710
711 async fn get_room_infos(&self, room_load_settings: &RoomLoadSettings) -> Result<Vec<RoomInfo>> {
712 let memory_store_inner = self.inner.read().unwrap();
713 let room_infos = &memory_store_inner.room_info;
714
715 Ok(match room_load_settings {
716 RoomLoadSettings::All => room_infos.values().cloned().collect(),
717
718 RoomLoadSettings::One(room_id) => match room_infos.get(room_id) {
719 Some(room_info) => vec![room_info.clone()],
720 None => vec![],
721 },
722 })
723 }
724
725 async fn get_users_with_display_name(
726 &self,
727 room_id: &RoomId,
728 display_name: &DisplayName,
729 ) -> Result<BTreeSet<OwnedUserId>> {
730 Ok(self
731 .inner
732 .read()
733 .unwrap()
734 .display_names
735 .get(room_id)
736 .and_then(|room_names| room_names.get(display_name).cloned())
737 .unwrap_or_default())
738 }
739
740 async fn get_users_with_display_names<'a>(
741 &self,
742 room_id: &RoomId,
743 display_names: &'a [DisplayName],
744 ) -> Result<HashMap<&'a DisplayName, BTreeSet<OwnedUserId>>> {
745 if display_names.is_empty() {
746 return Ok(HashMap::new());
747 }
748
749 let inner = self.inner.read().unwrap();
750 let Some(room_names) = inner.display_names.get(room_id) else {
751 return Ok(HashMap::new());
752 };
753
754 Ok(display_names.iter().filter_map(|n| room_names.get(n).map(|d| (n, d.clone()))).collect())
755 }
756
757 async fn get_account_data_event(
758 &self,
759 event_type: GlobalAccountDataEventType,
760 ) -> Result<Option<Raw<AnyGlobalAccountDataEvent>>> {
761 Ok(self.inner.read().unwrap().account_data.get(&event_type).cloned())
762 }
763
764 async fn get_room_account_data_event(
765 &self,
766 room_id: &RoomId,
767 event_type: RoomAccountDataEventType,
768 ) -> Result<Option<Raw<AnyRoomAccountDataEvent>>> {
769 Ok(self
770 .inner
771 .read()
772 .unwrap()
773 .room_account_data
774 .get(room_id)
775 .and_then(|m| m.get(&event_type))
776 .cloned())
777 }
778
779 async fn get_user_room_receipt_event(
780 &self,
781 room_id: &RoomId,
782 receipt_type: ReceiptType,
783 thread: ReceiptThread,
784 user_id: &UserId,
785 ) -> Result<Option<(OwnedEventId, Receipt)>> {
786 Ok(self.get_user_room_receipt_event_impl(room_id, receipt_type, thread, user_id))
787 }
788
789 async fn get_event_room_receipt_events(
790 &self,
791 room_id: &RoomId,
792 receipt_type: ReceiptType,
793 thread: ReceiptThread,
794 event_id: &EventId,
795 ) -> Result<Vec<(OwnedUserId, Receipt)>> {
796 Ok(self
797 .get_event_room_receipt_events_impl(room_id, receipt_type, thread, event_id)
798 .unwrap_or_default())
799 }
800
801 async fn get_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
802 Ok(self.inner.read().unwrap().custom.get(key).cloned())
803 }
804
805 async fn set_custom_value(&self, key: &[u8], value: Vec<u8>) -> Result<Option<Vec<u8>>> {
806 Ok(self.inner.write().unwrap().custom.insert(key.to_vec(), value))
807 }
808
809 async fn remove_custom_value(&self, key: &[u8]) -> Result<Option<Vec<u8>>> {
810 Ok(self.inner.write().unwrap().custom.remove(key))
811 }
812
813 async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
814 let mut inner = self.inner.write().unwrap();
815
816 inner.profiles.remove(room_id);
817 inner.display_names.remove(room_id);
818 inner.members.remove(room_id);
819 inner.room_info.remove(room_id);
820 inner.room_state.remove(room_id);
821 inner.room_account_data.remove(room_id);
822 inner.stripped_room_state.remove(room_id);
823 inner.stripped_members.remove(room_id);
824 inner.room_user_receipts.remove(room_id);
825 inner.room_event_receipts.remove(room_id);
826 inner.send_queue_events.remove(room_id);
827 inner.dependent_send_queue_events.remove(room_id);
828 inner.thread_subscriptions.remove(room_id);
829
830 Ok(())
831 }
832
833 async fn save_send_queue_request(
834 &self,
835 room_id: &RoomId,
836 transaction_id: OwnedTransactionId,
837 created_at: MilliSecondsSinceUnixEpoch,
838 kind: QueuedRequestKind,
839 priority: usize,
840 ) -> Result<(), Self::Error> {
841 self.inner
842 .write()
843 .unwrap()
844 .send_queue_events
845 .entry(room_id.to_owned())
846 .or_default()
847 .push(QueuedRequest { kind, transaction_id, error: None, priority, created_at });
848 Ok(())
849 }
850
851 async fn update_send_queue_request(
852 &self,
853 room_id: &RoomId,
854 transaction_id: &TransactionId,
855 kind: QueuedRequestKind,
856 ) -> Result<bool, Self::Error> {
857 if let Some(entry) = self
858 .inner
859 .write()
860 .unwrap()
861 .send_queue_events
862 .entry(room_id.to_owned())
863 .or_default()
864 .iter_mut()
865 .find(|item| item.transaction_id == transaction_id)
866 {
867 entry.kind = kind;
868 entry.error = None;
869 Ok(true)
870 } else {
871 Ok(false)
872 }
873 }
874
875 async fn remove_send_queue_request(
876 &self,
877 room_id: &RoomId,
878 transaction_id: &TransactionId,
879 ) -> Result<bool, Self::Error> {
880 let mut inner = self.inner.write().unwrap();
881 let q = &mut inner.send_queue_events;
882
883 let entry = q.get_mut(room_id);
884 if let Some(entry) = entry {
885 if let Some(pos) = entry.iter().position(|item| item.transaction_id == transaction_id) {
887 entry.remove(pos);
888 if entry.is_empty() {
890 q.remove(room_id);
891 }
892 return Ok(true);
893 }
894 }
895
896 Ok(false)
897 }
898
899 async fn load_send_queue_requests(
900 &self,
901 room_id: &RoomId,
902 ) -> Result<Vec<QueuedRequest>, Self::Error> {
903 let mut ret = self
904 .inner
905 .write()
906 .unwrap()
907 .send_queue_events
908 .entry(room_id.to_owned())
909 .or_default()
910 .clone();
911 ret.sort_by_key(|item| Reverse(item.priority));
913 Ok(ret)
914 }
915
916 async fn update_send_queue_request_status(
917 &self,
918 room_id: &RoomId,
919 transaction_id: &TransactionId,
920 error: Option<QueueWedgeError>,
921 ) -> Result<(), Self::Error> {
922 if let Some(entry) = self
923 .inner
924 .write()
925 .unwrap()
926 .send_queue_events
927 .entry(room_id.to_owned())
928 .or_default()
929 .iter_mut()
930 .find(|item| item.transaction_id == transaction_id)
931 {
932 entry.error = error;
933 }
934 Ok(())
935 }
936
937 async fn load_rooms_with_unsent_requests(&self) -> Result<Vec<OwnedRoomId>, Self::Error> {
938 Ok(self.inner.read().unwrap().send_queue_events.keys().cloned().collect())
939 }
940
941 async fn save_dependent_queued_request(
942 &self,
943 room: &RoomId,
944 parent_transaction_id: &TransactionId,
945 own_transaction_id: ChildTransactionId,
946 created_at: MilliSecondsSinceUnixEpoch,
947 content: DependentQueuedRequestKind,
948 ) -> Result<(), Self::Error> {
949 self.inner
950 .write()
951 .unwrap()
952 .dependent_send_queue_events
953 .entry(room.to_owned())
954 .or_default()
955 .push(DependentQueuedRequest {
956 kind: content,
957 parent_transaction_id: parent_transaction_id.to_owned(),
958 own_transaction_id,
959 parent_key: None,
960 created_at,
961 });
962 Ok(())
963 }
964
965 async fn mark_dependent_queued_requests_as_ready(
966 &self,
967 room: &RoomId,
968 parent_txn_id: &TransactionId,
969 sent_parent_key: SentRequestKey,
970 ) -> Result<usize, Self::Error> {
971 let mut inner = self.inner.write().unwrap();
972 let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
973 let mut num_updated = 0;
974 for d in dependents.iter_mut().filter(|item| item.parent_transaction_id == parent_txn_id) {
975 d.parent_key = Some(sent_parent_key.clone());
976 num_updated += 1;
977 }
978 Ok(num_updated)
979 }
980
981 async fn update_dependent_queued_request(
982 &self,
983 room: &RoomId,
984 own_transaction_id: &ChildTransactionId,
985 new_content: DependentQueuedRequestKind,
986 ) -> Result<bool, Self::Error> {
987 let mut inner = self.inner.write().unwrap();
988 let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
989 for d in dependents.iter_mut() {
990 if d.own_transaction_id == *own_transaction_id {
991 d.kind = new_content;
992 return Ok(true);
993 }
994 }
995 Ok(false)
996 }
997
998 async fn remove_dependent_queued_request(
999 &self,
1000 room: &RoomId,
1001 txn_id: &ChildTransactionId,
1002 ) -> Result<bool, Self::Error> {
1003 let mut inner = self.inner.write().unwrap();
1004 let dependents = inner.dependent_send_queue_events.entry(room.to_owned()).or_default();
1005 if let Some(pos) = dependents.iter().position(|item| item.own_transaction_id == *txn_id) {
1006 dependents.remove(pos);
1007 Ok(true)
1008 } else {
1009 Ok(false)
1010 }
1011 }
1012
1013 async fn load_dependent_queued_requests(
1014 &self,
1015 room: &RoomId,
1016 ) -> Result<Vec<DependentQueuedRequest>, Self::Error> {
1017 Ok(self
1018 .inner
1019 .read()
1020 .unwrap()
1021 .dependent_send_queue_events
1022 .get(room)
1023 .cloned()
1024 .unwrap_or_default())
1025 }
1026
1027 async fn upsert_thread_subscriptions(
1028 &self,
1029 updates: Vec<(&RoomId, &EventId, StoredThreadSubscription)>,
1030 ) -> Result<(), Self::Error> {
1031 let mut inner = self.inner.write().unwrap();
1032
1033 for (room_id, thread_id, mut new) in updates {
1034 let room_subs = inner.thread_subscriptions.entry(room_id.to_owned()).or_default();
1035
1036 if let Some(previous) = room_subs.get(thread_id) {
1037 if *previous == new {
1038 continue;
1039 }
1040 if !compare_thread_subscription_bump_stamps(
1041 previous.bump_stamp,
1042 &mut new.bump_stamp,
1043 ) {
1044 continue;
1045 }
1046 }
1047
1048 room_subs.insert(thread_id.to_owned(), new);
1049 }
1050
1051 Ok(())
1052 }
1053
1054 async fn load_thread_subscription(
1055 &self,
1056 room: &RoomId,
1057 thread_id: &EventId,
1058 ) -> Result<Option<StoredThreadSubscription>, Self::Error> {
1059 let inner = self.inner.read().unwrap();
1060 Ok(inner
1061 .thread_subscriptions
1062 .get(room)
1063 .and_then(|subscriptions| subscriptions.get(thread_id))
1064 .copied())
1065 }
1066
1067 async fn remove_thread_subscription(
1068 &self,
1069 room: &RoomId,
1070 thread_id: &EventId,
1071 ) -> Result<(), Self::Error> {
1072 let mut inner = self.inner.write().unwrap();
1073
1074 let Some(room_subs) = inner.thread_subscriptions.get_mut(room) else {
1075 return Ok(());
1076 };
1077
1078 room_subs.remove(thread_id);
1079
1080 if room_subs.is_empty() {
1081 inner.thread_subscriptions.remove(room);
1083 }
1084
1085 Ok(())
1086 }
1087
1088 async fn get_global_profile(
1089 &self,
1090 user_id: &UserId,
1091 ) -> Result<Option<UserProfile>, Self::Error> {
1092 let inner = self.inner.read().unwrap();
1093 Ok(inner.global_profiles.get(user_id).cloned())
1094 }
1095
1096 async fn get_global_profiles<'a>(
1097 &self,
1098 user_ids: &'a [OwnedUserId],
1099 ) -> Result<BTreeMap<&'a UserId, UserProfile>, Self::Error> {
1100 let inner = self.inner.read().unwrap();
1101 Ok(user_ids
1102 .iter()
1103 .filter_map(|user_id| {
1104 inner.global_profiles.get(user_id).map(|profile| (&**user_id, profile.clone()))
1105 })
1106 .collect())
1107 }
1108
1109 async fn optimize(&self) -> Result<(), Self::Error> {
1110 Ok(())
1111 }
1112
1113 async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
1114 Ok(None)
1115 }
1116}
1117
1118#[cfg(test)]
1119mod tests {
1120 use super::{MemoryStore, Result, StateStore};
1121
1122 async fn get_store() -> Result<impl StateStore> {
1123 Ok(MemoryStore::new())
1124 }
1125
1126 statestore_integration_tests!();
1127}