2023-10-02 09:12:24 +02:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2023-10-07 09:58:44 +08:00
|
|
|
use anyhow::Context;
|
2024-07-22 09:43:48 +02:00
|
|
|
use client_api::entity::billing_dto::SubscriptionPlan;
|
2024-06-20 07:44:57 +08:00
|
|
|
use tracing::{event, trace};
|
2023-10-07 09:58:44 +08:00
|
|
|
|
2024-06-05 04:05:51 +02:00
|
|
|
use collab_entity::CollabType;
|
2023-10-02 09:12:24 +02:00
|
|
|
use collab_integrate::collab_builder::AppFlowyCollabBuilder;
|
2024-07-22 09:43:48 +02:00
|
|
|
use flowy_chat::chat_manager::ChatManager;
|
2023-10-02 09:12:24 +02:00
|
|
|
use flowy_database2::DatabaseManager;
|
2023-12-31 07:29:40 +08:00
|
|
|
use flowy_document::manager::DocumentManager;
|
2024-02-08 23:53:05 +08:00
|
|
|
use flowy_error::{FlowyError, FlowyResult};
|
2023-12-31 07:29:40 +08:00
|
|
|
use flowy_folder::manager::{FolderInitDataSource, FolderManager};
|
2024-06-20 07:44:57 +08:00
|
|
|
use flowy_storage::manager::StorageManager;
|
2023-12-29 13:02:27 +08:00
|
|
|
use flowy_user::event_map::UserStatusCallback;
|
2024-02-04 05:50:23 +08:00
|
|
|
use flowy_user_pub::cloud::{UserCloudConfig, UserCloudServiceProvider};
|
2024-01-11 14:42:03 +08:00
|
|
|
use flowy_user_pub::entities::{Authenticator, UserProfile, UserWorkspace};
|
2023-10-02 09:12:24 +02:00
|
|
|
use lib_infra::future::{to_fut, Fut};
|
|
|
|
|
2023-12-29 15:03:24 +08:00
|
|
|
use crate::integrate::server::{Server, ServerProvider};
|
2023-10-02 09:12:24 +02:00
|
|
|
|
|
|
|
pub(crate) struct UserStatusCallbackImpl {
|
|
|
|
pub(crate) collab_builder: Arc<AppFlowyCollabBuilder>,
|
|
|
|
pub(crate) folder_manager: Arc<FolderManager>,
|
|
|
|
pub(crate) database_manager: Arc<DatabaseManager>,
|
|
|
|
pub(crate) document_manager: Arc<DocumentManager>,
|
|
|
|
pub(crate) server_provider: Arc<ServerProvider>,
|
2024-06-20 07:44:57 +08:00
|
|
|
pub(crate) storage_manager: Arc<StorageManager>,
|
2024-07-22 09:43:48 +02:00
|
|
|
pub(crate) chat_manager: Arc<ChatManager>,
|
2023-10-02 09:12:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl UserStatusCallback for UserStatusCallbackImpl {
|
|
|
|
fn did_init(
|
|
|
|
&self,
|
|
|
|
user_id: i64,
|
2023-12-30 07:05:26 +08:00
|
|
|
user_authenticator: &Authenticator,
|
2023-10-02 09:12:24 +02:00
|
|
|
cloud_config: &Option<UserCloudConfig>,
|
|
|
|
user_workspace: &UserWorkspace,
|
|
|
|
_device_id: &str,
|
|
|
|
) -> Fut<FlowyResult<()>> {
|
|
|
|
let user_id = user_id.to_owned();
|
|
|
|
let user_workspace = user_workspace.clone();
|
|
|
|
let folder_manager = self.folder_manager.clone();
|
|
|
|
let database_manager = self.database_manager.clone();
|
|
|
|
let document_manager = self.document_manager.clone();
|
|
|
|
|
2023-12-30 07:05:26 +08:00
|
|
|
self
|
|
|
|
.server_provider
|
|
|
|
.set_user_authenticator(user_authenticator);
|
|
|
|
|
2023-10-02 09:12:24 +02:00
|
|
|
if let Some(cloud_config) = cloud_config {
|
|
|
|
self
|
|
|
|
.server_provider
|
|
|
|
.set_enable_sync(user_id, cloud_config.enable_sync);
|
2023-11-17 15:38:56 +08:00
|
|
|
if cloud_config.enable_encrypt {
|
2023-10-02 09:12:24 +02:00
|
|
|
self
|
|
|
|
.server_provider
|
|
|
|
.set_encrypt_secret(cloud_config.encrypt_secret.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
to_fut(async move {
|
|
|
|
folder_manager
|
|
|
|
.initialize(
|
|
|
|
user_id,
|
|
|
|
&user_workspace.id,
|
2023-11-05 14:00:24 +08:00
|
|
|
FolderInitDataSource::LocalDisk {
|
2023-10-02 09:12:24 +02:00
|
|
|
create_if_not_exist: false,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.await?;
|
2024-04-26 09:44:07 +08:00
|
|
|
database_manager.initialize(user_id).await?;
|
|
|
|
document_manager.initialize(user_id).await?;
|
2023-10-02 09:12:24 +02:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn did_sign_in(
|
|
|
|
&self,
|
|
|
|
user_id: i64,
|
|
|
|
user_workspace: &UserWorkspace,
|
2023-11-05 14:00:24 +08:00
|
|
|
device_id: &str,
|
2023-10-02 09:12:24 +02:00
|
|
|
) -> Fut<FlowyResult<()>> {
|
2023-11-05 14:00:24 +08:00
|
|
|
let device_id = device_id.to_owned();
|
2023-10-02 09:12:24 +02:00
|
|
|
let user_id = user_id.to_owned();
|
|
|
|
let user_workspace = user_workspace.clone();
|
|
|
|
let folder_manager = self.folder_manager.clone();
|
|
|
|
let database_manager = self.database_manager.clone();
|
|
|
|
let document_manager = self.document_manager.clone();
|
|
|
|
|
|
|
|
to_fut(async move {
|
2023-11-05 14:00:24 +08:00
|
|
|
event!(
|
|
|
|
tracing::Level::TRACE,
|
|
|
|
"Notify did sign in: latest_workspace: {:?}, device_id: {}",
|
|
|
|
user_workspace,
|
|
|
|
device_id
|
|
|
|
);
|
|
|
|
|
2024-04-26 09:44:07 +08:00
|
|
|
folder_manager.initialize_with_workspace_id(user_id).await?;
|
|
|
|
database_manager.initialize(user_id).await?;
|
|
|
|
document_manager.initialize(user_id).await?;
|
2023-10-02 09:12:24 +02:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn did_sign_up(
|
|
|
|
&self,
|
|
|
|
is_new_user: bool,
|
|
|
|
user_profile: &UserProfile,
|
|
|
|
user_workspace: &UserWorkspace,
|
2023-11-05 14:00:24 +08:00
|
|
|
device_id: &str,
|
2023-10-02 09:12:24 +02:00
|
|
|
) -> Fut<FlowyResult<()>> {
|
2023-11-05 14:00:24 +08:00
|
|
|
let device_id = device_id.to_owned();
|
2023-10-02 09:12:24 +02:00
|
|
|
let user_profile = user_profile.clone();
|
|
|
|
let folder_manager = self.folder_manager.clone();
|
|
|
|
let database_manager = self.database_manager.clone();
|
|
|
|
let user_workspace = user_workspace.clone();
|
|
|
|
let document_manager = self.document_manager.clone();
|
2023-12-30 07:05:26 +08:00
|
|
|
self
|
|
|
|
.server_provider
|
|
|
|
.set_user_authenticator(&user_profile.authenticator);
|
2023-12-29 15:03:24 +08:00
|
|
|
let server_type = self.server_provider.get_server_type();
|
2023-10-02 09:12:24 +02:00
|
|
|
|
|
|
|
to_fut(async move {
|
2023-11-05 14:00:24 +08:00
|
|
|
event!(
|
|
|
|
tracing::Level::TRACE,
|
|
|
|
"Notify did sign up: is new: {} user_workspace: {:?}, device_id: {}",
|
|
|
|
is_new_user,
|
|
|
|
user_workspace,
|
|
|
|
device_id
|
|
|
|
);
|
|
|
|
|
2023-11-28 15:49:47 -08:00
|
|
|
// 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 folder_manager
|
|
|
|
.cloud_service
|
2024-02-04 05:49:45 +08:00
|
|
|
.get_folder_doc_state(
|
2023-12-29 13:02:27 +08:00
|
|
|
&user_workspace.id,
|
|
|
|
user_profile.uid,
|
|
|
|
CollabType::Folder,
|
|
|
|
&user_workspace.id,
|
|
|
|
)
|
2023-11-28 15:49:47 -08:00
|
|
|
.await
|
|
|
|
{
|
2023-12-29 15:03:24 +08:00
|
|
|
Ok(doc_state) => match server_type {
|
|
|
|
Server::Local => FolderInitDataSource::LocalDisk {
|
|
|
|
create_if_not_exist: true,
|
|
|
|
},
|
|
|
|
Server::AppFlowyCloud => FolderInitDataSource::Cloud(doc_state),
|
|
|
|
Server::Supabase => {
|
|
|
|
if is_new_user {
|
|
|
|
FolderInitDataSource::LocalDisk {
|
|
|
|
create_if_not_exist: true,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FolderInitDataSource::Cloud(doc_state)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
2024-02-08 23:53:05 +08:00
|
|
|
Err(err) => match server_type {
|
|
|
|
Server::Local => FolderInitDataSource::LocalDisk {
|
|
|
|
create_if_not_exist: true,
|
|
|
|
},
|
|
|
|
Server::AppFlowyCloud | Server::Supabase => {
|
|
|
|
return Err(FlowyError::from(err));
|
|
|
|
},
|
2023-11-28 15:49:47 -08:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-10-02 09:12:24 +02:00
|
|
|
folder_manager
|
|
|
|
.initialize_with_new_user(
|
|
|
|
user_profile.uid,
|
|
|
|
&user_profile.token,
|
|
|
|
is_new_user,
|
2023-11-28 15:49:47 -08:00
|
|
|
data_source,
|
2023-10-02 09:12:24 +02:00
|
|
|
&user_workspace.id,
|
|
|
|
)
|
2023-10-07 09:58:44 +08:00
|
|
|
.await
|
|
|
|
.context("FolderManager error")?;
|
|
|
|
|
2023-10-02 09:12:24 +02:00
|
|
|
database_manager
|
2024-04-26 09:44:07 +08:00
|
|
|
.initialize_with_new_user(user_profile.uid)
|
2023-10-07 09:58:44 +08:00
|
|
|
.await
|
|
|
|
.context("DatabaseManager error")?;
|
2023-10-02 09:12:24 +02:00
|
|
|
|
|
|
|
document_manager
|
2024-04-26 09:44:07 +08:00
|
|
|
.initialize_with_new_user(user_profile.uid)
|
2023-10-07 09:58:44 +08:00
|
|
|
.await
|
|
|
|
.context("DocumentManager error")?;
|
2023-10-02 09:12:24 +02:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn did_expired(&self, _token: &str, user_id: i64) -> Fut<FlowyResult<()>> {
|
|
|
|
let folder_manager = self.folder_manager.clone();
|
|
|
|
to_fut(async move {
|
|
|
|
folder_manager.clear(user_id).await;
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-04-26 09:44:07 +08:00
|
|
|
fn open_workspace(&self, user_id: i64, _user_workspace: &UserWorkspace) -> Fut<FlowyResult<()>> {
|
2023-10-02 09:12:24 +02:00
|
|
|
let folder_manager = self.folder_manager.clone();
|
|
|
|
let database_manager = self.database_manager.clone();
|
|
|
|
let document_manager = self.document_manager.clone();
|
|
|
|
|
|
|
|
to_fut(async move {
|
2024-04-26 09:44:07 +08:00
|
|
|
folder_manager.initialize_with_workspace_id(user_id).await?;
|
|
|
|
database_manager.initialize(user_id).await?;
|
|
|
|
document_manager.initialize(user_id).await?;
|
2023-10-02 09:12:24 +02:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn did_update_network(&self, reachable: bool) {
|
2024-06-20 07:44:57 +08:00
|
|
|
trace!("Notify did update network: reachable: {}", reachable);
|
2023-10-02 09:12:24 +02:00
|
|
|
self.collab_builder.update_network(reachable);
|
2024-06-20 07:44:57 +08:00
|
|
|
self.storage_manager.update_network_reachable(reachable);
|
2023-10-02 09:12:24 +02:00
|
|
|
}
|
2024-07-22 09:43:48 +02:00
|
|
|
|
|
|
|
fn did_update_plans(&self, plans: Vec<SubscriptionPlan>) {
|
|
|
|
let mut storage_plan_changed = false;
|
|
|
|
let mut local_ai_enabled = false;
|
|
|
|
for plan in &plans {
|
|
|
|
match plan {
|
|
|
|
SubscriptionPlan::Pro | SubscriptionPlan::Team => storage_plan_changed = true,
|
|
|
|
SubscriptionPlan::AiLocal => local_ai_enabled = true,
|
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if storage_plan_changed {
|
|
|
|
self.storage_manager.enable_storage_write_access();
|
|
|
|
}
|
|
|
|
|
|
|
|
if local_ai_enabled {
|
|
|
|
self.chat_manager.local_ai_purchased();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn did_update_storage_limitation(&self, can_write: bool) {
|
|
|
|
if can_write {
|
|
|
|
self.storage_manager.enable_storage_write_access();
|
|
|
|
} else {
|
|
|
|
self.storage_manager.disable_storage_write_access();
|
|
|
|
}
|
|
|
|
}
|
2023-10-02 09:12:24 +02:00
|
|
|
}
|