chore: checking workspace state consistent after switching workspace (#5201)

* refactor: getting workspace id

* refactor: check workspace id is match for http response

* refactor: check http repsonse in valid by checing the workspace id

* chore: update log

* chore: fix test

* chore: fix test

* chore: add test

* chore: update test
This commit is contained in:
Nathan.fooo
2024-04-26 09:44:07 +08:00
committed by GitHub
parent 65a289648e
commit cc66147bc0
51 changed files with 980 additions and 575 deletions

View File

@ -65,56 +65,32 @@ impl Display for CollabPluginProviderContext {
}
}
pub trait WorkspaceCollabIntegrate: Send + Sync {
fn workspace_id(&self) -> Result<String, Error>;
fn device_id(&self) -> Result<String, Error>;
}
pub struct AppFlowyCollabBuilder {
network_reachability: CollabConnectReachability,
workspace_id: RwLock<Option<String>>,
plugin_provider: RwLock<Arc<dyn CollabCloudPluginProvider>>,
snapshot_persistence: Mutex<Option<Arc<dyn SnapshotPersistence>>>,
#[cfg(not(target_arch = "wasm32"))]
rocksdb_backup: Mutex<Option<Arc<dyn RocksdbBackup>>>,
device_id: String,
}
pub struct CollabBuilderConfig {
pub sync_enable: bool,
/// If auto_initialize is false, the collab object will not be initialized automatically.
/// You need to call collab.initialize() manually.
///
/// Default is true.
pub auto_initialize: bool,
}
impl Default for CollabBuilderConfig {
fn default() -> Self {
Self {
sync_enable: true,
auto_initialize: true,
}
}
}
impl CollabBuilderConfig {
pub fn sync_enable(mut self, sync_enable: bool) -> Self {
self.sync_enable = sync_enable;
self
}
pub fn auto_initialize(mut self, auto_initialize: bool) -> Self {
self.auto_initialize = auto_initialize;
self
}
workspace_integrate: Arc<dyn WorkspaceCollabIntegrate>,
}
impl AppFlowyCollabBuilder {
pub fn new<T: CollabCloudPluginProvider>(storage_provider: T, device_id: String) -> Self {
pub fn new(
storage_provider: impl CollabCloudPluginProvider + 'static,
workspace_integrate: impl WorkspaceCollabIntegrate + 'static,
) -> Self {
Self {
network_reachability: CollabConnectReachability::new(),
workspace_id: Default::default(),
plugin_provider: RwLock::new(Arc::new(storage_provider)),
snapshot_persistence: Default::default(),
#[cfg(not(target_arch = "wasm32"))]
rocksdb_backup: Default::default(),
device_id,
workspace_integrate: Arc::new(workspace_integrate),
}
}
@ -127,10 +103,6 @@ impl AppFlowyCollabBuilder {
*self.rocksdb_backup.lock() = Some(rocksdb_backup);
}
pub fn initialize(&self, workspace_id: String) {
*self.workspace_id.write() = Some(workspace_id);
}
pub fn update_network(&self, reachable: bool) {
if reachable {
self
@ -149,15 +121,14 @@ impl AppFlowyCollabBuilder {
object_id: &str,
collab_type: CollabType,
) -> Result<CollabObject, Error> {
let workspace_id = self.workspace_id.read().clone().ok_or_else(|| {
anyhow::anyhow!("When using supabase plugin, the workspace_id should not be empty")
})?;
let device_id = self.workspace_integrate.device_id()?;
let workspace_id = self.workspace_integrate.workspace_id()?;
Ok(CollabObject::new(
uid,
object_id.to_string(),
collab_type,
workspace_id,
self.device_id.clone(),
device_id,
))
}
@ -175,8 +146,10 @@ impl AppFlowyCollabBuilder {
/// - `raw_data`: The raw data of the collaboration object, defined by the [CollabDocState] type.
/// - `collab_db`: A weak reference to the [CollabKVDB].
///
#[allow(clippy::too_many_arguments)]
pub async fn build(
&self,
workspace_id: &str,
uid: i64,
object_id: &str,
object_type: CollabType,
@ -184,14 +157,13 @@ impl AppFlowyCollabBuilder {
collab_db: Weak<CollabKVDB>,
build_config: CollabBuilderConfig,
) -> Result<Arc<MutexCollab>, Error> {
let persistence_config = CollabPersistenceConfig::default();
self.build_with_config(
workspace_id,
uid,
object_id,
object_type,
collab_db,
collab_doc_state,
persistence_config,
build_config,
)
}
@ -211,25 +183,34 @@ impl AppFlowyCollabBuilder {
/// - `collab_db`: A weak reference to the [CollabKVDB].
///
#[allow(clippy::too_many_arguments)]
#[instrument(
level = "trace",
skip(self, collab_db, collab_doc_state, persistence_config, build_config)
)]
#[instrument(level = "trace", skip(self, collab_db, collab_doc_state, build_config))]
pub fn build_with_config(
&self,
workspace_id: &str,
uid: i64,
object_id: &str,
object_type: CollabType,
collab_db: Weak<CollabKVDB>,
collab_doc_state: DataSource,
#[allow(unused_variables)] persistence_config: CollabPersistenceConfig,
build_config: CollabBuilderConfig,
) -> Result<Arc<MutexCollab>, Error> {
let collab = CollabBuilder::new(uid, object_id)
.with_doc_state(collab_doc_state)
.with_device_id(self.device_id.clone())
.with_device_id(self.workspace_integrate.device_id()?)
.build()?;
// Compare the workspace_id with the currently opened workspace_id. Return an error if they do not match.
// This check is crucial in asynchronous code contexts where the workspace_id might change during operation.
let actual_workspace_id = self.workspace_integrate.workspace_id()?;
if workspace_id != actual_workspace_id {
return Err(anyhow::anyhow!(
"workspace_id not match when build collab. expect workspace_id: {}, actual workspace_id: {}",
workspace_id,
actual_workspace_id
));
}
let persistence_config = CollabPersistenceConfig::default();
#[cfg(target_arch = "wasm32")]
{
collab.lock().add_plugin(Box::new(IndexeddbDiskPlugin::new(
@ -317,3 +298,33 @@ impl AppFlowyCollabBuilder {
Ok(arc_collab)
}
}
pub struct CollabBuilderConfig {
pub sync_enable: bool,
/// If auto_initialize is false, the collab object will not be initialized automatically.
/// You need to call collab.initialize() manually.
///
/// Default is true.
pub auto_initialize: bool,
}
impl Default for CollabBuilderConfig {
fn default() -> Self {
Self {
sync_enable: true,
auto_initialize: true,
}
}
}
impl CollabBuilderConfig {
pub fn sync_enable(mut self, sync_enable: bool) -> Self {
self.sync_enable = sync_enable;
self
}
pub fn auto_initialize(mut self, auto_initialize: bool) -> Self {
self.auto_initialize = auto_initialize;
self
}
}

View File

@ -1,8 +1,8 @@
use crate::collab_builder::{CollabPluginProviderContext, CollabPluginProviderType};
use collab::preclude::CollabPlugin;
use std::sync::Arc;
pub trait CollabCloudPluginProvider: Send + Sync + 'static {
#[cfg(target_arch = "wasm32")]
pub trait CollabCloudPluginProvider: 'static {
fn provider_type(&self) -> CollabPluginProviderType;
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>>;
@ -10,7 +10,35 @@ pub trait CollabCloudPluginProvider: Send + Sync + 'static {
fn is_sync_enabled(&self) -> bool;
}
impl<T> CollabCloudPluginProvider for Arc<T>
#[cfg(target_arch = "wasm32")]
impl<T> CollabCloudPluginProvider for std::rc::Rc<T>
where
T: CollabCloudPluginProvider,
{
fn provider_type(&self) -> CollabPluginProviderType {
(**self).provider_type()
}
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>> {
(**self).get_plugins(context)
}
fn is_sync_enabled(&self) -> bool {
(**self).is_sync_enabled()
}
}
#[cfg(not(target_arch = "wasm32"))]
pub trait CollabCloudPluginProvider: Send + Sync + 'static {
fn provider_type(&self) -> CollabPluginProviderType;
fn get_plugins(&self, context: CollabPluginProviderContext) -> Vec<Box<dyn CollabPlugin>>;
fn is_sync_enabled(&self) -> bool;
}
#[cfg(not(target_arch = "wasm32"))]
impl<T> CollabCloudPluginProvider for std::sync::Arc<T>
where
T: CollabCloudPluginProvider,
{