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
22 changed files with 161 additions and 202 deletions

View File

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

View File

@@ -2,17 +2,19 @@ import { config } from '@affine/env';
import { BlockSuiteWorkspace, Provider } from '../shared'; import { BlockSuiteWorkspace, Provider } from '../shared';
import { import {
createAffineWebSocketProvider,
createBroadCastChannelProvider, createBroadCastChannelProvider,
createIndexedDBProvider, createIndexedDBProvider,
createWebSocketProvider,
} from './providers'; } from './providers';
import { createAffineDownloadProvider } from './providers/affine';
export const createAffineProviders = ( export const createAffineProviders = (
blockSuiteWorkspace: BlockSuiteWorkspace blockSuiteWorkspace: BlockSuiteWorkspace
): Provider[] => { ): Provider[] => {
return ( return (
[ [
createWebSocketProvider(blockSuiteWorkspace), createAffineDownloadProvider(blockSuiteWorkspace),
createAffineWebSocketProvider(blockSuiteWorkspace),
config.enableBroadCastChannelProvider && config.enableBroadCastChannelProvider &&
createBroadCastChannelProvider(blockSuiteWorkspace), createBroadCastChannelProvider(blockSuiteWorkspace),
config.enableIndexedDBProvider && 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 { return {
flavour: 'broadcast-channel', flavour: 'broadcast-channel',
background: false,
connect: () => { connect: () => {
assertExists(blockSuiteWorkspace.room); assertExists(blockSuiteWorkspace.room);
broadcastChannel = Object.assign( broadcastChannel = Object.assign(

View File

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

View File

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

View File

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

View File

@@ -10,6 +10,11 @@ export function useBlockSuiteWorkspaceName(
const [name, set] = useState( const [name, set] = useState(
() => blockSuiteWorkspace?.meta.name ?? DEFAULT_WORKSPACE_NAME () => blockSuiteWorkspace?.meta.name ?? DEFAULT_WORKSPACE_NAME
); );
if (blockSuiteWorkspace) {
if (blockSuiteWorkspace.meta.name !== name) {
set(blockSuiteWorkspace.meta.name);
}
}
useEffect(() => { useEffect(() => {
if (blockSuiteWorkspace) { if (blockSuiteWorkspace) {
set(blockSuiteWorkspace.meta.name); set(blockSuiteWorkspace.meta.name);
@@ -24,8 +29,8 @@ export function useBlockSuiteWorkspaceName(
const setName = useCallback( const setName = useCallback(
(name: string) => { (name: string) => {
assertExists(blockSuiteWorkspace); assertExists(blockSuiteWorkspace);
set(name);
blockSuiteWorkspace.meta.setName(name); blockSuiteWorkspace.meta.setName(name);
set(name);
}, },
[blockSuiteWorkspace] [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 { ): string | null {
switch (workspace.flavour) { switch (workspace.flavour) {
case RemWorkspaceFlavour.AFFINE: { case RemWorkspaceFlavour.AFFINE: {
if (workspace.firstBinarySynced) { return (
return ( workspace.blockSuiteWorkspace.meta.pageMetas.find(
workspace.blockSuiteWorkspace.meta.pageMetas.find( page => page.id === targetId
page => page.id === targetId )?.id ??
)?.id ?? workspace.blockSuiteWorkspace.meta.pageMetas.at(0)?.id ??
workspace.blockSuiteWorkspace.meta.pageMetas.at(0)?.id ?? null
null );
);
} else {
return null;
}
break;
} }
case RemWorkspaceFlavour.LOCAL: { case RemWorkspaceFlavour.LOCAL: {
return ( return (

View File

@@ -2,12 +2,10 @@ import { NextRouter } from 'next/router';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useCurrentWorkspace } from './current/use-current-workspace'; import { useCurrentWorkspace } from './current/use-current-workspace';
import { useLoadWorkspace } from './use-load-workspace';
import { useWorkspaces } from './use-workspaces'; import { useWorkspaces } from './use-workspaces';
export function useSyncRouterWithCurrentWorkspace(router: NextRouter) { export function useSyncRouterWithCurrentWorkspace(router: NextRouter) {
const [currentWorkspace, setCurrentWorkspaceId] = useCurrentWorkspace(); const [currentWorkspace, setCurrentWorkspaceId] = useCurrentWorkspace();
useLoadWorkspace(currentWorkspace);
const workspaces = useWorkspaces(); const workspaces = useWorkspaces();
useEffect(() => { useEffect(() => {
const listener: Parameters<typeof router.events.on>[1] = (url: string) => { 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 { nanoid } from '@blocksuite/store';
import { useCallback, useMemo, useSyncExternalStore } from 'react'; import { useCallback, useMemo, useSyncExternalStore } from 'react';
import useSWR from 'swr'; import useSWR from 'swr';
import { IndexeddbPersistence } from 'y-indexeddb';
import { lockMutex } from '../atoms'; import { lockMutex } from '../atoms';
import { createLocalProviders } from '../blocksuite'; import { createLocalProviders } from '../blocksuite';
@@ -47,23 +46,6 @@ function createRemLocalWorkspace(name: string) {
flavour: RemWorkspaceFlavour.LOCAL, flavour: RemWorkspaceFlavour.LOCAL,
blockSuiteWorkspace: blockSuiteWorkspace, blockSuiteWorkspace: blockSuiteWorkspace,
providers: [...createLocalProviders(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, id,
}; };
if (config.enableIndexedDBProvider) { if (config.enableIndexedDBProvider) {
@@ -111,6 +93,7 @@ export async function refreshDataCenter(signal?: AbortSignal) {
break; break;
} }
const oldData = dataCenter.workspaces; const oldData = dataCenter.workspaces;
oldData.forEach(d => console.log(d.blockSuiteWorkspace.doc.toJSON()));
await plugin.prefetchData(dataCenter, signal); await plugin.prefetchData(dataCenter, signal);
const newData = dataCenter.workspaces; const newData = dataCenter.workspaces;
if (!Object.is(oldData, newData)) { 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 { useCurrentWorkspace } from '../hooks/current/use-current-workspace';
import { useBlockSuiteWorkspaceHelper } from '../hooks/use-blocksuite-workspace-helper'; import { useBlockSuiteWorkspaceHelper } from '../hooks/use-blocksuite-workspace-helper';
import { useRouterTitle } from '../hooks/use-router-title'; 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 { pathGenerator, publicPathGenerator } from '../shared';
import { StyledPage, StyledToolWrapper, StyledWrapper } from './styles'; import { StyledPage, StyledToolWrapper, StyledWrapper } from './styles';
@@ -47,13 +51,33 @@ export const WorkspaceLayout: React.FC<React.PropsWithChildren> = ({
useSyncWorkspaces(); useSyncWorkspaces();
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
const [currentPageId] = useCurrentPageId(); const [currentPageId] = useCurrentPageId();
const workspaces = useWorkspaces();
useEffect(() => { 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 => { currentWorkspace.providers.forEach(provider => {
if (provider.background) {
return;
}
provider.connect(); provider.connect();
}); });
return () => { return () => {
currentWorkspace.providers.forEach(provider => { currentWorkspace.providers.forEach(provider => {
if (provider.background) {
return;
}
provider.disconnect(); provider.disconnect();
}); });
}; };

View File

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

View File

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

View File

@@ -9,7 +9,6 @@ import PageList from '../../../components/blocksuite/block-suite-page-list/page-
import { PageLoading } from '../../../components/pure/loading'; import { PageLoading } from '../../../components/pure/loading';
import { WorkspaceTitle } from '../../../components/pure/workspace-title'; import { WorkspaceTitle } from '../../../components/pure/workspace-title';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace'; 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 { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
import { WorkspaceLayout } from '../../../layouts'; import { WorkspaceLayout } from '../../../layouts';
import { NextPageWithLayout } from '../../../shared'; import { NextPageWithLayout } from '../../../shared';
@@ -18,7 +17,6 @@ const FavouritePage: NextPageWithLayout = () => {
const router = useRouter(); const router = useRouter();
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
const { t } = useTranslation(); const { t } = useTranslation();
useLoadWorkspace(currentWorkspace);
useSyncRouterWithCurrentWorkspace(router); useSyncRouterWithCurrentWorkspace(router);
const onClickPage = useCallback( const onClickPage = useCallback(
(pageId: string, newTab?: boolean) => { (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 { PageLoading } from '../../../components/pure/loading';
import { WorkspaceTitle } from '../../../components/pure/workspace-title'; import { WorkspaceTitle } from '../../../components/pure/workspace-title';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace'; 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 { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
import { useWorkspacesHelper } from '../../../hooks/use-workspaces'; import { useWorkspacesHelper } from '../../../hooks/use-workspaces';
import { WorkspaceLayout } from '../../../layouts'; import { WorkspaceLayout } from '../../../layouts';
@@ -33,7 +32,6 @@ const SettingPage: NextPageWithLayout = () => {
const router = useRouter(); const router = useRouter();
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
const { t } = useTranslation(); const { t } = useTranslation();
useLoadWorkspace(currentWorkspace);
useSyncRouterWithCurrentWorkspace(router); useSyncRouterWithCurrentWorkspace(router);
const [currentTab, setCurrentTab] = useAtom(settingPanelAtom); const [currentTab, setCurrentTab] = useAtom(settingPanelAtom);
useEffect(() => {}); useEffect(() => {});

View File

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

View File

@@ -1,8 +1,8 @@
import { createAffineProviders } from '../../blocksuite';
import { Unreachable } from '../../components/affine/affine-error-eoundary'; import { Unreachable } from '../../components/affine/affine-error-eoundary';
import { import {
AffineRemoteUnSyncedWorkspace, AffineRemoteUnSyncedWorkspace,
RemWorkspaceFlavour, RemWorkspaceFlavour,
transformToAffineSyncedWorkspace,
} from '../../shared'; } from '../../shared';
import { apis } from '../../shared/apis'; import { apis } from '../../shared/apis';
import { createEmptyBlockSuiteWorkspace } from '../../utils'; import { createEmptyBlockSuiteWorkspace } from '../../utils';
@@ -42,26 +42,17 @@ export const fetcher = async (
if (query === QueryKey.getWorkspaces) { if (query === QueryKey.getWorkspaces) {
return apis.getWorkspaces().then(workspaces => { return apis.getWorkspaces().then(workspaces => {
return workspaces.map(workspace => { 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 = { const remWorkspace: AffineRemoteUnSyncedWorkspace = {
...workspace, ...workspace,
flavour: RemWorkspaceFlavour.AFFINE, flavour: RemWorkspaceFlavour.AFFINE,
firstBinarySynced: false, blockSuiteWorkspace,
blockSuiteWorkspace: createEmptyBlockSuiteWorkspace( providers: [...createAffineProviders(blockSuiteWorkspace)],
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);
},
}; };
return remWorkspace; return remWorkspace;
}); });

View File

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

View File

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

View File

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