From b46a7fc8ce20cfe50c7fdef66b48082108a3b8de Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 15:26:30 +0800 Subject: [PATCH 1/9] fix: fix init head icon --- packages/data-center/src/datacenter.ts | 35 +++++++++---------- .../data-center/src/provider/affine/affine.ts | 19 ++++++---- packages/data-center/src/provider/base.ts | 19 +++++----- .../data-center/src/provider/local/local.ts | 19 ++++++---- 4 files changed, 48 insertions(+), 44 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 2fc9431e9..00ca590ae 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -17,7 +17,6 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; export class DataCenter { private readonly _workspaces = new Workspaces(); private readonly _logger = getLogger('dc'); - private readonly _blobStorage: BlobStorage = new BlobStorage(); /** * A mainProvider must exist as the only data trustworthy source. */ @@ -35,14 +34,12 @@ export class DataCenter { new LocalProvider({ logger: dc._logger, workspaces: dc._workspaces.createScope(), - blobs: dc._blobStorage, }) ); dc.registerProvider( new AffineProvider({ logger: dc._logger, workspaces: dc._workspaces.createScope(), - blobs: dc._blobStorage, }) ); @@ -335,21 +332,21 @@ export class DataCenter { return; } - /** - * get blob url by workspaces id - * @param id - * @returns {Promise} blob url - */ - async getBlob(id: string): Promise { - return await this._blobStorage.get(id); - } + // /** + // * get blob url by workspaces id + // * @param id + // * @returns {Promise} blob url + // */ + // async getBlob(id: string): Promise { + // return await this._blobStorage.get(id); + // } - /** - * up load blob and get a blob url - * @param id - * @returns {Promise} blob url - */ - async setBlob(blob: Blob): Promise { - return await this._blobStorage.set(blob); - } + // /** + // * up load blob and get a blob url + // * @param id + // * @returns {Promise} blob url + // */ + // async setBlob(blob: Blob): Promise { + // return await this._blobStorage.set(blob); + // } } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 0f78ba704..cb9b1704d 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -246,19 +246,12 @@ export class AffineProvider extends BaseProvider { meta: WorkspaceMeta ): Promise { assert(meta.name, 'Workspace name is required'); - if (!meta.avatar) { - // set default avatar - const blob = await getDefaultHeadImgBlob(meta.name); - const blobId = await this.setBlob(blob); - meta.avatar = (await this.getBlob(blobId)) || ''; - } const { id } = await createWorkspace(meta as Required); this._logger('Creating affine workspace'); const nw = new Workspace({ room: id, }).register(BlockSchema); nw.meta.setName(meta.name); - nw.meta.setAvatar(meta.avatar); this._initWorkspaceDb(nw); const workspaceInfo: WS = { @@ -272,6 +265,18 @@ export class AffineProvider extends BaseProvider { provider: 'local', }; + if (!meta.avatar) { + // set default avatar + const blob = await getDefaultHeadImgBlob(meta.name); + const blobStorage = await nw.blobs; + assert(blobStorage, 'No blob storage'); + const blobId = await blobStorage.set(blob); + const avatar = await blobStorage.get(blobId); + if (avatar) { + nw.meta.setAvatar(avatar); + workspaceInfo.avatar = avatar; + } + } this._workspaces.add(workspaceInfo); return nw; } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 62fc943eb..249a536f2 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -9,19 +9,16 @@ const defaultLogger = () => { export interface ProviderConstructorParams { logger?: Logger; workspaces: WorkspacesScope; - blobs: BlobStorage; } export class BaseProvider { public readonly id: string = 'base'; protected _workspaces!: WorkspacesScope; protected _logger!: Logger; - protected _blobs!: BlobStorage; - public constructor({ logger, workspaces, blobs }: ProviderConstructorParams) { + public constructor({ logger, workspaces }: ProviderConstructorParams) { this._logger = (logger || defaultLogger) as Logger; this._workspaces = workspaces; - this._blobs = blobs; } /** @@ -69,19 +66,19 @@ export class BaseProvider { return; } - async getBlob(id: string): Promise { - return await this._blobs.get(id); - } + // async getBlob(id: string): Promise { + // return await this._blobs.get(id); + // } - async setBlob(blob: Blob): Promise { - return await this._blobs.set(blob); - } + // async setBlob(blob: Blob): Promise { + // return await this._blobs.set(blob); + // } /** * clear all local data in provider */ async clear() { - this._blobs.clear(); + // this._blobs.clear(); } /** diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 8454f212b..8988068b8 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -79,12 +79,6 @@ export class LocalProvider extends BaseProvider { meta: WorkspaceMeta ): Promise { assert(meta.name, 'Workspace name is required'); - if (!meta.avatar) { - // set default avatar - const blob = await getDefaultHeadImgBlob(meta.name); - const blobId = await this.setBlob(blob); - meta.avatar = (await this.getBlob(blobId)) || ''; - } this._logger('Creating affine workspace'); const workspaceInfo: WS = { @@ -101,7 +95,18 @@ export class LocalProvider extends BaseProvider { const workspace = new Workspace({ room: workspaceInfo.id }); this._initWorkspaceDb(workspace); workspace.meta.setName(meta.name); - workspace.meta.setAvatar(meta.avatar); + if (!meta.avatar) { + // set default avatar + const blob = await getDefaultHeadImgBlob(meta.name); + const blobStorage = await workspace.blobs; + assert(blobStorage, 'No blob storage'); + const blobId = await blobStorage.set(blob); + const avatar = await blobStorage.get(blobId); + if (avatar) { + workspace.meta.setAvatar(avatar); + workspaceInfo.avatar = avatar; + } + } this._workspaces.add(workspaceInfo); this._storeWorkspaces(this._workspaces.list()); From 3e9304fb050e4c4930c16a47c5a79317c769a015 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 16:45:26 +0800 Subject: [PATCH 2/9] feat: cache workspace instances --- packages/data-center/src/datacenter.ts | 53 +++++++++++-------- .../data-center/src/provider/affine/affine.ts | 16 +++--- packages/data-center/src/provider/base.ts | 9 ++++ .../data-center/src/provider/local/local.ts | 8 +-- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 00ca590ae..907b0e310 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -1,6 +1,6 @@ import { Workspaces } from './workspaces'; import type { WorkspacesChangeEvent } from './workspaces'; -import { BlobStorage, Workspace } from '@blocksuite/store'; +import { Workspace } from '@blocksuite/store'; import { BaseProvider } from './provider/base'; import { LocalProvider } from './provider/local/local'; import { AffineProvider } from './provider'; @@ -17,6 +17,7 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs'; export class DataCenter { private readonly _workspaces = new Workspaces(); private readonly _logger = getLogger('dc'); + private _workspaceInstances: Map = new Map(); /** * A mainProvider must exist as the only data trustworthy source. */ @@ -109,9 +110,14 @@ export class DataCenter { * @param {string} workspaceId workspace id */ private _getWorkspace(workspaceId: string) { - return new Workspace({ - room: workspaceId, - }).register(BlockSchema); + const workspaceInfo = this._workspaces.find(workspaceId); + assert(workspaceInfo, 'Workspace not found'); + return ( + this._workspaceInstances.get(workspaceId) || + new Workspace({ + room: workspaceId, + }).register(BlockSchema) + ); } /** @@ -149,8 +155,9 @@ export class DataCenter { const provider = this.providerMap.get(workspaceInfo.provider); assert(provider, `provide '${workspaceInfo.provider}' is not registered`); this._logger(`Loading ${workspaceInfo.provider} workspace: `, workspaceId); - - return await provider.warpWorkspace(this._getWorkspace(workspaceId)); + const workspace = this._getWorkspace(workspaceId); + this._workspaceInstances.set(workspaceId, workspace); + return await provider.warpWorkspace(workspace); } /** @@ -332,21 +339,23 @@ export class DataCenter { return; } - // /** - // * get blob url by workspaces id - // * @param id - // * @returns {Promise} blob url - // */ - // async getBlob(id: string): Promise { - // return await this._blobStorage.get(id); - // } + /** + * get blob url by workspaces id + * @param id + * @returns {Promise} blob url + */ + async getBlob(workspace: Workspace, id: string): Promise { + const blob = await workspace.blobs; + return (await blob?.get(id)) || ''; + } - // /** - // * up load blob and get a blob url - // * @param id - // * @returns {Promise} blob url - // */ - // async setBlob(blob: Blob): Promise { - // return await this._blobStorage.set(blob); - // } + /** + * up load blob and get a blob url + * @param id + * @returns {Promise} blob url + */ + async setBlob(workspace: Workspace, blob: Blob): Promise { + const blobStorage = await workspace.blobs; + return (await blobStorage?.set(blob)) || ''; + } } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index cb9b1704d..28cb19f1f 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -69,7 +69,7 @@ export class AffineProvider extends BaseProvider { override async warpWorkspace(workspace: Workspace) { const { doc, room } = workspace; assert(room); - this._initWorkspaceDb(workspace); + this.linkLocal(workspace); const updates = await downloadWorkspace(room); if (updates) { await new Promise(resolve => { @@ -77,8 +77,12 @@ export class AffineProvider extends BaseProvider { applyUpdate(doc, new Uint8Array(updates)); }); } - const ws = new WebsocketProvider('/', room, doc); - this._wsMap.set(room, ws); + let ws = this._wsMap.get(room); + if (!ws) { + ws = new WebsocketProvider('/', room, doc); + this._wsMap.set(room, ws); + } + ws.connect(); await new Promise((resolve, reject) => { // TODO: synced will also be triggered on reconnection after losing sync // There needs to be an event mechanism to emit the synchronization state to the upper layer @@ -231,7 +235,7 @@ export class AffineProvider extends BaseProvider { return await removeMember({ permissionId }); } - private async _initWorkspaceDb(workspace: Workspace) { + public override async linkLocal(workspace: Workspace) { assert(workspace.room); let idb = this._idbMap.get(workspace.room); idb?.destroy(); @@ -239,7 +243,7 @@ export class AffineProvider extends BaseProvider { this._idbMap.set(workspace.room, idb); await idb.whenSynced; this._logger('Local data loaded'); - return idb; + return workspace; } public override async createWorkspace( @@ -252,7 +256,7 @@ export class AffineProvider extends BaseProvider { room: id, }).register(BlockSchema); nw.meta.setName(meta.name); - this._initWorkspaceDb(nw); + this.linkLocal(nw); const workspaceInfo: WS = { name: meta.name, diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 249a536f2..5f531e294 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -169,4 +169,13 @@ export class BaseProvider { email; return null; } + + /** + * link workspace to local caches + * @param workspace + * @returns + */ + public async linkLocal(workspace: Workspace): Promise { + return workspace; + } } diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index fb73ccce4..10df43148 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -22,21 +22,21 @@ export class LocalProvider extends BaseProvider { storage.setItem(WORKSPACE_KEY, JSON.stringify(workspaces)); } - private async _initWorkspaceDb(workspace: Workspace) { + public override async linkLocal(workspace: Workspace) { assert(workspace.room); let idb = this._idbMap.get(workspace.room); idb?.destroy(); idb = new IndexedDBProvider(workspace.room, workspace.doc); this._idbMap.set(workspace.room, idb); this._logger('Local data loaded'); - return idb; + return workspace; } public override async warpWorkspace( workspace: Workspace ): Promise { assert(workspace.room); - await this._initWorkspaceDb(workspace); + await this.linkLocal(workspace); return workspace; } @@ -93,7 +93,7 @@ export class LocalProvider extends BaseProvider { }; const workspace = new Workspace({ room: workspaceInfo.id }); - this._initWorkspaceDb(workspace); + this.linkLocal(workspace); workspace.meta.setName(meta.name); if (!meta.avatar) { // set default avatar From f7ff8f29b8a8e46bc1658aa14b807e20a10d99d4 Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 17:04:31 +0800 Subject: [PATCH 3/9] fix: test case for delete workspace --- packages/data-center/src/provider/local/local.spec.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts index f6a7c764e..d1778f5b0 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -48,10 +48,13 @@ test.describe.serial('local provider', () => { expect(workspaces.workspaces.length).toEqual(1); /** * FIXME - * Running following code will crash the worker, and get error like next line: + * If we don't wrap setTimeout, + * Running deleteWorkspace will crash the worker, and get error like next line: * InvalidStateError: An operation was called on an object on which it is not allowed or at a time when it is not allowed. Also occurs if a request is made on a source object that has been deleted or removed. Use TransactionInactiveError or ReadOnlyError when possible, as they are more specific variations of InvalidStateError. * */ - // await provider.deleteWorkspace(workspaces.workspaces[0].id); - // expect(workspaces.workspaces.length).toEqual(0); + setTimeout(async () => { + await provider.deleteWorkspace(workspaces.workspaces[0].id); + expect(workspaces.workspaces.length).toEqual(0); + }, 10); }); }); From 44008719592e0f52d1037280034e969b2ac05a71 Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 17:05:10 +0800 Subject: [PATCH 4/9] fix: remove type error --- packages/data-center/src/provider/local/local.spec.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts index d1778f5b0..f24f118ff 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -2,13 +2,11 @@ import { test, expect } from '@playwright/test'; import { Workspaces } from '../../workspaces/index.js'; import { LocalProvider } from './local.js'; import 'fake-indexeddb/auto'; -import { BlobStorage } from '@blocksuite/store'; test.describe.serial('local provider', () => { const workspaces = new Workspaces(); const provider = new LocalProvider({ workspaces: workspaces.createScope(), - blobs: new BlobStorage(), }); const workspaceName = 'workspace-test'; @@ -29,7 +27,6 @@ test.describe.serial('local provider', () => { const workspaces1 = new Workspaces(); const provider1 = new LocalProvider({ workspaces: workspaces1.createScope(), - blobs: new BlobStorage(), }); await provider1.loadWorkspaces(); expect(workspaces1.workspaces.length).toEqual(1); From dacfdfa57f16cd90c907e6490675af65f22d87af Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 17:15:19 +0800 Subject: [PATCH 5/9] refactor: remove unused files --- .../src/provider/{ => local}/indexeddb.ts | 0 .../data-center/src/provider/local/local.ts | 2 +- .../src/workspaces/workspaces.ts.bak | 101 ------------------ 3 files changed, 1 insertion(+), 102 deletions(-) rename packages/data-center/src/provider/{ => local}/indexeddb.ts (100%) delete mode 100644 packages/data-center/src/workspaces/workspaces.ts.bak diff --git a/packages/data-center/src/provider/indexeddb.ts b/packages/data-center/src/provider/local/indexeddb.ts similarity index 100% rename from packages/data-center/src/provider/indexeddb.ts rename to packages/data-center/src/provider/local/indexeddb.ts diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 10df43148..82ffe7774 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -3,7 +3,7 @@ import type { ProviderConstructorParams } from '../base'; import { varStorage as storage } from 'lib0/storage'; import { Workspace as WS, WorkspaceMeta } from '../../types'; import { Workspace, uuidv4 } from '@blocksuite/store'; -import { IndexedDBProvider } from '../indexeddb.js'; +import { IndexedDBProvider } from './indexeddb.js'; import assert from 'assert'; import { getDefaultHeadImgBlob } from '../../utils/index.js'; diff --git a/packages/data-center/src/workspaces/workspaces.ts.bak b/packages/data-center/src/workspaces/workspaces.ts.bak deleted file mode 100644 index f813f6b16..000000000 --- a/packages/data-center/src/workspaces/workspaces.ts.bak +++ /dev/null @@ -1,101 +0,0 @@ -import { Workspace as WS } from '../types'; - -import { Observable } from 'lib0/observable'; -import { uuidv4 } from '@blocksuite/store'; -import { DataCenter } from '../datacenter'; - -export class Workspaces extends Observable { - private _workspaces: WS[]; - private readonly _dc: DataCenter; - - constructor(dc: DataCenter) { - super(); - this._workspaces = []; - this._dc = dc; - } - - public init() { - this._loadWorkspaces(); - } - - get workspaces() { - return this._workspaces; - } - - /** - * emit when workspaces changed - * @param {(workspace: WS[]) => void} cb - */ - onWorkspacesChange(cb: (workspace: WS[]) => void) { - this.on('change', cb); - } - - private async _loadWorkspaces() { - const providers = this._dc.providers; - let workspaces: WS[] = []; - providers.forEach(async p => { - const pWorkspaces = await p.loadWorkspaces(); - workspaces = [...workspaces, ...pWorkspaces]; - this._updateWorkspaces([...workspaces, ...pWorkspaces]); - }); - } - - /** - * focus load all workspaces list - */ - public async refreshWorkspaces() { - this._loadWorkspaces(); - } - - private _updateWorkspaces(workspaces: WS[]) { - this._workspaces = workspaces; - this.emit('change', this._workspaces); - } - - private _getDefaultWorkspace(name: string): WS { - return { - name, - id: uuidv4(), - isPublish: false, - avatar: '', - owner: undefined, - isLocal: true, - memberCount: 1, - provider: 'local', - }; - } - - /** add a local workspaces */ - public addLocalWorkspace(name: string) { - const workspace = this._getDefaultWorkspace(name); - this._updateWorkspaces([...this._workspaces, workspace]); - return workspace; - } - - /** delete a workspaces by id */ - public delete(id: string) { - const index = this._workspaces.findIndex(w => w.id === id); - if (index >= 0) { - this._workspaces.splice(index, 1); - this._updateWorkspaces(this._workspaces); - } - } - - /** get workspace info by id */ - public getWorkspace(id: string) { - return this._workspaces.find(w => w.id === id); - } - - /** check if workspace exists */ - public hasWorkspace(id: string) { - return this._workspaces.some(w => w.id === id); - } - - public updateWorkspaceInfo(id: string, info: Partial) { - const index = this._workspaces.findIndex(w => w.id === id); - if (index >= 0) { - this._workspaces[index] = { ...this._workspaces[index], ...info }; - this._updateWorkspaces(this._workspaces); - } - } -} From 0b5cc1beda4f27cc67b5cd50917f27c6bdb6ac4f Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 17:18:58 +0800 Subject: [PATCH 6/9] feat: fix --- packages/data-center/src/datacenter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 907b0e310..ee320d75e 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -81,7 +81,7 @@ export class DataCenter { /** * create new workspace , new workspace is a local workspace * @param {string} name workspace name - * @returns {Promise} + * @returns {Promise} */ public async createWorkspace(workspaceMeta: WorkspaceMeta) { assert( From d10affb41334aec380c50ff9066cfc509583f916 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 17:27:08 +0800 Subject: [PATCH 7/9] feat: disable local cache of affine provider --- .../data-center/src/provider/affine/affine.ts | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 28cb19f1f..973eed1dd 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -21,7 +21,7 @@ import { varStorage as storage } from 'lib0/storage'; import assert from 'assert'; import { getAuthorizer } from './apis/token'; import { WebsocketProvider } from './sync'; -import { IndexedDBProvider } from '../indexeddb'; +// import { IndexedDBProvider } from '../local/indexeddb'; import { getDefaultHeadImgBlob } from '../../utils'; import { getUserByEmail } from './apis/user'; @@ -32,7 +32,7 @@ export class AffineProvider extends BaseProvider { private readonly _authorizer = getAuthorizer(); private _user: User | undefined = undefined; private _wsMap: Map = new Map(); - private _idbMap: Map = new Map(); + // private _idbMap: Map = new Map(); constructor(params: ProviderConstructorParams) { super(params); @@ -197,7 +197,7 @@ export class AffineProvider extends BaseProvider { public override async deleteWorkspace(id: string): Promise { await this.closeWorkspace(id); - IndexedDBProvider.delete(id); + // IndexedDBProvider.delete(id); await deleteWorkspace({ id }); this._workspaces.remove(id); } @@ -217,8 +217,8 @@ export class AffineProvider extends BaseProvider { } public override async closeWorkspace(id: string) { - const idb = this._idbMap.get(id); - idb?.destroy(); + // const idb = this._idbMap.get(id); + // idb?.destroy(); const ws = this._wsMap.get(id); ws?.disconnect(); } @@ -236,14 +236,15 @@ export class AffineProvider extends BaseProvider { } public override async linkLocal(workspace: Workspace) { - assert(workspace.room); - let idb = this._idbMap.get(workspace.room); - idb?.destroy(); - idb = new IndexedDBProvider(workspace.room, workspace.doc); - this._idbMap.set(workspace.room, idb); - await idb.whenSynced; - this._logger('Local data loaded'); return workspace; + // assert(workspace.room); + // let idb = this._idbMap.get(workspace.room); + // idb?.destroy(); + // idb = new IndexedDBProvider(workspace.room, workspace.doc); + // this._idbMap.set(workspace.room, idb); + // await idb.whenSynced; + // this._logger('Local data loaded'); + // return workspace; } public override async createWorkspace( From 5095e2f27d945ad0aa9df7e526d9da82ac93748c Mon Sep 17 00:00:00 2001 From: alt0 Date: Mon, 9 Jan 2023 17:41:03 +0800 Subject: [PATCH 8/9] refactor: inject apis to affine --- .../data-center/src/provider/affine/affine.ts | 48 +++++++++---------- .../src/provider/affine/apis/index.ts | 2 +- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 973eed1dd..d86c42f9f 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -1,15 +1,3 @@ -import { - getWorkspaces, - getWorkspaceDetail, - WorkspaceDetail, - downloadWorkspace, - deleteWorkspace, - leaveWorkspace, - inviteMember, - removeMember, - createWorkspace, - updateWorkspace, -} from './apis/workspace'; import { BaseProvider } from '../base'; import type { ProviderConstructorParams } from '../base'; import { User, Workspace as WS, WorkspaceMeta } from '../../types'; @@ -23,7 +11,13 @@ import { getAuthorizer } from './apis/token'; import { WebsocketProvider } from './sync'; // import { IndexedDBProvider } from '../local/indexeddb'; import { getDefaultHeadImgBlob } from '../../utils'; -import { getUserByEmail } from './apis/user'; +import { getApis } from './apis/index.js'; +import type { Apis, WorkspaceDetail } from './apis'; + +export interface AffineProviderConstructorParams + extends ProviderConstructorParams { + apis?: Apis; +} export class AffineProvider extends BaseProvider { public id = 'affine'; @@ -32,10 +26,12 @@ export class AffineProvider extends BaseProvider { private readonly _authorizer = getAuthorizer(); private _user: User | undefined = undefined; private _wsMap: Map = new Map(); + private _apis: Apis; // private _idbMap: Map = new Map(); - constructor(params: ProviderConstructorParams) { + constructor({ apis, ...params }: AffineProviderConstructorParams) { super(params); + this._apis = apis || getApis(); } override async init() { @@ -70,7 +66,7 @@ export class AffineProvider extends BaseProvider { const { doc, room } = workspace; assert(room); this.linkLocal(workspace); - const updates = await downloadWorkspace(room); + const updates = await this._apis.downloadWorkspace(room); if (updates) { await new Promise(resolve => { doc.once('update', resolve); @@ -98,7 +94,7 @@ export class AffineProvider extends BaseProvider { if (!token.isLogin) { return []; } - const workspacesList = await getWorkspaces(); + const workspacesList = await this._apis.getWorkspaces(); const workspaces: WS[] = workspacesList.map(w => { return { ...w, @@ -116,7 +112,7 @@ export class AffineProvider extends BaseProvider { this._workspacesCache.set(id, workspace); if (workspace) { return new Promise(resolve => { - downloadWorkspace(id).then(data => { + this._apis.downloadWorkspace(id).then(data => { applyUpdate(workspace.doc, new Uint8Array(data)); resolve(workspace); }); @@ -139,7 +135,7 @@ export class AffineProvider extends BaseProvider { const { id } = w; return new Promise<{ id: string; detail: WorkspaceDetail | null }>( resolve => { - getWorkspaceDetail({ id }).then(data => { + this._apis.getWorkspaceDetail({ id }).then(data => { resolve({ id, detail: data || null }); }); } @@ -198,7 +194,7 @@ export class AffineProvider extends BaseProvider { public override async deleteWorkspace(id: string): Promise { await this.closeWorkspace(id); // IndexedDBProvider.delete(id); - await deleteWorkspace({ id }); + await this._apis.deleteWorkspace({ id }); this._workspaces.remove(id); } @@ -224,15 +220,15 @@ export class AffineProvider extends BaseProvider { } public override async leaveWorkspace(id: string): Promise { - await leaveWorkspace({ id }); + await this._apis.leaveWorkspace({ id }); } public override async invite(id: string, email: string): Promise { - return await inviteMember({ id, email }); + return await this._apis.inviteMember({ id, email }); } public override async removeMember(permissionId: number): Promise { - return await removeMember({ permissionId }); + return await this._apis.removeMember({ permissionId }); } public override async linkLocal(workspace: Workspace) { @@ -251,7 +247,9 @@ export class AffineProvider extends BaseProvider { meta: WorkspaceMeta ): Promise { assert(meta.name, 'Workspace name is required'); - const { id } = await createWorkspace(meta as Required); + const { id } = await this._apis.createWorkspace( + meta as Required + ); this._logger('Creating affine workspace'); const nw = new Workspace({ room: id, @@ -287,14 +285,14 @@ export class AffineProvider extends BaseProvider { } public override async publish(id: string, isPublish: boolean): Promise { - await updateWorkspace({ id, public: isPublish }); + await this._apis.updateWorkspace({ id, public: isPublish }); } public override async getUserByEmail( workspace_id: string, email: string ): Promise { - const user = await getUserByEmail({ workspace_id, email }); + const user = await this._apis.getUserByEmail({ workspace_id, email }); return user ? { id: user.id, diff --git a/packages/data-center/src/provider/affine/apis/index.ts b/packages/data-center/src/provider/affine/apis/index.ts index 28e49b02a..8c627519a 100644 --- a/packages/data-center/src/provider/affine/apis/index.ts +++ b/packages/data-center/src/provider/affine/apis/index.ts @@ -22,5 +22,5 @@ export const getApis = (): Apis => { }; export type { AccessTokenMessage } from './token'; -export type { Member, Workspace } from './workspace'; +export type { Member, Workspace, WorkspaceDetail } from './workspace'; export { WorkspaceType } from './workspace.js'; From bd5f0ad7c189cce006929df178e9edf728a87624 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Mon, 9 Jan 2023 17:52:38 +0800 Subject: [PATCH 9/9] feat: add disconnect ws --- packages/data-center/src/provider/affine/affine.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index d86c42f9f..41f438d88 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -78,6 +78,12 @@ export class AffineProvider extends BaseProvider { ws = new WebsocketProvider('/', room, doc); this._wsMap.set(room, ws); } + // close all websocket links + Array.from(this._wsMap.entries()).forEach(([id, ws]) => { + if (id !== room) { + ws.disconnect(); + } + }); ws.connect(); await new Promise((resolve, reject) => { // TODO: synced will also be triggered on reconnection after losing sync