refactor: move local workspace CRUD (#1778)
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
import { config } from '@affine/env';
|
import { config } from '@affine/env';
|
||||||
|
import {
|
||||||
|
createIndexedDBProvider,
|
||||||
|
createLocalProviders,
|
||||||
|
} from '@affine/workspace/providers';
|
||||||
|
import { createBroadCastChannelProvider } from '@affine/workspace/providers';
|
||||||
import type { Provider } from '@affine/workspace/type';
|
import type { Provider } from '@affine/workspace/type';
|
||||||
|
|
||||||
import type { BlockSuiteWorkspace } from '../shared';
|
import type { BlockSuiteWorkspace } from '../shared';
|
||||||
import {
|
import { createAffineWebSocketProvider } from './providers';
|
||||||
createAffineWebSocketProvider,
|
|
||||||
createBroadCastChannelProvider,
|
|
||||||
createIndexedDBProvider,
|
|
||||||
} from './providers';
|
|
||||||
import { createAffineDownloadProvider } from './providers/affine';
|
import { createAffineDownloadProvider } from './providers/affine';
|
||||||
|
|
||||||
export const createAffineProviders = (
|
export const createAffineProviders = (
|
||||||
@@ -24,15 +25,4 @@ export const createAffineProviders = (
|
|||||||
).filter(v => Boolean(v));
|
).filter(v => Boolean(v));
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createLocalProviders = (
|
export { createLocalProviders };
|
||||||
blockSuiteWorkspace: BlockSuiteWorkspace
|
|
||||||
): Provider[] => {
|
|
||||||
return (
|
|
||||||
[
|
|
||||||
config.enableBroadCastChannelProvider &&
|
|
||||||
createBroadCastChannelProvider(blockSuiteWorkspace),
|
|
||||||
config.enableIndexedDBProvider &&
|
|
||||||
createIndexedDBProvider(blockSuiteWorkspace),
|
|
||||||
] as any[]
|
|
||||||
).filter(v => Boolean(v));
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import { KeckProvider } from '@affine/workspace/affine/keck';
|
import { KeckProvider } from '@affine/workspace/affine/keck';
|
||||||
import { getLoginStorage } from '@affine/workspace/affine/login';
|
import { getLoginStorage } from '@affine/workspace/affine/login';
|
||||||
import type {
|
import type { AffineWebSocketProvider } from '@affine/workspace/type';
|
||||||
AffineWebSocketProvider,
|
|
||||||
LocalIndexedDBProvider,
|
|
||||||
} from '@affine/workspace/type';
|
|
||||||
import { assertExists } from '@blocksuite/store';
|
import { assertExists } from '@blocksuite/store';
|
||||||
import { IndexeddbPersistence } from 'y-indexeddb';
|
|
||||||
|
|
||||||
import type { BlockSuiteWorkspace } from '../../shared';
|
import type { BlockSuiteWorkspace } from '../../shared';
|
||||||
import { providerLogger } from '../logger';
|
import { providerLogger } from '../logger';
|
||||||
import { createBroadCastChannelProvider } from './broad-cast-channel';
|
|
||||||
|
|
||||||
const createAffineWebSocketProvider = (
|
const createAffineWebSocketProvider = (
|
||||||
blockSuiteWorkspace: BlockSuiteWorkspace
|
blockSuiteWorkspace: BlockSuiteWorkspace
|
||||||
@@ -52,46 +47,4 @@ const createAffineWebSocketProvider = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createIndexedDBProvider = (
|
export { createAffineWebSocketProvider };
|
||||||
blockSuiteWorkspace: BlockSuiteWorkspace
|
|
||||||
): LocalIndexedDBProvider => {
|
|
||||||
let indexeddbProvider: IndexeddbPersistence | null = null;
|
|
||||||
const callbacks = new Set<() => void>();
|
|
||||||
return {
|
|
||||||
flavour: 'local-indexeddb',
|
|
||||||
callbacks,
|
|
||||||
// fixme: remove background long polling
|
|
||||||
background: true,
|
|
||||||
cleanup: () => {
|
|
||||||
assertExists(indexeddbProvider);
|
|
||||||
indexeddbProvider.clearData();
|
|
||||||
callbacks.clear();
|
|
||||||
indexeddbProvider = null;
|
|
||||||
},
|
|
||||||
connect: () => {
|
|
||||||
providerLogger.info('connect indexeddb provider', blockSuiteWorkspace.id);
|
|
||||||
indexeddbProvider = new IndexeddbPersistence(
|
|
||||||
blockSuiteWorkspace.id,
|
|
||||||
blockSuiteWorkspace.doc
|
|
||||||
);
|
|
||||||
indexeddbProvider.whenSynced.then(() => {
|
|
||||||
callbacks.forEach(cb => cb());
|
|
||||||
});
|
|
||||||
},
|
|
||||||
disconnect: () => {
|
|
||||||
assertExists(indexeddbProvider);
|
|
||||||
providerLogger.info(
|
|
||||||
'disconnect indexeddb provider',
|
|
||||||
blockSuiteWorkspace.id
|
|
||||||
);
|
|
||||||
indexeddbProvider.destroy();
|
|
||||||
indexeddbProvider = null;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
createAffineWebSocketProvider,
|
|
||||||
createBroadCastChannelProvider,
|
|
||||||
createIndexedDBProvider,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Button } from '@affine/component';
|
import { Button } from '@affine/component';
|
||||||
import { DebugLogger } from '@affine/debug';
|
import { DebugLogger } from '@affine/debug';
|
||||||
|
import { createBroadCastChannelProvider } from '@affine/workspace/providers';
|
||||||
import type { BroadCastChannelProvider } from '@affine/workspace/type';
|
import type { BroadCastChannelProvider } from '@affine/workspace/type';
|
||||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||||
import { nanoid } from '@blocksuite/store';
|
import { nanoid } from '@blocksuite/store';
|
||||||
@@ -7,7 +8,6 @@ import { Typography } from '@mui/material';
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { createBroadCastChannelProvider } from '../../blocksuite/providers';
|
|
||||||
import PageList from '../../components/blocksuite/block-suite-page-list/page-list';
|
import PageList from '../../components/blocksuite/block-suite-page-list/page-list';
|
||||||
import { StyledPage, StyledWrapper } from '../../layouts/styles';
|
import { StyledPage, StyledWrapper } from '../../layouts/styles';
|
||||||
import { toast } from '../../utils';
|
import { toast } from '../../utils';
|
||||||
|
|||||||
@@ -1,97 +1,18 @@
|
|||||||
import type { LocalWorkspace } from '@affine/workspace/type';
|
import { CRUD } from '@affine/workspace/local/crud';
|
||||||
import { LoadPriority, WorkspaceFlavour } from '@affine/workspace/type';
|
import { LoadPriority, WorkspaceFlavour } from '@affine/workspace/type';
|
||||||
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
|
|
||||||
import { nanoid } from '@blocksuite/store';
|
|
||||||
import { createJSONStorage } from 'jotai/utils';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { IndexeddbPersistence } from 'y-indexeddb';
|
|
||||||
import { z } from 'zod';
|
|
||||||
|
|
||||||
import { createLocalProviders } from '../../blocksuite';
|
|
||||||
import { PageNotFoundError } from '../../components/affine/affine-error-eoundary';
|
import { PageNotFoundError } from '../../components/affine/affine-error-eoundary';
|
||||||
import { WorkspaceSettingDetail } from '../../components/affine/workspace-setting-detail';
|
import { WorkspaceSettingDetail } from '../../components/affine/workspace-setting-detail';
|
||||||
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
|
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
|
||||||
import { PageDetailEditor } from '../../components/page-detail-editor';
|
import { PageDetailEditor } from '../../components/page-detail-editor';
|
||||||
import { BlockSuiteWorkspace } from '../../shared';
|
|
||||||
import { initPage } from '../../utils';
|
import { initPage } from '../../utils';
|
||||||
import type { WorkspacePlugin } from '..';
|
import type { WorkspacePlugin } from '..';
|
||||||
|
|
||||||
const getStorage = () => createJSONStorage(() => localStorage);
|
|
||||||
|
|
||||||
export const kStoreKey = 'affine-local-workspace';
|
|
||||||
const schema = z.array(z.string());
|
|
||||||
|
|
||||||
export const LocalPlugin: WorkspacePlugin<WorkspaceFlavour.LOCAL> = {
|
export const LocalPlugin: WorkspacePlugin<WorkspaceFlavour.LOCAL> = {
|
||||||
flavour: WorkspaceFlavour.LOCAL,
|
flavour: WorkspaceFlavour.LOCAL,
|
||||||
loadPriority: LoadPriority.LOW,
|
loadPriority: LoadPriority.LOW,
|
||||||
CRUD: {
|
CRUD,
|
||||||
get: async workspaceId => {
|
|
||||||
const storage = getStorage();
|
|
||||||
!Array.isArray(storage.getItem(kStoreKey)) &&
|
|
||||||
storage.setItem(kStoreKey, []);
|
|
||||||
const data = storage.getItem(kStoreKey) as z.infer<typeof schema>;
|
|
||||||
const id = data.find(id => id === workspaceId);
|
|
||||||
if (!id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
|
||||||
id,
|
|
||||||
(_: string) => undefined
|
|
||||||
);
|
|
||||||
const workspace: LocalWorkspace = {
|
|
||||||
id,
|
|
||||||
flavour: WorkspaceFlavour.LOCAL,
|
|
||||||
blockSuiteWorkspace: blockSuiteWorkspace,
|
|
||||||
providers: [...createLocalProviders(blockSuiteWorkspace)],
|
|
||||||
};
|
|
||||||
return workspace;
|
|
||||||
},
|
|
||||||
create: async ({ doc }) => {
|
|
||||||
const storage = getStorage();
|
|
||||||
!Array.isArray(storage.getItem(kStoreKey)) &&
|
|
||||||
storage.setItem(kStoreKey, []);
|
|
||||||
const data = storage.getItem(kStoreKey) as z.infer<typeof schema>;
|
|
||||||
const binary = BlockSuiteWorkspace.Y.encodeStateAsUpdateV2(doc);
|
|
||||||
const id = nanoid();
|
|
||||||
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
|
||||||
id,
|
|
||||||
(_: string) => undefined
|
|
||||||
);
|
|
||||||
BlockSuiteWorkspace.Y.applyUpdateV2(blockSuiteWorkspace.doc, binary);
|
|
||||||
const persistence = new IndexeddbPersistence(id, blockSuiteWorkspace.doc);
|
|
||||||
await persistence.whenSynced.then(() => {
|
|
||||||
persistence.destroy();
|
|
||||||
});
|
|
||||||
storage.setItem(kStoreKey, [...data, id]);
|
|
||||||
console.log('create', id, storage.getItem(kStoreKey));
|
|
||||||
return id;
|
|
||||||
},
|
|
||||||
delete: async workspace => {
|
|
||||||
const storage = getStorage();
|
|
||||||
!Array.isArray(storage.getItem(kStoreKey)) &&
|
|
||||||
storage.setItem(kStoreKey, []);
|
|
||||||
const data = storage.getItem(kStoreKey) as z.infer<typeof schema>;
|
|
||||||
const idx = data.findIndex(id => id === workspace.id);
|
|
||||||
if (idx === -1) {
|
|
||||||
throw new Error('workspace not found');
|
|
||||||
}
|
|
||||||
data.splice(idx, 1);
|
|
||||||
storage.setItem(kStoreKey, [...data]);
|
|
||||||
},
|
|
||||||
list: async () => {
|
|
||||||
const storage = getStorage();
|
|
||||||
!Array.isArray(storage.getItem(kStoreKey)) &&
|
|
||||||
storage.setItem(kStoreKey, []);
|
|
||||||
const data = (
|
|
||||||
await Promise.all(
|
|
||||||
(storage.getItem(kStoreKey) as z.infer<typeof schema>).map(id =>
|
|
||||||
LocalPlugin.CRUD.get(id)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
).filter(item => item !== null) as LocalWorkspace[];
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
UI: {
|
UI: {
|
||||||
PageDetail: ({ currentWorkspace, currentPageId }) => {
|
PageDetail: ({ currentWorkspace, currentPageId }) => {
|
||||||
const page = currentWorkspace.blockSuiteWorkspace.getPage(currentPageId);
|
const page = currentWorkspace.blockSuiteWorkspace.getPage(currentPageId);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
"./atom": "./src/atom.ts",
|
"./atom": "./src/atom.ts",
|
||||||
"./utils": "./src/utils.ts",
|
"./utils": "./src/utils.ts",
|
||||||
"./type": "./src/type.ts",
|
"./type": "./src/type.ts",
|
||||||
|
"./local/crud": "./src/local/crud.ts",
|
||||||
|
"./providers": "./src/providers/index.ts",
|
||||||
"./affine/*": "./src/affine/*.ts",
|
"./affine/*": "./src/affine/*.ts",
|
||||||
"./affine/api": "./src/affine/api/index.ts",
|
"./affine/api": "./src/affine/api/index.ts",
|
||||||
"./affine/sync": "./src/affine/sync.js",
|
"./affine/sync": "./src/affine/sync.js",
|
||||||
@@ -24,6 +26,7 @@
|
|||||||
"lib0": "^0.2.73",
|
"lib0": "^0.2.73",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"y-indexeddb": "^9.0.10",
|
||||||
"y-protocols": "^1.0.5",
|
"y-protocols": "^1.0.5",
|
||||||
"yjs": "^13.5.51",
|
"yjs": "^13.5.51",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
|
|||||||
82
packages/workspace/src/local/crud.ts
Normal file
82
packages/workspace/src/local/crud.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { nanoid, Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||||
|
import { createJSONStorage } from 'jotai/utils';
|
||||||
|
import { IndexeddbPersistence } from 'y-indexeddb';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { createLocalProviders } from '../providers';
|
||||||
|
import type { LocalWorkspace, WorkspaceCRUD } from '../type';
|
||||||
|
import { WorkspaceFlavour } from '../type';
|
||||||
|
import { createEmptyBlockSuiteWorkspace } from '../utils';
|
||||||
|
|
||||||
|
const getStorage = () => createJSONStorage(() => localStorage);
|
||||||
|
|
||||||
|
const kStoreKey = 'affine-local-workspace';
|
||||||
|
const schema = z.array(z.string());
|
||||||
|
|
||||||
|
export const CRUD: WorkspaceCRUD<WorkspaceFlavour.LOCAL> = {
|
||||||
|
get: async workspaceId => {
|
||||||
|
const storage = getStorage();
|
||||||
|
!Array.isArray(storage.getItem(kStoreKey)) &&
|
||||||
|
storage.setItem(kStoreKey, []);
|
||||||
|
const data = storage.getItem(kStoreKey) as z.infer<typeof schema>;
|
||||||
|
const id = data.find(id => id === workspaceId);
|
||||||
|
if (!id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
||||||
|
id,
|
||||||
|
(_: string) => undefined
|
||||||
|
);
|
||||||
|
const workspace: LocalWorkspace = {
|
||||||
|
id,
|
||||||
|
flavour: WorkspaceFlavour.LOCAL,
|
||||||
|
blockSuiteWorkspace: blockSuiteWorkspace,
|
||||||
|
providers: [...createLocalProviders(blockSuiteWorkspace)],
|
||||||
|
};
|
||||||
|
return workspace;
|
||||||
|
},
|
||||||
|
create: async ({ doc }) => {
|
||||||
|
const storage = getStorage();
|
||||||
|
!Array.isArray(storage.getItem(kStoreKey)) &&
|
||||||
|
storage.setItem(kStoreKey, []);
|
||||||
|
const data = storage.getItem(kStoreKey) as z.infer<typeof schema>;
|
||||||
|
const binary = BlockSuiteWorkspace.Y.encodeStateAsUpdateV2(doc);
|
||||||
|
const id = nanoid();
|
||||||
|
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
|
||||||
|
id,
|
||||||
|
(_: string) => undefined
|
||||||
|
);
|
||||||
|
BlockSuiteWorkspace.Y.applyUpdateV2(blockSuiteWorkspace.doc, binary);
|
||||||
|
const persistence = new IndexeddbPersistence(id, blockSuiteWorkspace.doc);
|
||||||
|
await persistence.whenSynced.then(() => {
|
||||||
|
persistence.destroy();
|
||||||
|
});
|
||||||
|
storage.setItem(kStoreKey, [...data, id]);
|
||||||
|
console.log('create', id, storage.getItem(kStoreKey));
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
delete: async workspace => {
|
||||||
|
const storage = getStorage();
|
||||||
|
!Array.isArray(storage.getItem(kStoreKey)) &&
|
||||||
|
storage.setItem(kStoreKey, []);
|
||||||
|
const data = storage.getItem(kStoreKey) as z.infer<typeof schema>;
|
||||||
|
const idx = data.findIndex(id => id === workspace.id);
|
||||||
|
if (idx === -1) {
|
||||||
|
throw new Error('workspace not found');
|
||||||
|
}
|
||||||
|
data.splice(idx, 1);
|
||||||
|
storage.setItem(kStoreKey, [...data]);
|
||||||
|
},
|
||||||
|
list: async () => {
|
||||||
|
const storage = getStorage();
|
||||||
|
!Array.isArray(storage.getItem(kStoreKey)) &&
|
||||||
|
storage.setItem(kStoreKey, []);
|
||||||
|
return (
|
||||||
|
await Promise.all(
|
||||||
|
(storage.getItem(kStoreKey) as z.infer<typeof schema>).map(id =>
|
||||||
|
CRUD.get(id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).filter(item => item !== null) as LocalWorkspace[];
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { BroadCastChannelProvider } from '@affine/workspace/type';
|
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||||
import { assertExists } from '@blocksuite/store';
|
import { assertExists } from '@blocksuite/store';
|
||||||
import type { Awareness } from 'y-protocols/awareness';
|
import type { Awareness } from 'y-protocols/awareness';
|
||||||
import {
|
import {
|
||||||
@@ -6,8 +6,8 @@ import {
|
|||||||
encodeAwarenessUpdate,
|
encodeAwarenessUpdate,
|
||||||
} from 'y-protocols/awareness';
|
} from 'y-protocols/awareness';
|
||||||
|
|
||||||
import { BlockSuiteWorkspace } from '../../../shared';
|
import type { BroadCastChannelProvider } from '../../type';
|
||||||
import { providerLogger } from '../../logger';
|
import { localProviderLogger } from '../logger';
|
||||||
import type {
|
import type {
|
||||||
AwarenessChanges,
|
AwarenessChanges,
|
||||||
BroadcastChannelMessageEvent,
|
BroadcastChannelMessageEvent,
|
||||||
@@ -86,7 +86,10 @@ export const createBroadCastChannelProvider = (
|
|||||||
onmessage: handleBroadcastChannelMessage,
|
onmessage: handleBroadcastChannelMessage,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
providerLogger.info('connect broadcast channel', blockSuiteWorkspace.id);
|
localProviderLogger.info(
|
||||||
|
'connect broadcast channel',
|
||||||
|
blockSuiteWorkspace.id
|
||||||
|
);
|
||||||
const docDiff = Y.encodeStateVector(doc);
|
const docDiff = Y.encodeStateVector(doc);
|
||||||
broadcastChannel.postMessage(['doc:diff', docDiff, awareness.clientID]);
|
broadcastChannel.postMessage(['doc:diff', docDiff, awareness.clientID]);
|
||||||
const docUpdateV2 = Y.encodeStateAsUpdate(doc);
|
const docUpdateV2 = Y.encodeStateAsUpdate(doc);
|
||||||
@@ -101,7 +104,7 @@ export const createBroadCastChannelProvider = (
|
|||||||
},
|
},
|
||||||
disconnect: () => {
|
disconnect: () => {
|
||||||
assertExists(broadcastChannel);
|
assertExists(broadcastChannel);
|
||||||
providerLogger.info(
|
localProviderLogger.info(
|
||||||
'disconnect broadcast channel',
|
'disconnect broadcast channel',
|
||||||
blockSuiteWorkspace.id
|
blockSuiteWorkspace.id
|
||||||
);
|
);
|
||||||
115
packages/workspace/src/providers/index.ts
Normal file
115
packages/workspace/src/providers/index.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
import { config } from '@affine/env';
|
||||||
|
import { KeckProvider } from '@affine/workspace/affine/keck';
|
||||||
|
import { getLoginStorage } from '@affine/workspace/affine/login';
|
||||||
|
import type { Provider } from '@affine/workspace/type';
|
||||||
|
import type {
|
||||||
|
AffineWebSocketProvider,
|
||||||
|
LocalIndexedDBProvider,
|
||||||
|
} from '@affine/workspace/type';
|
||||||
|
import type { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||||
|
import { assertExists } from '@blocksuite/store';
|
||||||
|
import { IndexeddbPersistence } from 'y-indexeddb';
|
||||||
|
|
||||||
|
import { createBroadCastChannelProvider } from './broad-cast-channel';
|
||||||
|
import { localProviderLogger } from './logger';
|
||||||
|
|
||||||
|
const createAffineWebSocketProvider = (
|
||||||
|
blockSuiteWorkspace: BlockSuiteWorkspace
|
||||||
|
): AffineWebSocketProvider => {
|
||||||
|
let webSocketProvider: KeckProvider | null = null;
|
||||||
|
return {
|
||||||
|
flavour: 'affine-websocket',
|
||||||
|
background: false,
|
||||||
|
cleanup: () => {
|
||||||
|
assertExists(webSocketProvider);
|
||||||
|
webSocketProvider.destroy();
|
||||||
|
webSocketProvider = null;
|
||||||
|
},
|
||||||
|
connect: () => {
|
||||||
|
const wsUrl = `${
|
||||||
|
window.location.protocol === 'https:' ? 'wss' : 'ws'
|
||||||
|
}://${window.location.host}/api/sync/`;
|
||||||
|
webSocketProvider = new KeckProvider(
|
||||||
|
wsUrl,
|
||||||
|
blockSuiteWorkspace.id,
|
||||||
|
blockSuiteWorkspace.doc,
|
||||||
|
{
|
||||||
|
params: { token: getLoginStorage()?.token ?? '' },
|
||||||
|
// @ts-expect-error ignore the type
|
||||||
|
awareness: blockSuiteWorkspace.awarenessStore.awareness,
|
||||||
|
// we maintain broadcast channel by ourselves
|
||||||
|
disableBc: true,
|
||||||
|
connect: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
localProviderLogger.info('connect', webSocketProvider.url);
|
||||||
|
webSocketProvider.connect();
|
||||||
|
},
|
||||||
|
disconnect: () => {
|
||||||
|
assertExists(webSocketProvider);
|
||||||
|
localProviderLogger.info('disconnect', webSocketProvider.url);
|
||||||
|
webSocketProvider.destroy();
|
||||||
|
webSocketProvider = null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const createIndexedDBProvider = (
|
||||||
|
blockSuiteWorkspace: BlockSuiteWorkspace
|
||||||
|
): LocalIndexedDBProvider => {
|
||||||
|
let indexeddbProvider: IndexeddbPersistence | null = null;
|
||||||
|
const callbacks = new Set<() => void>();
|
||||||
|
return {
|
||||||
|
flavour: 'local-indexeddb',
|
||||||
|
callbacks,
|
||||||
|
// fixme: remove background long polling
|
||||||
|
background: true,
|
||||||
|
cleanup: () => {
|
||||||
|
assertExists(indexeddbProvider);
|
||||||
|
indexeddbProvider.clearData();
|
||||||
|
callbacks.clear();
|
||||||
|
indexeddbProvider = null;
|
||||||
|
},
|
||||||
|
connect: () => {
|
||||||
|
localProviderLogger.info(
|
||||||
|
'connect indexeddb provider',
|
||||||
|
blockSuiteWorkspace.id
|
||||||
|
);
|
||||||
|
indexeddbProvider = new IndexeddbPersistence(
|
||||||
|
blockSuiteWorkspace.id,
|
||||||
|
blockSuiteWorkspace.doc
|
||||||
|
);
|
||||||
|
indexeddbProvider.whenSynced.then(() => {
|
||||||
|
callbacks.forEach(cb => cb());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
disconnect: () => {
|
||||||
|
assertExists(indexeddbProvider);
|
||||||
|
localProviderLogger.info(
|
||||||
|
'disconnect indexeddb provider',
|
||||||
|
blockSuiteWorkspace.id
|
||||||
|
);
|
||||||
|
indexeddbProvider.destroy();
|
||||||
|
indexeddbProvider = null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
createAffineWebSocketProvider,
|
||||||
|
createBroadCastChannelProvider,
|
||||||
|
createIndexedDBProvider,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createLocalProviders = (
|
||||||
|
blockSuiteWorkspace: BlockSuiteWorkspace
|
||||||
|
): Provider[] => {
|
||||||
|
return (
|
||||||
|
[
|
||||||
|
config.enableBroadCastChannelProvider &&
|
||||||
|
createBroadCastChannelProvider(blockSuiteWorkspace),
|
||||||
|
config.enableIndexedDBProvider &&
|
||||||
|
createIndexedDBProvider(blockSuiteWorkspace),
|
||||||
|
] as any[]
|
||||||
|
).filter(v => Boolean(v));
|
||||||
|
};
|
||||||
3
packages/workspace/src/providers/logger.ts
Normal file
3
packages/workspace/src/providers/logger.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { DebugLogger } from '@affine/debug';
|
||||||
|
|
||||||
|
export const localProviderLogger = new DebugLogger('local-provider');
|
||||||
Reference in New Issue
Block a user