chore: pass folder init data

This commit is contained in:
Nathan 2025-04-20 18:07:02 +08:00
parent 791a79a234
commit 92d5690bba
10 changed files with 106 additions and 85 deletions

View file

@ -2835,6 +2835,7 @@ dependencies = [
"flowy-notification", "flowy-notification",
"flowy-search-pub", "flowy-search-pub",
"flowy-sqlite", "flowy-sqlite",
"flowy-user-pub",
"futures", "futures",
"lazy_static", "lazy_static",
"lib-dispatch", "lib-dispatch",

View file

@ -131,7 +131,7 @@ impl AIManager {
#[instrument(skip_all, err)] #[instrument(skip_all, err)]
pub async fn initialize_after_open_workspace( pub async fn initialize_after_open_workspace(
&self, &self,
_workspace_id: &str, _workspace_id: &Uuid,
) -> Result<(), FlowyError> { ) -> Result<(), FlowyError> {
let local_ai = self.local_ai.clone(); let local_ai = self.local_ai.clone();
tokio::spawn(async move { tokio::spawn(async move {

View file

@ -253,6 +253,7 @@ impl AppFlowyCore {
.await; .await;
let user_status_callback = UserStatusCallbackImpl { let user_status_callback = UserStatusCallbackImpl {
user_manager: user_manager.clone(),
collab_builder, collab_builder,
folder_manager: folder_manager.clone(), folder_manager: folder_manager.clone(),
database_manager: database_manager.clone(), database_manager: database_manager.clone(),

View file

@ -4,23 +4,27 @@ use anyhow::Context;
use client_api::entity::billing_dto::SubscriptionPlan; use client_api::entity::billing_dto::SubscriptionPlan;
use tracing::{error, event, info}; use tracing::{error, event, info};
use crate::server_layer::ServerProvider;
use collab_entity::CollabType; use collab_entity::CollabType;
use collab_integrate::collab_builder::AppFlowyCollabBuilder; 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_ai::ai_manager::AIManager;
use flowy_database2::DatabaseManager; use flowy_database2::DatabaseManager;
use flowy_document::manager::DocumentManager; use flowy_document::manager::DocumentManager;
use flowy_error::FlowyResult; use flowy_error::{FlowyError, FlowyResult};
use flowy_folder::manager::{FolderInitDataSource, FolderManager}; use flowy_folder::manager::{FolderInitDataSource, FolderManager};
use flowy_storage::manager::StorageManager; use flowy_storage::manager::StorageManager;
use flowy_user::event_map::UserStatusCallback; use flowy_user::event_map::UserStatusCallback;
use flowy_user::user_manager::UserManager;
use flowy_user_pub::cloud::{UserCloudConfig, UserCloudServiceProvider}; use flowy_user_pub::cloud::{UserCloudConfig, UserCloudServiceProvider};
use flowy_user_pub::entities::{AuthType, UserProfile, UserWorkspace}; use flowy_user_pub::entities::{AuthType, UserProfile, UserWorkspace};
use lib_dispatch::runtime::AFPluginRuntime; use lib_dispatch::runtime::AFPluginRuntime;
use lib_infra::async_trait::async_trait; use lib_infra::async_trait::async_trait;
use uuid::Uuid;
use crate::server_layer::ServerProvider;
pub(crate) struct UserStatusCallbackImpl { pub(crate) struct UserStatusCallbackImpl {
pub(crate) user_manager: Arc<UserManager>,
pub(crate) collab_builder: Arc<AppFlowyCollabBuilder>, pub(crate) collab_builder: Arc<AppFlowyCollabBuilder>,
pub(crate) folder_manager: Arc<FolderManager>, pub(crate) folder_manager: Arc<FolderManager>,
pub(crate) database_manager: Arc<DatabaseManager>, pub(crate) database_manager: Arc<DatabaseManager>,
@ -42,6 +46,60 @@ impl UserStatusCallbackImpl {
} }
}); });
} }
async fn folder_init_data_source(
&self,
user_id: i64,
workspace_id: &Uuid,
auth_type: &AuthType,
) -> FlowyResult<FolderInitDataSource> {
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<bool> {
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] #[async_trait]
@ -101,9 +159,13 @@ impl UserStatusCallback for UserStatusCallbackImpl {
user_workspace, user_workspace,
device_id 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 self
.folder_manager .folder_manager
.initialize_after_sign_in(user_id) .initialize_after_sign_in(user_id, data_source)
.await?; .await?;
self self
.database_manager .database_manager
@ -135,37 +197,9 @@ impl UserStatusCallback for UserStatusCallbackImpl {
device_id device_id
); );
let workspace_id = user_workspace.workspace_id()?; let workspace_id = user_workspace.workspace_id()?;
let data_source = self
// In the current implementation, when a user signs up for AppFlowy Cloud, a default workspace .folder_init_data_source(user_profile.uid, &workspace_id, auth_type)
// is automatically created for them. However, for users who sign up through Supabase, the creation .await?;
// 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);
},
},
};
self self
.folder_manager .folder_manager
@ -204,12 +238,17 @@ impl UserStatusCallback for UserStatusCallbackImpl {
async fn on_workspace_opened( async fn on_workspace_opened(
&self, &self,
user_id: i64, user_id: i64,
user_workspace: &UserWorkspace, workspace_id: &Uuid,
_user_workspace: &UserWorkspace,
auth_type: &AuthType, auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {
let data_source = self
.folder_init_data_source(user_id, workspace_id, auth_type)
.await?;
self self
.folder_manager .folder_manager
.initialize_after_open_workspace(user_id) .initialize_after_open_workspace(user_id, data_source)
.await?; .await?;
self self
.database_manager .database_manager
@ -221,11 +260,11 @@ impl UserStatusCallback for UserStatusCallbackImpl {
.await?; .await?;
self self
.ai_manager .ai_manager
.initialize_after_open_workspace(&user_workspace.id) .initialize_after_open_workspace(workspace_id)
.await?; .await?;
self self
.storage_manager .storage_manager
.initialize_after_open_workspace(&user_workspace.id) .initialize_after_open_workspace(workspace_id)
.await; .await;
Ok(()) Ok(())
} }

View file

@ -14,6 +14,7 @@ collab-plugins = { workspace = true }
collab-integrate = { workspace = true } collab-integrate = { workspace = true }
flowy-folder-pub = { workspace = true } flowy-folder-pub = { workspace = true }
flowy-search-pub = { workspace = true } flowy-search-pub = { workspace = true }
flowy-user-pub = { workspace = true }
flowy-sqlite = { workspace = true } flowy-sqlite = { workspace = true }
flowy-derive.workspace = true flowy-derive.workspace = true
flowy-notification = { workspace = true } flowy-notification = { workspace = true }

View file

@ -262,16 +262,17 @@ impl FolderManager {
/// Initialize the folder with the given workspace id. /// Initialize the folder with the given workspace id.
/// Fetch the folder updates from the cloud service and initialize the folder. /// Fetch the folder updates from the cloud service and initialize the folder.
#[tracing::instrument(skip(self, user_id), err)] #[tracing::instrument(skip_all, err)]
pub async fn initialize_after_sign_in(&self, user_id: i64) -> FlowyResult<()> { pub async fn initialize_after_sign_in(
&self,
user_id: i64,
data_source: FolderInitDataSource,
) -> FlowyResult<()> {
let workspace_id = self.user.workspace_id()?; let workspace_id = self.user.workspace_id()?;
let object_id = &workspace_id; 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
let is_exist = self // disk. the data will be synced to the remote server.
.user error!("initialize folder with error {:?}, fallback local", err);
.is_folder_exist_on_disk(user_id, &workspace_id)
.unwrap_or(false);
if is_exist {
self self
.initialize( .initialize(
user_id, user_id,
@ -281,39 +282,17 @@ impl FolderManager {
}, },
) )
.await?; .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(()) Ok(())
} }
pub async fn initialize_after_open_workspace(&self, uid: i64) -> FlowyResult<()> { pub async fn initialize_after_open_workspace(
self.initialize_after_sign_in(uid).await &self,
uid: i64,
data_source: FolderInitDataSource,
) -> FlowyResult<()> {
self.initialize_after_sign_in(uid, data_source).await
} }
/// Initialize the folder for the new user. /// 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)] #[allow(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum FolderInitDataSource { pub enum FolderInitDataSource {
/// It means using the data stored on local disk to initialize the folder /// It means using the data stored on local disk to initialize the folder
LocalDisk { create_if_not_exist: bool }, LocalDisk { create_if_not_exist: bool },

View file

@ -85,9 +85,7 @@ impl FolderCloudService for LocalServerFolderCloudServiceImpl {
} else { } else {
let data = default_encode_collab_for_collab_type(uid, &object_id, collab_type).await?; let data = default_encode_collab_for_collab_type(uid, &object_id, collab_type).await?;
drop(read_txn); drop(read_txn);
Ok(data.doc_state.to_vec())
// create default folder doc
Err(FlowyError::local_version_not_support())
} }
} }

View file

@ -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(); self.enable_storage_write_access();
if let Err(err) = prepare_upload_task(self.uploader.clone(), self.user_service.clone()).await { if let Err(err) = prepare_upload_task(self.uploader.clone(), self.user_service.clone()).await {

View file

@ -1,13 +1,13 @@
use client_api::entity::billing_dto::SubscriptionPlan; use client_api::entity::billing_dto::SubscriptionPlan;
use std::sync::Weak;
use strum_macros::Display;
use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_user_pub::cloud::UserCloudConfig; use flowy_user_pub::cloud::UserCloudConfig;
use flowy_user_pub::entities::*; use flowy_user_pub::entities::*;
use lib_dispatch::prelude::*; use lib_dispatch::prelude::*;
use lib_infra::async_trait::async_trait; use lib_infra::async_trait::async_trait;
use std::sync::Weak;
use strum_macros::Display;
use uuid::Uuid;
use crate::event_handler::*; use crate::event_handler::*;
use crate::user_manager::UserManager; use crate::user_manager::UserManager;
@ -323,6 +323,7 @@ pub trait UserStatusCallback: Send + Sync + 'static {
async fn on_workspace_opened( async fn on_workspace_opened(
&self, &self,
_user_id: i64, _user_id: i64,
_workspace_id: &Uuid,
_user_workspace: &UserWorkspace, _user_workspace: &UserWorkspace,
_auth_type: &AuthType, _auth_type: &AuthType,
) -> FlowyResult<()> { ) -> FlowyResult<()> {

View file

@ -195,7 +195,7 @@ impl UserManager {
.user_status_callback .user_status_callback
.read() .read()
.await .await
.on_workspace_opened(uid, &user_workspace, &user_profile.auth_type) .on_workspace_opened(uid, workspace_id, &user_workspace, &user_profile.auth_type)
.await .await
{ {
error!("Open workspace failed: {:?}", err); error!("Open workspace failed: {:?}", err);