feat(base): add fns for atomically updating room info

Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
This commit is contained in:
Michael Goldenberg
2026-04-18 13:26:00 -04:00
committed by Damir Jelić
parent 77e0714d6b
commit efd96d9299
2 changed files with 69 additions and 4 deletions

View File

@@ -58,6 +58,7 @@ use ruma::{
serde::Raw,
};
use serde::{Deserialize, Serialize};
use tokio::sync::MutexGuard;
use tracing::{field::debug, info, instrument, warn};
use super::{
@@ -65,13 +66,13 @@ use super::{
RoomHero, RoomNotableTags, RoomState, RoomSummary,
};
use crate::{
MinimalStateEvent,
MinimalStateEvent, StateChanges, StoreError,
deserialized_responses::RawSyncOrStrippedState,
latest_event::LatestEventValue,
notification_settings::RoomNotificationMode,
read_receipts::RoomReadReceipts,
room::call::CallIntentConsensus,
store::{SaveLockedStateStore, StateStoreExt},
store::{IncorrectMutexGuardError, SaveLockedStateStore, StateStoreExt},
sync::UnreadNotificationsCount,
utils::{AnyStateEventEnum, RawStateEventWithKeys},
};
@@ -90,6 +91,70 @@ impl Room {
self.info.get()
}
/// Update [`RoomInfo`] with the given function `F`. Updates are atomic as
/// this function acquires the lock of the underlying store before updating
/// the [`RoomInfo`].
pub async fn update_room_info<F>(&self, f: F)
where
F: FnOnce(RoomInfo) -> (RoomInfo, RoomInfoNotableUpdateReasons),
{
self.update_room_info_with_store_guard(&self.store.lock().lock().await, f)
.expect("should have correct mutex!")
}
/// Same as [`Self::update_room_info`], but allows the caller to provide a
/// guard for the lock of the underlying store in case it has already been
/// acquired.
///
/// This function returns an [`IncorrectMutexGuardError`] if the provided
/// guard is not associated with the lock of the underlying store.
pub fn update_room_info_with_store_guard<F>(
&self,
guard: &MutexGuard<'_, ()>,
f: F,
) -> Result<(), IncorrectMutexGuardError>
where
F: FnOnce(RoomInfo) -> (RoomInfo, RoomInfoNotableUpdateReasons),
{
if !std::ptr::eq(MutexGuard::mutex(guard), self.store.lock()) {
return Err(IncorrectMutexGuardError);
}
let (info, reasons) = f(self.clone_info());
self.set_room_info(info, reasons);
Ok(())
}
/// Same as [`Self::update_room_info`] but also saves the changes to the
/// underlying store.
pub async fn update_and_save_room_info<F>(&self, f: F) -> Result<(), StoreError>
where
F: FnOnce(RoomInfo) -> (RoomInfo, RoomInfoNotableUpdateReasons),
{
self.update_and_save_room_info_with_store_guard(&self.store.lock().lock().await, f).await
}
/// Same as [`Self::update_and_save_room_info`], but allows the caller to
/// provide a guard for the lock of the underlying store in case it has
/// already been acquired.
///
/// This function returns an [`IncorrectMutexGuardError`] if the provided
/// guard is not associated with the lock of the underlying store.
pub async fn update_and_save_room_info_with_store_guard<F>(
&self,
guard: &MutexGuard<'_, ()>,
f: F,
) -> Result<(), StoreError>
where
F: FnOnce(RoomInfo) -> (RoomInfo, RoomInfoNotableUpdateReasons),
{
let (info, reasons) = f(self.clone_info());
let mut changes = StateChanges::default();
changes.add_room(info.clone());
self.store.save_changes_with_guard(guard, &changes).await?;
self.set_room_info(info, reasons);
Ok(())
}
/// Update the summary with given RoomInfo.
pub fn set_room_info(
&self,

View File

@@ -94,8 +94,8 @@ pub use self::{
},
traits::{
ComposerDraft, ComposerDraftType, DraftAttachment, DraftAttachmentContent, DraftThumbnail,
DynStateStore, IntoStateStore, SaveLockedStateStore, StateStore, StateStoreDataKey,
StateStoreDataValue, StateStoreExt, SupportedVersionsResponse,
DynStateStore, IncorrectMutexGuardError, IntoStateStore, SaveLockedStateStore, StateStore,
StateStoreDataKey, StateStoreDataValue, StateStoreExt, SupportedVersionsResponse,
ThreadSubscriptionCatchupToken, WellKnownResponse,
},
};