123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- use crate::entities::workspace::*;
- use crate::manager::FolderManager;
- use crate::{
- errors::*,
- event_map::{FolderCouldServiceV1, WorkspaceUser},
- notification::*,
- services::{
- persistence::{FolderPersistence, FolderPersistenceTransaction, WorkspaceChangeset},
- read_workspace_apps, TrashController,
- },
- };
- use flowy_sqlite::kv::KV;
- use folder_model::{AppRevision, WorkspaceRevision};
- use lib_dispatch::prelude::ToBytes;
- use std::sync::Arc;
- pub struct WorkspaceController {
- pub user: Arc<dyn WorkspaceUser>,
- persistence: Arc<FolderPersistence>,
- pub(crate) trash_controller: Arc<TrashController>,
- cloud_service: Arc<dyn FolderCouldServiceV1>,
- }
- impl WorkspaceController {
- pub(crate) fn new(
- user: Arc<dyn WorkspaceUser>,
- persistence: Arc<FolderPersistence>,
- trash_can: Arc<TrashController>,
- cloud_service: Arc<dyn FolderCouldServiceV1>,
- ) -> Self {
- Self {
- user,
- persistence,
- trash_controller: trash_can,
- cloud_service,
- }
- }
- pub(crate) async fn create_workspace_from_params(
- &self,
- params: CreateWorkspaceParams,
- ) -> Result<WorkspaceRevision, FlowyError> {
- let workspace = self.create_workspace_on_server(params.clone()).await?;
- let user_id = self.user.user_id()?;
- let workspaces = self
- .persistence
- .begin_transaction(|transaction| {
- transaction.create_workspace(&user_id, workspace.clone())?;
- transaction.read_workspaces(&user_id, None)
- })
- .await?
- .into_iter()
- .map(|workspace_rev| workspace_rev.into())
- .collect();
- let repeated_workspace = RepeatedWorkspacePB { items: workspaces };
- send_workspace_notification(FolderNotification::DidCreateWorkspace, repeated_workspace);
- set_current_workspace(&user_id, &workspace.id);
- Ok(workspace)
- }
- #[allow(dead_code)]
- pub(crate) async fn update_workspace(
- &self,
- params: UpdateWorkspaceParams,
- ) -> Result<(), FlowyError> {
- let changeset = WorkspaceChangeset::new(params.clone());
- let workspace_id = changeset.id.clone();
- let workspace = self
- .persistence
- .begin_transaction(|transaction| {
- transaction.update_workspace(changeset)?;
- let user_id = self.user.user_id()?;
- self.read_workspace(workspace_id.clone(), &user_id, &transaction)
- })
- .await?;
- send_workspace_notification(FolderNotification::DidUpdateWorkspace, workspace);
- self.update_workspace_on_server(params)?;
- Ok(())
- }
- #[allow(dead_code)]
- pub(crate) async fn delete_workspace(&self, workspace_id: &str) -> Result<(), FlowyError> {
- let user_id = self.user.user_id()?;
- let repeated_workspace = self
- .persistence
- .begin_transaction(|transaction| {
- transaction.delete_workspace(workspace_id)?;
- self.read_workspaces(None, &user_id, &transaction)
- })
- .await?;
- send_workspace_notification(FolderNotification::DidDeleteWorkspace, repeated_workspace);
- self.delete_workspace_on_server(workspace_id)?;
- Ok(())
- }
- pub(crate) async fn open_workspace(
- &self,
- params: WorkspaceIdPB,
- ) -> Result<WorkspacePB, FlowyError> {
- let user_id = self.user.user_id()?;
- if let Some(workspace_id) = params.value {
- let workspace = self
- .persistence
- .begin_transaction(|transaction| self.read_workspace(workspace_id, &user_id, &transaction))
- .await?;
- set_current_workspace(&user_id, &workspace.id);
- Ok(workspace)
- } else {
- Err(FlowyError::workspace_id().context("Opened workspace id should not be empty"))
- }
- }
- pub(crate) async fn read_current_workspace_apps(&self) -> Result<Vec<AppRevision>, FlowyError> {
- let user_id = self.user.user_id()?;
- let workspace_id = get_current_workspace(&user_id)?;
- let app_revs = self
- .persistence
- .begin_transaction(|transaction| {
- read_workspace_apps(&workspace_id, self.trash_controller.clone(), &transaction)
- })
- .await?;
- // TODO: read from server
- Ok(app_revs)
- }
- #[tracing::instrument(level = "debug", skip(self, transaction), err)]
- pub(crate) fn read_workspaces<'a>(
- &self,
- workspace_id: Option<String>,
- user_id: &str,
- transaction: &'a (dyn FolderPersistenceTransaction + 'a),
- ) -> Result<RepeatedWorkspacePB, FlowyError> {
- let workspace_id = workspace_id.to_owned();
- let trash_ids = self.trash_controller.read_trash_ids(transaction)?;
- let workspaces = transaction
- .read_workspaces(user_id, workspace_id)?
- .into_iter()
- .map(|mut workspace_rev| {
- workspace_rev
- .apps
- .retain(|app_rev| !trash_ids.contains(&app_rev.id));
- workspace_rev.into()
- })
- .collect();
- Ok(RepeatedWorkspacePB { items: workspaces })
- }
- pub(crate) fn read_workspace<'a>(
- &self,
- workspace_id: String,
- user_id: &str,
- transaction: &'a (dyn FolderPersistenceTransaction + 'a),
- ) -> Result<WorkspacePB, FlowyError> {
- let mut workspaces = self
- .read_workspaces(Some(workspace_id.clone()), user_id, transaction)?
- .items;
- if workspaces.is_empty() {
- return Err(
- FlowyError::record_not_found().context(format!("{} workspace not found", workspace_id)),
- );
- }
- debug_assert_eq!(workspaces.len(), 1);
- let workspace = workspaces
- .drain(..1)
- .collect::<Vec<WorkspacePB>>()
- .pop()
- .unwrap();
- Ok(workspace)
- }
- }
- impl WorkspaceController {
- async fn create_workspace_on_server(
- &self,
- params: CreateWorkspaceParams,
- ) -> Result<WorkspaceRevision, FlowyError> {
- let token = self.user.token()?;
- self.cloud_service.create_workspace(&token, params).await
- }
- fn update_workspace_on_server(&self, params: UpdateWorkspaceParams) -> Result<(), FlowyError> {
- let (token, server) = (self.user.token()?, self.cloud_service.clone());
- tokio::spawn(async move {
- match server.update_workspace(&token, params).await {
- Ok(_) => {},
- Err(e) => {
- // TODO: retry?
- log::error!("Update workspace failed: {:?}", e);
- },
- }
- });
- Ok(())
- }
- fn delete_workspace_on_server(&self, workspace_id: &str) -> Result<(), FlowyError> {
- let params = WorkspaceIdPB {
- value: Some(workspace_id.to_string()),
- };
- let (token, server) = (self.user.token()?, self.cloud_service.clone());
- tokio::spawn(async move {
- match server.delete_workspace(&token, params).await {
- Ok(_) => {},
- Err(e) => {
- // TODO: retry?
- log::error!("Delete workspace failed: {:?}", e);
- },
- }
- });
- Ok(())
- }
- }
- pub async fn notify_workspace_setting_did_change(
- folder_manager: &Arc<FolderManager>,
- view_id: &str,
- ) -> FlowyResult<()> {
- let user_id = folder_manager.user.user_id()?;
- let workspace_id = get_current_workspace(&user_id)?;
- let workspace_setting = folder_manager
- .persistence
- .begin_transaction(|transaction| {
- let workspace = folder_manager.workspace_controller.read_workspace(
- workspace_id.clone(),
- &user_id,
- &transaction,
- )?;
- let setting = match transaction.read_view(view_id) {
- Ok(latest_view) => WorkspaceSettingPB {
- workspace,
- latest_view: Some(latest_view.into()),
- },
- Err(_) => WorkspaceSettingPB {
- workspace,
- latest_view: None,
- },
- };
- Ok(setting)
- })
- .await?;
- send_workspace_notification(
- FolderNotification::DidUpdateWorkspaceSetting,
- workspace_setting,
- );
- Ok(())
- }
- /// The [CURRENT_WORKSPACE] represents as the current workspace that opened by the
- /// user. Only one workspace can be opened at a time.
- const CURRENT_WORKSPACE: &str = "current-workspace";
- fn send_workspace_notification<T: ToBytes>(ty: FolderNotification, payload: T) {
- send_notification(CURRENT_WORKSPACE, ty)
- .payload(payload)
- .send();
- }
- const CURRENT_WORKSPACE_ID: &str = "current_workspace_id";
- pub fn set_current_workspace(_user_id: &str, workspace_id: &str) {
- KV::set_str(CURRENT_WORKSPACE_ID, workspace_id.to_owned());
- }
- pub fn clear_current_workspace(_user_id: &str) {
- let _ = KV::remove(CURRENT_WORKSPACE_ID);
- }
- pub fn get_current_workspace(_user_id: &str) -> Result<String, FlowyError> {
- match KV::get_str(CURRENT_WORKSPACE_ID) {
- None => Err(
- FlowyError::record_not_found()
- .context("Current workspace not found or should call open workspace first"),
- ),
- Some(workspace_id) => Ok(workspace_id),
- }
- }
|