refactor: remove sync binary (#1297)

This commit is contained in:
Himself65 2023-03-03 13:36:42 -06:00 committed by GitHub
parent fd510834ed
commit 296cd215c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 161 additions and 202 deletions

View File

@ -39,7 +39,6 @@ export const publicBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(
id: workspaceId,
blockSuiteWorkspace,
flavour: RemWorkspaceFlavour.LOCAL,
syncBinary: () => Promise.resolve(workspace),
providers: [],
};
dataCenter.workspaces.push(workspace);

View File

@ -2,17 +2,19 @@ import { config } from '@affine/env';
import { BlockSuiteWorkspace, Provider } from '../shared';
import {
createAffineWebSocketProvider,
createBroadCastChannelProvider,
createIndexedDBProvider,
createWebSocketProvider,
} from './providers';
import { createAffineDownloadProvider } from './providers/affine';
export const createAffineProviders = (
blockSuiteWorkspace: BlockSuiteWorkspace
): Provider[] => {
return (
[
createWebSocketProvider(blockSuiteWorkspace),
createAffineDownloadProvider(blockSuiteWorkspace),
createAffineWebSocketProvider(blockSuiteWorkspace),
config.enableBroadCastChannelProvider &&
createBroadCastChannelProvider(blockSuiteWorkspace),
config.enableIndexedDBProvider &&

View File

@ -0,0 +1,43 @@
import { assertExists } from '@blocksuite/store';
import { AffineDownloadProvider, BlockSuiteWorkspace } from '../../../shared';
import { apis } from '../../../shared/apis';
import { providerLogger } from '../../logger';
const hashMap = new Map<string, ArrayBuffer>();
export const createAffineDownloadProvider = (
blockSuiteWorkspace: BlockSuiteWorkspace
): AffineDownloadProvider => {
assertExists(blockSuiteWorkspace.room);
const id = blockSuiteWorkspace.room;
return {
flavour: 'affine-download',
background: true,
connect: () => {
providerLogger.info('connect download provider', id);
if (hashMap.has(id)) {
providerLogger.debug('applyUpdate');
BlockSuiteWorkspace.Y.applyUpdate(
blockSuiteWorkspace.doc,
new Uint8Array(hashMap.get(id) as ArrayBuffer)
);
return;
}
apis.downloadWorkspace(id, false).then(binary => {
hashMap.set(id, binary);
providerLogger.debug('applyUpdate');
BlockSuiteWorkspace.Y.applyUpdate(
blockSuiteWorkspace.doc,
new Uint8Array(binary)
);
});
},
disconnect: () => {
providerLogger.info('disconnect download provider', id);
},
cleanup: () => {
hashMap.delete(id);
},
};
};

View File

@ -76,6 +76,7 @@ export const createBroadCastChannelProvider = (
};
return {
flavour: 'broadcast-channel',
background: false,
connect: () => {
assertExists(blockSuiteWorkspace.room);
broadcastChannel = Object.assign(

View File

@ -11,12 +11,13 @@ import { apis } from '../../shared/apis';
import { providerLogger } from '../logger';
import { createBroadCastChannelProvider } from './broad-cast-channel';
const createWebSocketProvider = (
const createAffineWebSocketProvider = (
blockSuiteWorkspace: BlockSuiteWorkspace
): AffineWebSocketProvider => {
let webSocketProvider: WebsocketProvider | null = null;
return {
flavour: 'affine-websocket',
background: false,
cleanup: () => {
assertExists(webSocketProvider);
webSocketProvider.destroy();
@ -54,37 +55,39 @@ const createWebSocketProvider = (
const createIndexedDBProvider = (
blockSuiteWorkspace: BlockSuiteWorkspace
): LocalIndexedDBProvider => {
let indexdbProvider: IndexeddbPersistence | null = null;
let indexeddbProvider: IndexeddbPersistence | null = null;
return {
flavour: 'local-indexeddb',
// fixme: remove background long polling
background: true,
cleanup: () => {
assertExists(indexdbProvider);
indexdbProvider.clearData();
assertExists(indexeddbProvider);
indexeddbProvider.clearData();
},
connect: () => {
providerLogger.info(
'connect indexeddb provider',
blockSuiteWorkspace.room
);
indexdbProvider = new IndexeddbPersistence(
indexeddbProvider = new IndexeddbPersistence(
blockSuiteWorkspace.room as string,
blockSuiteWorkspace.doc
);
},
disconnect: () => {
assertExists(indexdbProvider);
assertExists(indexeddbProvider);
providerLogger.info(
'disconnect indexeddb provider',
blockSuiteWorkspace.room
);
indexdbProvider.destroy();
indexdbProvider = null;
indexeddbProvider.destroy();
indexeddbProvider = null;
},
};
};
export {
createAffineWebSocketProvider,
createBroadCastChannelProvider,
createIndexedDBProvider,
createWebSocketProvider,
};

View File

@ -4,7 +4,7 @@ import { assertExists } from '@blocksuite/store';
import React, { useState } from 'react';
import { useIsWorkspaceOwner } from '../../../../../hooks/affine/use-is-workspace-owner';
import { refreshDataCenter } from '../../../../../hooks/use-workspaces';
import { useBlockSuiteWorkspaceName } from '../../../../../hooks/use-blocksuite-workspace-name';
import { RemWorkspaceFlavour } from '../../../../../shared';
import { Upload } from '../../../../pure/file-upload';
import {
@ -31,17 +31,16 @@ export const GeneralPanel: React.FC<PanelProps> = ({
}) => {
const [showDelete, setShowDelete] = useState<boolean>(false);
const [showLeave, setShowLeave] = useState<boolean>(false);
const [workspaceName, setWorkspaceName] = useState<string>(
workspace.blockSuiteWorkspace.meta.name
const [name, setName] = useBlockSuiteWorkspaceName(
workspace.blockSuiteWorkspace
);
const [input, setInput] = useState<string>(name);
const isOwner = useIsWorkspaceOwner(workspace);
const [showEditInput, setShowEditInput] = useState(false);
const { t } = useTranslation();
const handleUpdateWorkspaceName = () => {
workspace.blockSuiteWorkspace.meta.setName(workspaceName);
// fixme(himself65): don't refresh
refreshDataCenter();
const handleUpdateWorkspaceName = (name: string) => {
setName(name);
};
const fileChange = async (file: File) => {
@ -50,8 +49,6 @@ export const GeneralPanel: React.FC<PanelProps> = ({
assertExists(blobs);
const blobId = await blobs.set(blob);
workspace.blockSuiteWorkspace.meta.setAvatar(blobId);
// fixme(himself65): don't refresh
refreshDataCenter();
};
return (
@ -84,7 +81,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
<div style={{ position: 'relative' }}>
<MuiFade in={!showEditInput}>
<FlexWrapper>
{workspace.blockSuiteWorkspace.meta.name}
{name}
{isOwner && (
<StyledEditButton
onClick={() => {
@ -103,23 +100,21 @@ export const GeneralPanel: React.FC<PanelProps> = ({
<StyledInput
width={284}
height={38}
value={workspaceName}
value={input}
placeholder={t('Workspace Name')}
maxLength={15}
minLength={0}
onChange={newName => {
setWorkspaceName(newName);
setInput(newName);
}}
></StyledInput>
<Button
type="light"
shape="circle"
style={{ marginLeft: '24px' }}
disabled={
workspaceName === workspace.blockSuiteWorkspace.meta.name
}
disabled={input === workspace.blockSuiteWorkspace.meta.name}
onClick={() => {
handleUpdateWorkspaceName();
handleUpdateWorkspaceName(input);
setShowEditInput(false);
}}
>
@ -130,7 +125,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
shape="circle"
style={{ marginLeft: '24px' }}
onClick={() => {
setWorkspaceName(workspace.blockSuiteWorkspace.meta.name);
setInput(workspace.blockSuiteWorkspace.meta.name);
setShowEditInput(false);
}}
>

View File

@ -2,6 +2,7 @@ import { PermissionType } from '@affine/datacenter';
import { useTranslation } from '@affine/i18n';
import React, { useCallback } from 'react';
import { useBlockSuiteWorkspaceName } from '../../../hooks/use-blocksuite-workspace-name';
import { RemWorkspace, RemWorkspaceFlavour } from '../../../shared';
import {
CloudWorkspaceIcon,
@ -60,14 +61,7 @@ export const WorkspaceCard: React.FC<WorkspaceCardProps> = ({
currentWorkspaceId,
}) => {
const { t } = useTranslation();
let name = 'UNKNOWN';
if (workspace.flavour === RemWorkspaceFlavour.LOCAL) {
name = workspace.blockSuiteWorkspace.meta.name;
} else if (workspace.flavour === RemWorkspaceFlavour.AFFINE) {
if (workspace.firstBinarySynced) {
name = workspace.blockSuiteWorkspace.meta.name;
}
}
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
return (
<StyledCard

View File

@ -10,6 +10,11 @@ export function useBlockSuiteWorkspaceName(
const [name, set] = useState(
() => blockSuiteWorkspace?.meta.name ?? DEFAULT_WORKSPACE_NAME
);
if (blockSuiteWorkspace) {
if (blockSuiteWorkspace.meta.name !== name) {
set(blockSuiteWorkspace.meta.name);
}
}
useEffect(() => {
if (blockSuiteWorkspace) {
set(blockSuiteWorkspace.meta.name);
@ -24,8 +29,8 @@ export function useBlockSuiteWorkspaceName(
const setName = useCallback(
(name: string) => {
assertExists(blockSuiteWorkspace);
set(name);
blockSuiteWorkspace.meta.setName(name);
set(name);
},
[blockSuiteWorkspace]
);

View File

@ -1,13 +0,0 @@
import { useEffect } from 'react';
import { RemWorkspace, RemWorkspaceFlavour } from '../shared';
export function useLoadWorkspace(workspace: RemWorkspace | null | undefined) {
useEffect(() => {
if (workspace?.flavour === RemWorkspaceFlavour.AFFINE) {
if (!workspace.firstBinarySynced) {
workspace.syncBinary();
}
}
}, [workspace]);
}

View File

@ -12,18 +12,13 @@ export function findSuitablePageId(
): string | null {
switch (workspace.flavour) {
case RemWorkspaceFlavour.AFFINE: {
if (workspace.firstBinarySynced) {
return (
workspace.blockSuiteWorkspace.meta.pageMetas.find(
page => page.id === targetId
)?.id ??
workspace.blockSuiteWorkspace.meta.pageMetas.at(0)?.id ??
null
);
} else {
return null;
}
break;
return (
workspace.blockSuiteWorkspace.meta.pageMetas.find(
page => page.id === targetId
)?.id ??
workspace.blockSuiteWorkspace.meta.pageMetas.at(0)?.id ??
null
);
}
case RemWorkspaceFlavour.LOCAL: {
return (

View File

@ -2,12 +2,10 @@ import { NextRouter } from 'next/router';
import { useEffect } from 'react';
import { useCurrentWorkspace } from './current/use-current-workspace';
import { useLoadWorkspace } from './use-load-workspace';
import { useWorkspaces } from './use-workspaces';
export function useSyncRouterWithCurrentWorkspace(router: NextRouter) {
const [currentWorkspace, setCurrentWorkspaceId] = useCurrentWorkspace();
useLoadWorkspace(currentWorkspace);
const workspaces = useWorkspaces();
useEffect(() => {
const listener: Parameters<typeof router.events.on>[1] = (url: string) => {

View File

@ -3,7 +3,6 @@ import { config, getEnvironment } from '@affine/env';
import { nanoid } from '@blocksuite/store';
import { useCallback, useMemo, useSyncExternalStore } from 'react';
import useSWR from 'swr';
import { IndexeddbPersistence } from 'y-indexeddb';
import { lockMutex } from '../atoms';
import { createLocalProviders } from '../blocksuite';
@ -47,23 +46,6 @@ function createRemLocalWorkspace(name: string) {
flavour: RemWorkspaceFlavour.LOCAL,
blockSuiteWorkspace: blockSuiteWorkspace,
providers: [...createLocalProviders(blockSuiteWorkspace)],
syncBinary: async () => {
if (!config.enableIndexedDBProvider) {
return {
...workspace,
};
}
const persistence = new IndexeddbPersistence(
blockSuiteWorkspace.room as string,
blockSuiteWorkspace.doc
);
return persistence.whenSynced.then(() => {
persistence.destroy();
return {
...workspace,
};
});
},
id,
};
if (config.enableIndexedDBProvider) {
@ -111,6 +93,7 @@ export async function refreshDataCenter(signal?: AbortSignal) {
break;
}
const oldData = dataCenter.workspaces;
oldData.forEach(d => console.log(d.blockSuiteWorkspace.doc.toJSON()));
await plugin.prefetchData(dataCenter, signal);
const newData = dataCenter.workspaces;
if (!Object.is(oldData, newData)) {

View File

@ -18,7 +18,11 @@ import { useCurrentPageId } from '../hooks/current/use-current-page-id';
import { useCurrentWorkspace } from '../hooks/current/use-current-workspace';
import { useBlockSuiteWorkspaceHelper } from '../hooks/use-blocksuite-workspace-helper';
import { useRouterTitle } from '../hooks/use-router-title';
import { refreshDataCenter, useSyncWorkspaces } from '../hooks/use-workspaces';
import {
refreshDataCenter,
useSyncWorkspaces,
useWorkspaces,
} from '../hooks/use-workspaces';
import { pathGenerator, publicPathGenerator } from '../shared';
import { StyledPage, StyledToolWrapper, StyledWrapper } from './styles';
@ -47,13 +51,33 @@ export const WorkspaceLayout: React.FC<React.PropsWithChildren> = ({
useSyncWorkspaces();
const [currentWorkspace] = useCurrentWorkspace();
const [currentPageId] = useCurrentPageId();
const workspaces = useWorkspaces();
useEffect(() => {
if (currentWorkspace && 'providers' in currentWorkspace) {
const providers = workspaces.flatMap(workspace =>
workspace.providers.filter(provider => provider.background)
);
providers.forEach(provider => {
provider.connect();
});
return () => {
providers.forEach(provider => {
provider.disconnect();
});
};
}, [workspaces]);
useEffect(() => {
if (currentWorkspace) {
currentWorkspace.providers.forEach(provider => {
if (provider.background) {
return;
}
provider.connect();
});
return () => {
currentWorkspace.providers.forEach(provider => {
if (provider.background) {
return;
}
provider.disconnect();
});
};

View File

@ -5,7 +5,6 @@ import { Unreachable } from '../../../components/affine/affine-error-eoundary';
import { PageLoading } from '../../../components/pure/loading';
import { useCurrentPageId } from '../../../hooks/current/use-current-page-id';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { useLoadWorkspace } from '../../../hooks/use-load-workspace';
import { useSyncRouterWithCurrentWorkspaceAndPage } from '../../../hooks/use-sync-router-with-current-workspace-and-page';
import { WorkspaceLayout } from '../../../layouts';
import { WorkspacePlugins } from '../../../plugins';
@ -72,7 +71,6 @@ const WorkspaceDetail: React.FC = () => {
const WorkspaceDetailPage: NextPageWithLayout = () => {
const router = useRouter();
useLoadWorkspace(useCurrentWorkspace()[0]);
useSyncRouterWithCurrentWorkspaceAndPage(router);
if (!router.isReady) {
return <PageLoading />;

View File

@ -11,7 +11,6 @@ import {
import { PageLoading } from '../../../components/pure/loading';
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { useLoadWorkspace } from '../../../hooks/use-load-workspace';
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
import { WorkspaceLayout } from '../../../layouts';
import { WorkspacePlugins } from '../../../plugins';
@ -20,7 +19,6 @@ const AllPage: NextPageWithLayout = () => {
const router = useRouter();
const [currentWorkspace] = useCurrentWorkspace();
const { t } = useTranslation();
useLoadWorkspace(currentWorkspace);
useSyncRouterWithCurrentWorkspace(router);
const onClickPage = useCallback(
(pageId: string, newTab?: boolean) => {
@ -50,21 +48,15 @@ const AllPage: NextPageWithLayout = () => {
}
if (currentWorkspace.flavour === RemWorkspaceFlavour.AFFINE) {
const PageList = WorkspacePlugins[currentWorkspace.flavour].PageList;
if (currentWorkspace.firstBinarySynced) {
return (
<>
<WorkspaceTitle icon={<FolderIcon />}>
{t('All pages')}
</WorkspaceTitle>
<PageList
onOpenPage={onClickPage}
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
/>
</>
);
} else {
return <div>loading</div>;
}
return (
<>
<WorkspaceTitle icon={<FolderIcon />}>{t('All pages')}</WorkspaceTitle>
<PageList
onOpenPage={onClickPage}
blockSuiteWorkspace={currentWorkspace.blockSuiteWorkspace}
/>
</>
);
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.LOCAL) {
const PageList = WorkspacePlugins[currentWorkspace.flavour].PageList;
return (

View File

@ -9,7 +9,6 @@ import PageList from '../../../components/blocksuite/block-suite-page-list/page-
import { PageLoading } from '../../../components/pure/loading';
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { useLoadWorkspace } from '../../../hooks/use-load-workspace';
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
import { WorkspaceLayout } from '../../../layouts';
import { NextPageWithLayout } from '../../../shared';
@ -18,7 +17,6 @@ const FavouritePage: NextPageWithLayout = () => {
const router = useRouter();
const [currentWorkspace] = useCurrentWorkspace();
const { t } = useTranslation();
useLoadWorkspace(currentWorkspace);
useSyncRouterWithCurrentWorkspace(router);
const onClickPage = useCallback(
(pageId: string, newTab?: boolean) => {

View File

@ -11,7 +11,6 @@ import { Unreachable } from '../../../components/affine/affine-error-eoundary';
import { PageLoading } from '../../../components/pure/loading';
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { useLoadWorkspace } from '../../../hooks/use-load-workspace';
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
import { useWorkspacesHelper } from '../../../hooks/use-workspaces';
import { WorkspaceLayout } from '../../../layouts';
@ -33,7 +32,6 @@ const SettingPage: NextPageWithLayout = () => {
const router = useRouter();
const [currentWorkspace] = useCurrentWorkspace();
const { t } = useTranslation();
useLoadWorkspace(currentWorkspace);
useSyncRouterWithCurrentWorkspace(router);
const [currentTab, setCurrentTab] = useAtom(settingPanelAtom);
useEffect(() => {});

View File

@ -9,7 +9,6 @@ import PageList from '../../../components/blocksuite/block-suite-page-list/page-
import { PageLoading } from '../../../components/pure/loading';
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { useLoadWorkspace } from '../../../hooks/use-load-workspace';
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
import { WorkspaceLayout } from '../../../layouts';
import { NextPageWithLayout } from '../../../shared';
@ -18,7 +17,6 @@ const TrashPage: NextPageWithLayout = () => {
const router = useRouter();
const [currentWorkspace] = useCurrentWorkspace();
const { t } = useTranslation();
useLoadWorkspace(currentWorkspace);
useSyncRouterWithCurrentWorkspace(router);
const onClickPage = useCallback(
(pageId: string, newTab?: boolean) => {

View File

@ -1,8 +1,8 @@
import { createAffineProviders } from '../../blocksuite';
import { Unreachable } from '../../components/affine/affine-error-eoundary';
import {
AffineRemoteUnSyncedWorkspace,
RemWorkspaceFlavour,
transformToAffineSyncedWorkspace,
} from '../../shared';
import { apis } from '../../shared/apis';
import { createEmptyBlockSuiteWorkspace } from '../../utils';
@ -42,26 +42,17 @@ export const fetcher = async (
if (query === QueryKey.getWorkspaces) {
return apis.getWorkspaces().then(workspaces => {
return workspaces.map(workspace => {
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
workspace.id,
(k: string) =>
// fixme: token could be expired
({ api: '/api/workspace', token: apis.auth.token }[k])
);
const remWorkspace: AffineRemoteUnSyncedWorkspace = {
...workspace,
flavour: RemWorkspaceFlavour.AFFINE,
firstBinarySynced: false,
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace(
workspace.id,
(k: string) =>
// fixme: token could be expired
({ api: '/api/workspace', token: apis.auth.token }[k])
),
syncBinary: async () => {
const binary = await apis.downloadWorkspace(
workspace.id,
workspace.public
);
if (remWorkspace.firstBinarySynced) {
return null;
}
return transformToAffineSyncedWorkspace(remWorkspace, binary);
},
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};
return remWorkspace;
});

View File

@ -44,9 +44,7 @@ export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
await apis.deleteWorkspace({
id: workspace.id,
});
if (workspace.firstBinarySynced) {
workspace.providers.forEach(p => p.cleanup());
}
workspace.providers.forEach(p => p.cleanup());
},
prefetchData: async dataCenter => {
if (localStorage.getItem(kAffineLocal)) {
@ -74,9 +72,6 @@ export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
flavour: RemWorkspaceFlavour.AFFINE,
syncBinary: async () => {
return { ...affineWorkspace };
},
};
return affineWorkspace;
});
@ -106,9 +101,6 @@ export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
.then(async workspaces => {
const promises = workspaces.map(workspace => {
assertEquals(workspace.flavour, RemWorkspaceFlavour.AFFINE);
if (!workspace.firstBinarySynced) {
return workspace.syncBinary();
}
return workspace;
});
return Promise.all(promises)
@ -151,9 +143,6 @@ export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
});
},
PageDetail: ({ currentWorkspace, currentPageId }) => {
if (!currentWorkspace.firstBinarySynced) {
return <div>Loading</div>;
}
const page = currentWorkspace.blockSuiteWorkspace.getPage(currentPageId);
if (!page) {
throw new PageNotFoundError(

View File

@ -1,5 +1,5 @@
import { DebugLogger } from '@affine/debug';
import { config } from '@affine/env';
import { config, DEFAULT_WORKSPACE_NAME } from '@affine/env';
import { assertEquals, nanoid } from '@blocksuite/store';
import React from 'react';
import { IndexeddbPersistence } from 'y-indexeddb';
@ -10,6 +10,7 @@ import { WorkspaceSettingDetail } from '../../components/affine/workspace-settin
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
import { PageDetailEditor } from '../../components/page-detail-editor';
import {
BlockSuiteWorkspace,
LoadPriority,
LocalWorkspace,
RemWorkspaceFlavour,
@ -20,6 +21,8 @@ import { WorkspacePlugin } from '..';
const logger = new DebugLogger('local-plugin');
export const kStoreKey = 'affine-local-workspace';
// fixme(himself65): this is a hacking that first workspace will disappear somehow
const hashMap = new Map<string, BlockSuiteWorkspace>();
export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
flavour: RemWorkspaceFlavour.LOCAL,
@ -92,34 +95,17 @@ export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
if (config.enableIndexedDBProvider) {
const workspaces = await Promise.all(
ids.map(id => {
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(
id,
(_: string) => undefined
);
const blockSuiteWorkspace = hashMap.has(id)
? (hashMap.get(id) as BlockSuiteWorkspace)
: createEmptyBlockSuiteWorkspace(id, (_: string) => undefined);
hashMap.set(id, blockSuiteWorkspace);
const workspace: LocalWorkspace = {
id,
flavour: RemWorkspaceFlavour.LOCAL,
blockSuiteWorkspace: blockSuiteWorkspace,
providers: [...createLocalProviders(blockSuiteWorkspace)],
syncBinary: async () => {
if (!config.enableIndexedDBProvider) {
return {
...workspace,
};
}
const persistence = new IndexeddbPersistence(
blockSuiteWorkspace.room as string,
blockSuiteWorkspace.doc
);
return persistence.whenSynced.then(() => {
persistence.destroy();
return {
...workspace,
};
});
},
};
return workspace.syncBinary();
return workspace;
})
);
workspaces.forEach(workspace => {
@ -146,7 +132,8 @@ export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
workspaceId,
(_: string) => undefined
);
blockSuiteWorkspace.meta.setName('Untitled Workspace');
hashMap.set(workspaceId, blockSuiteWorkspace);
blockSuiteWorkspace.meta.setName(DEFAULT_WORKSPACE_NAME);
localStorage.setItem(kStoreKey, JSON.stringify([workspaceId]));
blockSuiteWorkspace.createPage(nanoid());
const workspace: LocalWorkspace = {
@ -154,33 +141,14 @@ export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
flavour: RemWorkspaceFlavour.LOCAL,
blockSuiteWorkspace: blockSuiteWorkspace,
providers: [...createLocalProviders(blockSuiteWorkspace)],
syncBinary: async () => {
if (!config.enableIndexedDBProvider) {
return {
...workspace,
};
}
const persistence = new IndexeddbPersistence(
blockSuiteWorkspace.room as string,
blockSuiteWorkspace.doc
);
return persistence.whenSynced.then(() => {
persistence.destroy();
return {
...workspace,
};
});
},
};
await workspace.syncBinary();
if (signal?.aborted) {
const persistence = new IndexeddbPersistence(
blockSuiteWorkspace.room as string,
blockSuiteWorkspace.doc
);
await persistence.clearData();
return;
}
const persistence = new IndexeddbPersistence(
blockSuiteWorkspace.room as string,
blockSuiteWorkspace.doc
);
await persistence.whenSynced.then(() => {
persistence.destroy();
});
dataCenter.workspaces = [workspace];
}
},

View File

@ -27,29 +27,21 @@ export interface FlavourToWorkspace {
[RemWorkspaceFlavour.LOCAL]: LocalWorkspace;
}
export interface WorkspaceHandler {
syncBinary: () => Promise<RemWorkspace | null>;
}
export interface AffineRemoteSyncedWorkspace
extends RemoteWorkspace,
WorkspaceHandler {
export interface AffineRemoteSyncedWorkspace extends RemoteWorkspace {
flavour: RemWorkspaceFlavour.AFFINE;
firstBinarySynced: true;
blockSuiteWorkspace: BlockSuiteWorkspace;
providers: Provider[];
}
export interface AffineRemoteUnSyncedWorkspace
extends RemoteWorkspace,
WorkspaceHandler {
export interface AffineRemoteUnSyncedWorkspace extends RemoteWorkspace {
flavour: RemWorkspaceFlavour.AFFINE;
firstBinarySynced: false;
// empty
blockSuiteWorkspace: BlockSuiteWorkspace;
providers: Provider[];
}
export interface LocalWorkspace extends WorkspaceHandler {
export interface LocalWorkspace {
flavour: RemWorkspaceFlavour.LOCAL;
id: string;
blockSuiteWorkspace: BlockSuiteWorkspace;
@ -85,12 +77,18 @@ export const transformToAffineSyncedWorkspace = async (
export type BaseProvider = {
flavour: string;
// if this is true, we will connect the provider on the background
background: boolean;
connect: () => void;
disconnect: () => void;
// cleanup data when workspace is removed
cleanup: () => void;
};
export interface AffineDownloadProvider extends BaseProvider {
flavour: 'affine-download';
}
export interface BroadCastChannelProvider extends BaseProvider {
flavour: 'broadcast-channel';
}