diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index ed3b3ec4d..d1e90f915 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -64,8 +64,8 @@ use crate::{ Room, RoomInfoNotableUpdate, RoomInfoNotableUpdateReasons, RoomMembersUpdate, RoomState, }, store::{ - BaseStateStore, DynStateStore, MemoryStore, Result as StoreResult, RoomLoadSettings, - StateChanges, StateStoreDataKey, StateStoreDataValue, StateStoreExt, StoreConfig, + BaseStateStore, DynStateStore, Result as StoreResult, RoomLoadSettings, StateChanges, + StateStoreDataKey, StateStoreDataValue, StateStoreExt, StoreConfig, ambiguity_map::AmbiguityCache, }, sync::{RoomUpdates, SyncResponse}, @@ -221,24 +221,50 @@ impl BaseClient { cross_process_store_locks_holder_name: &str, handle_verification_events: bool, ) -> Result { - let in_memory_store_config = + let StoreConfig { state_store, event_cache_store, media_store, .. } = StoreConfig::new(cross_process_store_locks_holder_name.to_owned()) - .state_store(MemoryStore::new()) - .crypto_store(self.crypto_store.clone()); + .event_cache_store({ + if cross_process_store_locks_holder_name == self.event_cache_store.lock_holder() + { + return Err(Error::DuplicatedCrossProcessLockHolder( + cross_process_store_locks_holder_name.to_owned(), + )); + } + + // SAFETY: the store will be used behind another lock holder, so it's safe to + // use a clone of it. + unsafe { self.event_cache_store.clone_store() } + }) + .media_store({ + if cross_process_store_locks_holder_name == self.media_store.lock_holder() { + return Err(Error::DuplicatedCrossProcessLockHolder( + cross_process_store_locks_holder_name.to_owned(), + )); + } + + // SAFETY: the store will be used behind another lock holder, so it's safe to + // use a clone of it. + unsafe { self.media_store.clone_store() } + }); + + // Clone the Crypto store. + // We copy the crypto store as well as the `OlmMachine` for two reasons: + // 1. The `self.crypto_store` is the same as the one used inside the + // `OlmMachine`. + // 2. We need to ensure that the parent and child use the same data and caches + // inside the `OlmMachine` so the various ratchets and places where new + // randomness gets introduced don't diverge, i.e. one-time keys that get + // generated by the Olm Account or Olm sessions when they encrypt or decrypt + // messages. + let crypto_store = self.crypto_store.clone(); + let olm_machine = self.olm_machine.clone(); let copy = Self { - state_store: BaseStateStore::new(in_memory_store_config.state_store), - // The event and media stores both have cross process locking support. - event_cache_store: self.event_cache_store.clone(), - media_store: self.media_store.clone(), - // We copy the crypto store as well as the `OlmMachine` for two reasons: - // 1. The `self.crypto_store` is the same as the one used inside the `OlmMachine`. - // 2. We need to ensure that the parent and child use the same data and caches inside - // the `OlmMachine` so the various ratchets and places where new randomness gets - // introduced don't diverge, i.e. one-time keys that get generated by the Olm Account - // or Olm sessions when they encrypt or decrypt messages. - crypto_store: self.crypto_store.clone(), - olm_machine: self.olm_machine.clone(), + state_store: BaseStateStore::new(state_store), + event_cache_store, + media_store, + crypto_store, + olm_machine, ignore_user_list_changes: Default::default(), room_info_notable_update_sender: self.room_info_notable_update_sender.clone(), room_key_recipient_strategy: self.room_key_recipient_strategy.clone(), diff --git a/crates/matrix-sdk-base/src/error.rs b/crates/matrix-sdk-base/src/error.rs index 86e0586e4..8151d022c 100644 --- a/crates/matrix-sdk-base/src/error.rs +++ b/crates/matrix-sdk-base/src/error.rs @@ -58,6 +58,10 @@ pub enum Error { #[error(transparent)] CryptoStore(#[from] CryptoStoreError), + /// The given cross-process lock holder name is already used by a store. + #[error("The given cross-process lock holder name is already used by a store: `{0}`")] + DuplicatedCrossProcessLockHolder(String), + /// An error occurred during a E2EE operation. #[cfg(feature = "e2e-encryption")] #[error(transparent)] diff --git a/crates/matrix-sdk-base/src/event_cache/store/mod.rs b/crates/matrix-sdk-base/src/event_cache/store/mod.rs index d6d9e932f..03c57a7d7 100644 --- a/crates/matrix-sdk-base/src/event_cache/store/mod.rs +++ b/crates/matrix-sdk-base/src/event_cache/store/mod.rs @@ -91,6 +91,22 @@ impl EventCacheStoreLock { Ok(lock_state) } + + /// Clone the inner store, by-passing the lock. + /// + /// # Safety + /// + /// This method is useful when you want to build a new client with another + /// lock holder name for example. But the lock is fully by-passed in this + /// method. Be extremely careful! + pub(crate) unsafe fn clone_store(&self) -> Arc { + self.store.clone() + } + + /// Get the lock holder name. + pub(crate) fn lock_holder(&self) -> &str { + self.cross_process_lock.lock_holder() + } } /// The equivalent of [`CrossProcessLockState`] but for the [`EventCacheStore`]. diff --git a/crates/matrix-sdk-base/src/media/store/mod.rs b/crates/matrix-sdk-base/src/media/store/mod.rs index b7f6b4ba0..13007b307 100644 --- a/crates/matrix-sdk-base/src/media/store/mod.rs +++ b/crates/matrix-sdk-base/src/media/store/mod.rs @@ -150,6 +150,22 @@ impl MediaStoreLock { Ok(MediaStoreLockGuard { cross_process_lock_guard, store: self.store.deref() }) } + + /// Clone the inner store, by-passing the lock. + /// + /// # Safety + /// + /// This method is useful when you want to build a new client with another + /// lock holder name for example. But the lock is fully by-passed in this + /// method. Be extremely careful! + pub(crate) unsafe fn clone_store(&self) -> Arc { + self.store.clone() + } + + /// Get the lock holder name. + pub(crate) fn lock_holder(&self) -> &str { + self.cross_process_lock.lock_holder() + } } /// An RAII implementation of a “scoped lock” of an [`MediaStoreLock`].