This commit is contained in:
Ivan Enderlin
2025-12-19 14:48:46 +01:00
committed by Stefan Ceriu
parent 76ccc94f9f
commit 324cd5e08f
4 changed files with 79 additions and 17 deletions

View File

@@ -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<Self> {
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(),

View File

@@ -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)]

View File

@@ -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<DynEventCacheStore> {
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`].

View File

@@ -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<DynMediaStore> {
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`].