diff --git a/client-app/src-tauri/src/commands.rs b/client-app/src-tauri/src/commands.rs index 4b1262854b..60ac58e04e 100644 --- a/client-app/src-tauri/src/commands.rs +++ b/client-app/src-tauri/src/commands.rs @@ -16,6 +16,7 @@ pub fn invoke_handler() -> impl Fn(tauri::Invoke) + Send + Sync + 'static { get_workspaces, get_workspace, create_user, + create_doc, get_doc, put_blob, get_blob diff --git a/client-app/src-tauri/src/commands/document.rs b/client-app/src-tauri/src/commands/document.rs index a28b9d4397..f34c350fa4 100644 --- a/client-app/src-tauri/src/commands/document.rs +++ b/client-app/src-tauri/src/commands/document.rs @@ -1,9 +1,44 @@ -use ipc_types::document::{GetDocumentParameter, GetDocumentResponse, YDocumentUpdate}; +use ipc_types::document::{ + CreateDocumentParameter, GetDocumentParameter, GetDocumentResponse, YDocumentUpdate, +}; use jwst::DocStorage; +use jwst::Workspace as OctoBaseWorkspace; +use lib0::any::Any; use yrs::StateVector; use crate::state::AppState; +#[tauri::command] +/// get yDoc created by create_workspace, using same id +pub async fn create_doc<'s>( + state: tauri::State<'s, AppState>, + parameters: CreateDocumentParameter, +) -> Result<(), String> { + let workspace_doc = OctoBaseWorkspace::new(parameters.workspace_id.clone()); + + workspace_doc.with_trx(|mut workspace_doc_transaction| { + workspace_doc_transaction.set_metadata( + "name", + Any::String(parameters.workspace_name.clone().into_boxed_str()), + ); + }); + if let Err(error_message) = &state + .0 + .lock() + .await + .doc_storage + .write_doc(parameters.workspace_id.clone(), workspace_doc.doc()) + .await + { + Err(format!( + "Failed to write_doc during create_workspace with error {}", + error_message.to_string() + )) + } else { + Ok(()) + } +} + #[tauri::command] /// get yDoc created by create_workspace, using same id pub async fn get_doc<'s>( @@ -25,10 +60,7 @@ pub async fn get_doc<'s>( update: doc.encode_state_as_update_v1(&StateVector::default()), }) } else { - Err(format!( - "Failed to get yDoc from {}", - parameters.id - )) + Err(format!("Failed to get yDoc from {}", parameters.id)) } } @@ -48,9 +80,6 @@ pub async fn update_y_document<'s>( { Ok(true) } else { - Err(format!( - "Failed to update yDoc to {}", - parameters.id - )) + Err(format!("Failed to update yDoc to {}", parameters.id)) } } diff --git a/client-app/src-tauri/src/commands/user.rs b/client-app/src-tauri/src/commands/user.rs index 360fa35419..0eb83f9ab0 100644 --- a/client-app/src-tauri/src/commands/user.rs +++ b/client-app/src-tauri/src/commands/user.rs @@ -1,23 +1,38 @@ +use ipc_types::document::CreateDocumentParameter; use jwst_storage::{CreateUser, User}; use crate::state::AppState; +use super::document::create_doc; + #[tauri::command] -/// create yDoc for a workspace +/// create new user and a private workspace pub async fn create_user<'s>( state: tauri::State<'s, AppState>, parameters: CreateUser, ) -> Result { - match &state + let new_user_result = &state .0 .lock() .await .metadata_db .create_user(parameters.clone()) - .await - { + .await; + match new_user_result{ Ok(new_user_option) => match new_user_option { - Some(new_user) => Ok(new_user.clone()), + Some((new_user, new_workspace)) => { + // a new private workspace is created, we have to create a yDoc for it + create_doc( + state, + CreateDocumentParameter { + workspace_id: new_workspace.id.clone(), + workspace_name: parameters.name.clone(), + }, + ) + .await + .ok(); + Ok(new_user.clone()) + } None => Err("User creation failed".to_string()), }, Err(error_message) => Err(error_message.to_string()), diff --git a/client-app/src-tauri/src/commands/workspace.rs b/client-app/src-tauri/src/commands/workspace.rs index 77261de8e5..66173089b5 100644 --- a/client-app/src-tauri/src/commands/workspace.rs +++ b/client-app/src-tauri/src/commands/workspace.rs @@ -1,12 +1,15 @@ -use ipc_types::workspace::{ - CreateWorkspace, CreateWorkspaceResult, GetWorkspace, GetWorkspaceResult, GetWorkspaces, - GetWorkspacesResult, UpdateWorkspace, +use ipc_types::{ + document::CreateDocumentParameter, + workspace::{ + CreateWorkspace, CreateWorkspaceResult, GetWorkspace, GetWorkspaceResult, GetWorkspaces, + GetWorkspacesResult, UpdateWorkspace, + }, }; -use jwst::{DocStorage, Workspace as OctoBaseWorkspace}; -use lib0::any::Any; use crate::state::AppState; +use super::document::create_doc; + #[tauri::command] /// create yDoc for a workspace pub async fn get_workspaces<'s>( @@ -46,7 +49,7 @@ pub async fn get_workspace<'s>( Some(user_workspace) => Ok(GetWorkspaceResult { workspace: user_workspace.clone(), }), - None => Err("Get workspace has no result".to_string()) + None => Err("Get workspace has no result".to_string()), }, Err(error_message) => Err(error_message.to_string()), } @@ -58,40 +61,33 @@ pub async fn create_workspace<'s>( state: tauri::State<'s, AppState>, parameters: CreateWorkspace, ) -> Result { - match &state + let new_workspace_result = &state .0 .lock() .await .metadata_db .create_normal_workspace(parameters.user_id) - .await - { + .await; + match new_workspace_result { Ok(new_workspace) => { - let workspace_doc = OctoBaseWorkspace::new(new_workspace.id.clone()); - - workspace_doc.with_trx(|mut workspace_doc_transaction| { - workspace_doc_transaction.set_metadata( - "name", - Any::String(parameters.name.clone().into_boxed_str()), - ); - }); - if let Err(error_message) = &state - .0 - .lock() - .await - .doc_storage - .write_doc(new_workspace.id.clone(), workspace_doc.doc()) - .await - { - Err(error_message.to_string()) - } else { - Ok(CreateWorkspaceResult { - id: new_workspace.id.clone(), - name: parameters.name, - }) - } + create_doc( + state, + CreateDocumentParameter { + workspace_id: new_workspace.id.clone(), + workspace_name: parameters.name.clone(), + }, + ) + .await + .ok(); + Ok(CreateWorkspaceResult { + id: new_workspace.id.clone(), + name: parameters.name, + }) } - Err(error_message) => Err(error_message.to_string()), + Err(error_message) => Err(format!( + "Failed to create_workspace with error {}", + error_message.to_string() + )), } } diff --git a/client-app/src-tauri/types/src/document.rs b/client-app/src-tauri/types/src/document.rs index 99ebb9679f..50f8f5a509 100644 --- a/client-app/src-tauri/types/src/document.rs +++ b/client-app/src-tauri/types/src/document.rs @@ -12,6 +12,11 @@ pub struct GetDocumentParameter { pub id: String, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] +pub struct CreateDocumentParameter { + pub workspace_id: String, + pub workspace_name: String, +} +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct GetDocumentResponse { pub update: Vec, } @@ -19,6 +24,7 @@ pub struct GetDocumentResponse { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)] pub enum IDocumentParameters { YDocumentUpdate(YDocumentUpdate), + CreateDocumentParameter(CreateDocumentParameter), GetDocumentParameter(GetDocumentParameter), GetDocumentResponse(GetDocumentResponse), } diff --git a/packages/data-center/src/provider/tauri-ipc/index.ts b/packages/data-center/src/provider/tauri-ipc/index.ts index 95f44469d0..a53b48710d 100644 --- a/packages/data-center/src/provider/tauri-ipc/index.ts +++ b/packages/data-center/src/provider/tauri-ipc/index.ts @@ -11,21 +11,35 @@ import { import { BlockSchema } from '@blocksuite/blocks/models'; import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; import { IPCBlobProvider } from './blocksuite-provider/blob.js'; -import { WorkspaceDetail } from '../affine/apis/workspace.js'; +import type { WorkspaceDetail } from '../affine/apis/workspace.js'; import { setDefaultAvatar } from '../utils.js'; export class TauriIPCProvider extends LocalProvider { static id = 'tauri-ipc'; private _workspacesCache: Map = new Map(); + /** + * // TODO: We only have one user in this version of app client. But may support switch user later. + */ + #defaultUserID = 1; constructor(params: ProviderConstructorParams) { super(params); - // TODO: let blocksuite's blob provider get blob receive workspace id. Currently, all blobs are placed together - this.loadWorkspaces(); } async init() { - // nothing to init until load workspace + // we create a default user if we don't have one. + try { + const user = await ipcMethods.createUser({ + email: 'xxx@xx.xx', + name: 'xxx', + password: 'xxx', + avatar_url: '', + }); + this.#defaultUserID = user.id; + } catch (error) { + // maybe user existed, which can be omited + console.error(error); + } } async #initDocFromIPC(workspaceID: string, doc: Y.Doc) { @@ -70,7 +84,7 @@ export class TauriIPCProvider extends LocalProvider { const { id } = await ipcMethods.createWorkspace({ name: meta.name, // TODO: get userID here - user_id: 0, + user_id: this.#defaultUserID, }); const workspaceInfo: WorkspaceMeta0 = { @@ -104,8 +118,6 @@ export class TauriIPCProvider extends LocalProvider { assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); this._logger('Creating affine workspace'); - this.linkLocal(blocksuiteWorkspace); - const workspaceInfo: WorkspaceMeta0 = { name: meta.name, id: workspaceId, @@ -125,23 +137,8 @@ export class TauriIPCProvider extends LocalProvider { } override async loadWorkspaces() { - // TODO: get user id here - // try create a default user, otherwise getWorkspaces will failed due to user not exists - let createdUserID = 0; - try { - const user = await ipcMethods.createUser({ - email: 'xxx@xx.xx', - name: 'xxx', - password: 'xxx', - avatar_url: '', - }); - createdUserID = user.id; - } catch (error) { - // maybe user existed, which can be omited - console.error(error); - } const { workspaces: workspacesList } = await ipcMethods.getWorkspaces({ - user_id: createdUserID, + user_id: this.#defaultUserID, }); const workspaces: WorkspaceMeta0[] = workspacesList.map(w => { return { diff --git a/packages/data-center/src/provider/tauri-ipc/ipc/methods.ts b/packages/data-center/src/provider/tauri-ipc/ipc/methods.ts index 7eb1678533..f9f5982ceb 100644 --- a/packages/data-center/src/provider/tauri-ipc/ipc/methods.ts +++ b/packages/data-center/src/provider/tauri-ipc/ipc/methods.ts @@ -51,6 +51,10 @@ export const getBlob = async (parameters: GetBlob) => parameters, }); +/** + * This will create a private workspace too. + * @returns + */ export const createUser = async (parameters: CreateUser) => await invoke('create_user', { parameters,