Files
AFFiNE-Mirror/packages/workspace/src/providers/index.ts
2023-04-05 21:01:12 -05:00

123 lines
3.5 KiB
TypeScript

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 {
createIndexedDBProvider as create,
EarlyDisconnectError,
} from '@toeverything/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 => {
const indexeddbProvider = create(
blockSuiteWorkspace.id,
blockSuiteWorkspace.doc
);
const callbacks = new Set<() => void>();
return {
flavour: 'local-indexeddb',
callbacks,
// fixme: remove background long polling
background: true,
cleanup: () => {
// todo: cleanup data
},
connect: () => {
localProviderLogger.info(
'connect indexeddb provider',
blockSuiteWorkspace.id
);
indexeddbProvider.connect();
indexeddbProvider.whenSynced
.then(() => {
callbacks.forEach(cb => cb());
})
.catch(error => {
if (error instanceof EarlyDisconnectError) {
return;
} else {
throw error;
}
});
},
disconnect: () => {
assertExists(indexeddbProvider);
localProviderLogger.info(
'disconnect indexeddb provider',
blockSuiteWorkspace.id
);
indexeddbProvider.disconnect();
},
};
};
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));
};