diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index 4a3fae985a..51a3f1a3b2 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -2835,6 +2835,7 @@ dependencies = [ "flowy-notification", "flowy-search-pub", "flowy-sqlite", + "flowy-user-pub", "futures", "lazy_static", "lib-dispatch", diff --git a/frontend/rust-lib/flowy-ai/src/ai_manager.rs b/frontend/rust-lib/flowy-ai/src/ai_manager.rs index 399a8d2d5d..9055341b99 100644 --- a/frontend/rust-lib/flowy-ai/src/ai_manager.rs +++ b/frontend/rust-lib/flowy-ai/src/ai_manager.rs @@ -131,7 +131,7 @@ impl AIManager { #[instrument(skip_all, err)] pub async fn initialize_after_open_workspace( &self, - _workspace_id: &str, + _workspace_id: &Uuid, ) -> Result<(), FlowyError> { let local_ai = self.local_ai.clone(); tokio::spawn(async move { diff --git a/frontend/rust-lib/flowy-core/src/lib.rs b/frontend/rust-lib/flowy-core/src/lib.rs index 893a010a18..c2800bd73b 100644 --- a/frontend/rust-lib/flowy-core/src/lib.rs +++ b/frontend/rust-lib/flowy-core/src/lib.rs @@ -253,6 +253,7 @@ impl AppFlowyCore { .await; let user_status_callback = UserStatusCallbackImpl { + user_manager: user_manager.clone(), collab_builder, folder_manager: folder_manager.clone(), database_manager: database_manager.clone(), diff --git a/frontend/rust-lib/flowy-core/src/user_state_callback.rs b/frontend/rust-lib/flowy-core/src/user_state_callback.rs index e43002d709..8db4e3f926 100644 --- a/frontend/rust-lib/flowy-core/src/user_state_callback.rs +++ b/frontend/rust-lib/flowy-core/src/user_state_callback.rs @@ -4,23 +4,27 @@ use anyhow::Context; use client_api::entity::billing_dto::SubscriptionPlan; use tracing::{error, event, info}; +use crate::server_layer::ServerProvider; use collab_entity::CollabType; use collab_integrate::collab_builder::AppFlowyCollabBuilder; +use collab_plugins::local_storage::kv::doc::CollabKVAction; +use collab_plugins::local_storage::kv::KVTransactionDB; use flowy_ai::ai_manager::AIManager; use flowy_database2::DatabaseManager; use flowy_document::manager::DocumentManager; -use flowy_error::FlowyResult; +use flowy_error::{FlowyError, FlowyResult}; use flowy_folder::manager::{FolderInitDataSource, FolderManager}; use flowy_storage::manager::StorageManager; use flowy_user::event_map::UserStatusCallback; +use flowy_user::user_manager::UserManager; use flowy_user_pub::cloud::{UserCloudConfig, UserCloudServiceProvider}; use flowy_user_pub::entities::{AuthType, UserProfile, UserWorkspace}; use lib_dispatch::runtime::AFPluginRuntime; use lib_infra::async_trait::async_trait; - -use crate::server_layer::ServerProvider; +use uuid::Uuid; pub(crate) struct UserStatusCallbackImpl { + pub(crate) user_manager: Arc, pub(crate) collab_builder: Arc, pub(crate) folder_manager: Arc, pub(crate) database_manager: Arc, @@ -42,6 +46,60 @@ impl UserStatusCallbackImpl { } }); } + + async fn folder_init_data_source( + &self, + user_id: i64, + workspace_id: &Uuid, + auth_type: &AuthType, + ) -> FlowyResult { + let is_exist = self.is_object_exist_on_disk(user_id, workspace_id, workspace_id)?; + if is_exist { + Ok(FolderInitDataSource::LocalDisk { + create_if_not_exist: false, + }) + } else { + let data_source = match self + .folder_manager + .cloud_service + .get_folder_doc_state(workspace_id, user_id, CollabType::Folder, workspace_id) + .await + { + Ok(doc_state) => match auth_type { + AuthType::Local => FolderInitDataSource::LocalDisk { + create_if_not_exist: true, + }, + AuthType::AppFlowyCloud => FolderInitDataSource::Cloud(doc_state), + }, + Err(err) => match auth_type { + AuthType::Local => FolderInitDataSource::LocalDisk { + create_if_not_exist: true, + }, + AuthType::AppFlowyCloud => { + return Err(err); + }, + }, + }; + Ok(data_source) + } + } + + fn is_object_exist_on_disk( + &self, + user_id: i64, + workspace_id: &Uuid, + object_id: &Uuid, + ) -> FlowyResult { + let db = self + .user_manager + .get_collab_db(user_id)? + .upgrade() + .ok_or_else(|| FlowyError::internal().with_context("Collab db is not initialized"))?; + let read = db.read_txn(); + let workspace_id = workspace_id.to_string(); + let object_id = object_id.to_string(); + Ok(read.is_exist(user_id, &workspace_id, &object_id)) + } } #[async_trait] @@ -101,9 +159,13 @@ impl UserStatusCallback for UserStatusCallbackImpl { user_workspace, device_id ); + let workspace_id = user_workspace.workspace_id()?; + let data_source = self + .folder_init_data_source(user_id, &workspace_id, auth_type) + .await?; self .folder_manager - .initialize_after_sign_in(user_id) + .initialize_after_sign_in(user_id, data_source) .await?; self .database_manager @@ -135,37 +197,9 @@ impl UserStatusCallback for UserStatusCallbackImpl { device_id ); let workspace_id = user_workspace.workspace_id()?; - - // In the current implementation, when a user signs up for AppFlowy Cloud, a default workspace - // is automatically created for them. However, for users who sign up through Supabase, the creation - // of the default workspace relies on the client-side operation. This means that the process - // for initializing a default workspace differs depending on the sign-up method used. - let data_source = match self - .folder_manager - .cloud_service - .get_folder_doc_state( - &workspace_id, - user_profile.uid, - CollabType::Folder, - &workspace_id, - ) - .await - { - Ok(doc_state) => match auth_type { - AuthType::Local => FolderInitDataSource::LocalDisk { - create_if_not_exist: true, - }, - AuthType::AppFlowyCloud => FolderInitDataSource::Cloud(doc_state), - }, - Err(err) => match auth_type { - AuthType::Local => FolderInitDataSource::LocalDisk { - create_if_not_exist: true, - }, - AuthType::AppFlowyCloud => { - return Err(err); - }, - }, - }; + let data_source = self + .folder_init_data_source(user_profile.uid, &workspace_id, auth_type) + .await?; self .folder_manager @@ -204,12 +238,17 @@ impl UserStatusCallback for UserStatusCallbackImpl { async fn on_workspace_opened( &self, user_id: i64, - user_workspace: &UserWorkspace, + workspace_id: &Uuid, + _user_workspace: &UserWorkspace, auth_type: &AuthType, ) -> FlowyResult<()> { + let data_source = self + .folder_init_data_source(user_id, workspace_id, auth_type) + .await?; + self .folder_manager - .initialize_after_open_workspace(user_id) + .initialize_after_open_workspace(user_id, data_source) .await?; self .database_manager @@ -221,11 +260,11 @@ impl UserStatusCallback for UserStatusCallbackImpl { .await?; self .ai_manager - .initialize_after_open_workspace(&user_workspace.id) + .initialize_after_open_workspace(workspace_id) .await?; self .storage_manager - .initialize_after_open_workspace(&user_workspace.id) + .initialize_after_open_workspace(workspace_id) .await; Ok(()) } diff --git a/frontend/rust-lib/flowy-folder/Cargo.toml b/frontend/rust-lib/flowy-folder/Cargo.toml index 998fcb84f5..13b19e48b8 100644 --- a/frontend/rust-lib/flowy-folder/Cargo.toml +++ b/frontend/rust-lib/flowy-folder/Cargo.toml @@ -14,6 +14,7 @@ collab-plugins = { workspace = true } collab-integrate = { workspace = true } flowy-folder-pub = { workspace = true } flowy-search-pub = { workspace = true } +flowy-user-pub = { workspace = true } flowy-sqlite = { workspace = true } flowy-derive.workspace = true flowy-notification = { workspace = true } diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 8662c1e061..fd12c15fba 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -262,16 +262,17 @@ impl FolderManager { /// Initialize the folder with the given workspace id. /// Fetch the folder updates from the cloud service and initialize the folder. - #[tracing::instrument(skip(self, user_id), err)] - pub async fn initialize_after_sign_in(&self, user_id: i64) -> FlowyResult<()> { + #[tracing::instrument(skip_all, err)] + pub async fn initialize_after_sign_in( + &self, + user_id: i64, + data_source: FolderInitDataSource, + ) -> FlowyResult<()> { let workspace_id = self.user.workspace_id()?; - let object_id = &workspace_id; - - let is_exist = self - .user - .is_folder_exist_on_disk(user_id, &workspace_id) - .unwrap_or(false); - if is_exist { + if let Err(err) = self.initialize(user_id, &workspace_id, data_source).await { + // If failed to open folder with remote data, open from local disk. After open from the local + // disk. the data will be synced to the remote server. + error!("initialize folder with error {:?}, fallback local", err); self .initialize( user_id, @@ -281,39 +282,17 @@ impl FolderManager { }, ) .await?; - } else { - let folder_doc_state = self - .cloud_service - .get_folder_doc_state(&workspace_id, user_id, CollabType::Folder, object_id) - .await?; - if let Err(err) = self - .initialize( - user_id, - &workspace_id, - FolderInitDataSource::Cloud(folder_doc_state), - ) - .await - { - // If failed to open folder with remote data, open from local disk. After open from the local - // disk. the data will be synced to the remote server. - error!("initialize folder with error {:?}, fallback local", err); - self - .initialize( - user_id, - &workspace_id, - FolderInitDataSource::LocalDisk { - create_if_not_exist: false, - }, - ) - .await?; - } } Ok(()) } - pub async fn initialize_after_open_workspace(&self, uid: i64) -> FlowyResult<()> { - self.initialize_after_sign_in(uid).await + pub async fn initialize_after_open_workspace( + &self, + uid: i64, + data_source: FolderInitDataSource, + ) -> FlowyResult<()> { + self.initialize_after_sign_in(uid, data_source).await } /// Initialize the folder for the new user. @@ -2139,6 +2118,7 @@ pub(crate) fn get_workspace_private_view_pbs(workspace_id: &Uuid, folder: &Folde } #[allow(clippy::large_enum_variant)] +#[derive(Debug)] pub enum FolderInitDataSource { /// It means using the data stored on local disk to initialize the folder LocalDisk { create_if_not_exist: bool }, diff --git a/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs b/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs index 7f4720de99..483ca3d100 100644 --- a/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs +++ b/frontend/rust-lib/flowy-server/src/local_server/impls/folder.rs @@ -85,9 +85,7 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl { } else { let data = default_encode_collab_for_collab_type(uid, &object_id, collab_type).await?; drop(read_txn); - - // create default folder doc - Err(FlowyError::local_version_not_support()) + Ok(data.doc_state.to_vec()) } } diff --git a/frontend/rust-lib/flowy-storage/src/manager.rs b/frontend/rust-lib/flowy-storage/src/manager.rs index 619dc47f90..0dd729b087 100644 --- a/frontend/rust-lib/flowy-storage/src/manager.rs +++ b/frontend/rust-lib/flowy-storage/src/manager.rs @@ -181,7 +181,7 @@ impl StorageManager { } } - pub async fn initialize_after_open_workspace(&self, workspace_id: &str) { + pub async fn initialize_after_open_workspace(&self, workspace_id: &Uuid) { self.enable_storage_write_access(); if let Err(err) = prepare_upload_task(self.uploader.clone(), self.user_service.clone()).await { diff --git a/frontend/rust-lib/flowy-user/src/event_map.rs b/frontend/rust-lib/flowy-user/src/event_map.rs index 0b489e6f28..fbee0a96d9 100644 --- a/frontend/rust-lib/flowy-user/src/event_map.rs +++ b/frontend/rust-lib/flowy-user/src/event_map.rs @@ -1,13 +1,13 @@ use client_api::entity::billing_dto::SubscriptionPlan; -use std::sync::Weak; -use strum_macros::Display; - use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; use flowy_error::FlowyResult; use flowy_user_pub::cloud::UserCloudConfig; use flowy_user_pub::entities::*; use lib_dispatch::prelude::*; use lib_infra::async_trait::async_trait; +use std::sync::Weak; +use strum_macros::Display; +use uuid::Uuid; use crate::event_handler::*; use crate::user_manager::UserManager; @@ -323,6 +323,7 @@ pub trait UserStatusCallback: Send + Sync + 'static { async fn on_workspace_opened( &self, _user_id: i64, + _workspace_id: &Uuid, _user_workspace: &UserWorkspace, _auth_type: &AuthType, ) -> FlowyResult<()> { diff --git a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs index 425b2351b0..34d0ece483 100644 --- a/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs +++ b/frontend/rust-lib/flowy-user/src/user_manager/manager_user_workspace.rs @@ -195,7 +195,7 @@ impl UserManager { .user_status_callback .read() .await - .on_workspace_opened(uid, &user_workspace, &user_profile.auth_type) + .on_workspace_opened(uid, workspace_id, &user_workspace, &user_profile.auth_type) .await { error!("Open workspace failed: {:?}", err);