mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-23 10:42:00 +03:00
feat: remove workspace & cloud sync
This commit is contained in:
parent
7fea77b64f
commit
c0626cf8ac
@ -20,7 +20,7 @@ const DynamicBlocksuite = ({
|
||||
new Promise(async resolve => {
|
||||
if (workspaceId) {
|
||||
const workspace = await getDataCenter().then(dc =>
|
||||
dc.initWorkspace(workspaceId, 'affine')
|
||||
dc.getWorkspace(workspaceId, 'affine')
|
||||
);
|
||||
|
||||
resolve(workspace);
|
||||
|
@ -13,18 +13,18 @@ export class DataCenter {
|
||||
private readonly _config;
|
||||
private readonly _logger;
|
||||
|
||||
static async init(): Promise<DataCenter> {
|
||||
const dc = new DataCenter();
|
||||
static async init(debug: boolean): Promise<DataCenter> {
|
||||
const dc = new DataCenter(debug);
|
||||
dc.addProvider(AffineProvider);
|
||||
dc.addProvider(LocalProvider);
|
||||
|
||||
return dc;
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
private constructor(debug: boolean) {
|
||||
this._config = getKVConfigure('sys');
|
||||
this._logger = getLogger('dc');
|
||||
this._logger.enabled = true;
|
||||
this._logger.enabled = debug;
|
||||
}
|
||||
|
||||
private addProvider(provider: typeof BaseProvider) {
|
||||
@ -43,7 +43,7 @@ export class DataCenter {
|
||||
throw Error(`Provider ${providerId} not found`);
|
||||
}
|
||||
|
||||
private async _initWorkspace(id: string, pid: string): Promise<BaseProvider> {
|
||||
private async _getWorkspace(id: string, pid: string): Promise<BaseProvider> {
|
||||
this._logger(`Init workspace ${id} with ${pid}`);
|
||||
|
||||
const providerId = await this._getProvider(id, pid);
|
||||
@ -57,6 +57,7 @@ export class DataCenter {
|
||||
|
||||
await provider.init({
|
||||
config: getKVConfigure(id),
|
||||
debug: this._logger.enabled,
|
||||
logger: this._logger.extend(`${Provider.id}:${id}`),
|
||||
workspace,
|
||||
});
|
||||
@ -66,13 +67,13 @@ export class DataCenter {
|
||||
return provider;
|
||||
}
|
||||
|
||||
async initWorkspace(
|
||||
async getWorkspace(
|
||||
id: string,
|
||||
provider = 'local'
|
||||
): Promise<Workspace | null> {
|
||||
if (id) {
|
||||
if (!this._workspaces.has(id)) {
|
||||
this._workspaces.set(id, this._initWorkspace(id, provider));
|
||||
this._workspaces.set(id, this._getWorkspace(id, provider));
|
||||
}
|
||||
const workspace = this._workspaces.get(id);
|
||||
assert(workspace);
|
||||
@ -86,10 +87,24 @@ export class DataCenter {
|
||||
return config.set(key, value);
|
||||
}
|
||||
|
||||
async getWorkspaceList() {
|
||||
async listWorkspace() {
|
||||
const keys = await this._config.keys();
|
||||
return keys
|
||||
.filter(k => k.startsWith('workspace:'))
|
||||
.map(k => k.split(':')[1]);
|
||||
}
|
||||
|
||||
async removeWorkspace(id: string) {
|
||||
await this._config.delete(`workspace:${id}:provider`);
|
||||
const provider = await this._workspaces.get(id);
|
||||
if (provider) {
|
||||
this._workspaces.delete(id);
|
||||
await provider.clear();
|
||||
}
|
||||
}
|
||||
|
||||
async clearWorkspaces() {
|
||||
const workspaces = await this.listWorkspace();
|
||||
await Promise.all(workspaces.map(id => this.removeWorkspace(id)));
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ import { DataCenter } from './datacenter.js';
|
||||
const _initializeDataCenter = () => {
|
||||
let _dataCenterInstance: Promise<DataCenter>;
|
||||
|
||||
return () => {
|
||||
return (debug = true) => {
|
||||
if (!_dataCenterInstance) {
|
||||
_dataCenterInstance = DataCenter.init();
|
||||
_dataCenterInstance = DataCenter.init(debug);
|
||||
}
|
||||
|
||||
return _dataCenterInstance;
|
||||
|
@ -5,11 +5,13 @@ import type { InitialParams } from '../index.js';
|
||||
import { LocalProvider } from '../local/index.js';
|
||||
|
||||
import { downloadWorkspace } from './apis.js';
|
||||
import { WebsocketProvider } from './sync.js';
|
||||
import { token, Callback } from './token.js';
|
||||
|
||||
export class AffineProvider extends LocalProvider {
|
||||
static id = 'affine';
|
||||
private _onTokenRefresh?: Callback = undefined;
|
||||
private _ws?: WebsocketProvider;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -64,7 +66,21 @@ export class AffineProvider extends LocalProvider {
|
||||
try {
|
||||
const updates = await downloadWorkspace(workspace.room);
|
||||
if (updates) {
|
||||
applyUpdate(doc, new Uint8Array(updates));
|
||||
await new Promise(resolve => {
|
||||
doc.once('update', resolve);
|
||||
applyUpdate(doc, new Uint8Array(updates));
|
||||
});
|
||||
// TODO: wait util data loaded
|
||||
this._ws = new WebsocketProvider('/', workspace.room, doc);
|
||||
// Wait for ws synchronization to complete, otherwise the data will be modified in reverse, which can be optimized later
|
||||
await new Promise<void>((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
|
||||
assert(this._ws);
|
||||
this._ws.once('synced', () => resolve());
|
||||
this._ws.once('lost-connection', () => resolve());
|
||||
this._ws.once('connection-error', () => reject());
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
this._logger('Failed to init cloud workspace', e);
|
||||
|
@ -17,7 +17,12 @@ export class BaseProvider {
|
||||
this._config = params.config;
|
||||
this._logger = params.logger;
|
||||
this._workspace = params.workspace;
|
||||
this._logger.enabled = true;
|
||||
this._logger.enabled = params.debug;
|
||||
}
|
||||
|
||||
async clear() {
|
||||
await this.destroy();
|
||||
await this._config.clear();
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
|
@ -7,6 +7,7 @@ export type Logger = ReturnType<typeof getLogger>;
|
||||
|
||||
export type InitialParams = {
|
||||
config: ConfigStore;
|
||||
debug: boolean;
|
||||
logger: Logger;
|
||||
workspace: Workspace;
|
||||
};
|
||||
|
@ -33,6 +33,12 @@ export class LocalProvider extends BaseProvider {
|
||||
this._logger('Local data loaded');
|
||||
}
|
||||
|
||||
async clear() {
|
||||
await super.clear();
|
||||
await this._blobs.clear();
|
||||
this._idb?.clearData();
|
||||
}
|
||||
|
||||
async destroy(): Promise<void> {
|
||||
super.destroy();
|
||||
if (this._idb) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { createStore, del, get, keys, set } from 'idb-keyval';
|
||||
import { createStore, del, get, keys, set, clear } from 'idb-keyval';
|
||||
|
||||
export type ConfigStore<T = any> = {
|
||||
get: (key: string) => Promise<T | undefined>;
|
||||
set: (key: string, value: T) => Promise<void>;
|
||||
keys: () => Promise<string[]>;
|
||||
delete: (key: string) => Promise<void>;
|
||||
clear: () => Promise<void>;
|
||||
};
|
||||
|
||||
const initialIndexedDB = <T = any>(database: string): ConfigStore<T> => {
|
||||
@ -14,6 +15,7 @@ const initialIndexedDB = <T = any>(database: string): ConfigStore<T> => {
|
||||
set: (key: string, value: T) => set(key, value, store),
|
||||
keys: () => keys(store),
|
||||
delete: (key: string) => del(key, store),
|
||||
clear: () => clear(store),
|
||||
};
|
||||
};
|
||||
|
||||
@ -34,7 +36,16 @@ const scopedIndexedDB = () => {
|
||||
.filter(k => k.startsWith(`${scope}:`))
|
||||
.map(k => k.replace(`${scope}:`, ''))
|
||||
),
|
||||
delete: (key: string) => del(`${scope}:${key}`),
|
||||
delete: (key: string) => idb.delete(`${scope}:${key}`),
|
||||
clear: async () => {
|
||||
await idb
|
||||
.keys()
|
||||
.then(keys =>
|
||||
Promise.all(
|
||||
keys.filter(k => k.startsWith(`${scope}:`)).map(k => del(k))
|
||||
)
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
storeCache.set(scope, store);
|
||||
|
@ -1,6 +1,5 @@
|
||||
export { signInWithGoogle, onAuthStateChanged } from './auth';
|
||||
export * from './sdks';
|
||||
export * from './websocket';
|
||||
|
||||
export { getDataCenter } from './datacenter';
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
export { WebsocketProvider } from './y-websocket';
|
@ -7,43 +7,61 @@ import 'fake-indexeddb/auto';
|
||||
test('init data center', async () => {
|
||||
const dataCenter = await getDataCenter();
|
||||
expect(dataCenter).toBeTruthy();
|
||||
await dataCenter.clearWorkspaces();
|
||||
|
||||
const workspace = await dataCenter.initWorkspace('test');
|
||||
const workspace = await dataCenter.getWorkspace('test1');
|
||||
expect(workspace).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should init error with unknown provider', async () => {
|
||||
const dataCenter = await getDataCenter();
|
||||
await dataCenter.clearWorkspaces();
|
||||
|
||||
test.fail();
|
||||
await dataCenter.initWorkspace('test', 'not exist provider');
|
||||
await dataCenter.getWorkspace('test2', 'not exist provider');
|
||||
});
|
||||
|
||||
test.skip('init affine provider', async () => {
|
||||
const dataCenter = await getDataCenter();
|
||||
await dataCenter.clearWorkspaces();
|
||||
|
||||
// TODO: set constant token for testing
|
||||
await dataCenter.setWorkspaceConfig('6', 'token', 'YOUR_TOKEN');
|
||||
|
||||
const workspace = await dataCenter.initWorkspace('6', 'affine');
|
||||
const workspace = await dataCenter.getWorkspace('6', 'affine');
|
||||
|
||||
expect(workspace).toBeTruthy();
|
||||
});
|
||||
|
||||
test('list workspaces', async () => {
|
||||
const dataCenter = await getDataCenter();
|
||||
await dataCenter.clearWorkspaces();
|
||||
|
||||
await Promise.all([
|
||||
dataCenter.initWorkspace('test1'),
|
||||
dataCenter.initWorkspace('test2'),
|
||||
dataCenter.initWorkspace('test3'),
|
||||
dataCenter.initWorkspace('test4'),
|
||||
dataCenter.getWorkspace('test3'),
|
||||
dataCenter.getWorkspace('test4'),
|
||||
dataCenter.getWorkspace('test5'),
|
||||
dataCenter.getWorkspace('test6'),
|
||||
]);
|
||||
|
||||
expect(await dataCenter.getWorkspaceList()).toStrictEqual([
|
||||
'test1',
|
||||
'test2',
|
||||
expect(await dataCenter.listWorkspace()).toStrictEqual([
|
||||
'test3',
|
||||
'test4',
|
||||
'test5',
|
||||
'test6',
|
||||
]);
|
||||
});
|
||||
|
||||
test('remove workspaces', async () => {
|
||||
const dataCenter = await getDataCenter();
|
||||
await dataCenter.clearWorkspaces();
|
||||
|
||||
await Promise.all([
|
||||
dataCenter.getWorkspace('test7'),
|
||||
dataCenter.getWorkspace('test8'),
|
||||
]);
|
||||
|
||||
await dataCenter.removeWorkspace('test7');
|
||||
|
||||
expect(await dataCenter.listWorkspace()).toStrictEqual(['test8']);
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
export const getDataCenter = () =>
|
||||
import('../src/datacenter/index.js').then(async dataCenter =>
|
||||
dataCenter.getDataCenter()
|
||||
export const getDataCenter = () => {
|
||||
return import('../src/datacenter/index.js').then(async dataCenter =>
|
||||
dataCenter.getDataCenter(false)
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user