mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-02 18:09:58 +08:00
feat: dc provider
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.29.1",
|
"@playwright/test": "^1.29.1",
|
||||||
|
"fake-indexeddb": "4.0.1",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "^4.8.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
"ky": "^0.33.0",
|
"ky": "^0.33.0",
|
||||||
"lib0": "^0.2.58",
|
"lib0": "^0.2.58",
|
||||||
"swr": "^2.0.0",
|
"swr": "^2.0.0",
|
||||||
|
"yjs": "^13.5.43",
|
||||||
"y-protocols": "^1.0.5"
|
"y-protocols": "^1.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,48 @@
|
|||||||
import { DCProvider, MemoryProvider } from './provider.js';
|
import { Doc } from 'yjs';
|
||||||
|
|
||||||
|
import type { BaseProvider } from './provider/index.js';
|
||||||
|
import { MemoryProvider } from './provider/index.js';
|
||||||
|
import { getKVConfigure } from './store.js';
|
||||||
|
|
||||||
export class DataCenter {
|
export class DataCenter {
|
||||||
private readonly _providers = new Map<string, DCProvider>();
|
private readonly _providers = new Map<string, typeof BaseProvider>();
|
||||||
|
private readonly _workspaces = new Map<string, Promise<Doc | undefined>>();
|
||||||
|
private readonly _config;
|
||||||
|
|
||||||
static async init() {
|
static async init(): Promise<DataCenter> {
|
||||||
const dc = new DataCenter();
|
const dc = new DataCenter();
|
||||||
dc.addProvider(MemoryProvider);
|
dc.addProvider(MemoryProvider);
|
||||||
|
|
||||||
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
// TODO
|
this._config = getKVConfigure('sys');
|
||||||
}
|
}
|
||||||
|
|
||||||
addProvider<P extends DCProvider>(provider: P) {
|
addProvider(provider: typeof BaseProvider) {
|
||||||
this._providers.set(provider.id, provider);
|
this._providers.set(provider.id, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _initWorkspace(id: string): Promise<Doc> {
|
||||||
|
const workspace = new Doc();
|
||||||
|
|
||||||
|
const providerId = await this._config.get(`workspace:${id}:provider`);
|
||||||
|
if (this._providers.has(providerId)) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const Provider = this._providers.get(providerId)!;
|
||||||
|
const provider = new Provider();
|
||||||
|
provider.init(getKVConfigure(id));
|
||||||
|
}
|
||||||
|
return workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getWorkspace(id: string): Promise<Doc | undefined> {
|
||||||
|
if (!this._workspaces.has(id)) {
|
||||||
|
const workspace = this._initWorkspace(id);
|
||||||
|
this._workspaces.set(id, workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._workspaces.get(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
import { IdbInstance } from './store.js';
|
|
||||||
|
|
||||||
export interface DCProvider {
|
|
||||||
id: string;
|
|
||||||
init(config: IdbInstance<any>): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MemoryProvider implements DCProvider {
|
|
||||||
static readonly id = 'memory';
|
|
||||||
private _config: IdbInstance<any> | undefined;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
init(config: IdbInstance<any>) {
|
|
||||||
this._config = config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import type { ConfigStore } from '../store.js';
|
||||||
|
|
||||||
|
export class BaseProvider {
|
||||||
|
static id = 'memory';
|
||||||
|
protected _config: ConfigStore | undefined;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
init(config: ConfigStore) {
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { BaseProvider } from './base.js';
|
||||||
|
export { MemoryProvider } from './memory.js';
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { BaseProvider } from './base.js';
|
||||||
|
|
||||||
|
export class MemoryProvider extends BaseProvider {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import { createStore, del, get, keys, set } from 'idb-keyval';
|
import { createStore, del, get, keys, set } from 'idb-keyval';
|
||||||
|
|
||||||
export type IdbInstance<T = any> = {
|
export type ConfigStore<T = any> = {
|
||||||
get: (key: string) => Promise<T | undefined>;
|
get: (key: string) => Promise<T | undefined>;
|
||||||
set: (key: string, value: T) => Promise<void>;
|
set: (key: string, value: T) => Promise<void>;
|
||||||
keys: () => Promise<string[]>;
|
keys: () => Promise<string[]>;
|
||||||
delete: (key: string) => Promise<void>;
|
delete: (key: string) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialIndexedDB = <T = any>(database: string): IdbInstance<T> => {
|
const initialIndexedDB = <T = any>(database: string): ConfigStore<T> => {
|
||||||
const store = createStore(`affine:${database}`, 'database');
|
const store = createStore(`affine:${database}`, 'database');
|
||||||
return {
|
return {
|
||||||
get: (key: string) => get<T>(key, store),
|
get: (key: string) => get<T>(key, store),
|
||||||
@@ -17,22 +17,31 @@ const initialIndexedDB = <T = any>(database: string): IdbInstance<T> => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const globalIndexedDB = () => {
|
const scopedIndexedDB = () => {
|
||||||
const idb = initialIndexedDB('global');
|
const idb = initialIndexedDB('global');
|
||||||
|
const storeCache = new Map<string, Readonly<ConfigStore>>();
|
||||||
|
|
||||||
return <T = any>(scope: string): IdbInstance<T> => ({
|
return <T = any>(scope: string): Readonly<ConfigStore<T>> => {
|
||||||
get: (key: string) => idb.get(`${scope}:${key}`),
|
if (!storeCache.has(scope)) {
|
||||||
set: (key: string, value: T) => idb.set(`${scope}:${key}`, value),
|
const store = {
|
||||||
keys: () =>
|
get: (key: string) => idb.get(`${scope}:${key}`),
|
||||||
idb
|
set: (key: string, value: T) => idb.set(`${scope}:${key}`, value),
|
||||||
.keys()
|
keys: () =>
|
||||||
.then(keys =>
|
idb
|
||||||
keys
|
.keys()
|
||||||
.filter(k => k.startsWith(`${scope}:`))
|
.then(keys =>
|
||||||
.map(k => k.replace(`${scope}:`, ''))
|
keys
|
||||||
),
|
.filter(k => k.startsWith(`${scope}:`))
|
||||||
delete: (key: string) => del(`${scope}:${key}`),
|
.map(k => k.replace(`${scope}:`, ''))
|
||||||
});
|
),
|
||||||
|
delete: (key: string) => del(`${scope}:${key}`),
|
||||||
|
};
|
||||||
|
|
||||||
|
storeCache.set(scope, store);
|
||||||
|
}
|
||||||
|
|
||||||
|
return storeCache.get(scope) as ConfigStore<T>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getKVConfigure = globalIndexedDB();
|
export const getKVConfigure = scopedIndexedDB();
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
import { getDataCenter } from './utils.js';
|
import { getDataCenter } from './utils.js';
|
||||||
|
|
||||||
|
import 'fake-indexeddb/auto';
|
||||||
|
|
||||||
test('can init data center', async () => {
|
test('can init data center', async () => {
|
||||||
const dataCenter = await getDataCenter();
|
const dataCenter = await getDataCenter();
|
||||||
|
|
||||||
expect(dataCenter).toBeTruthy();
|
expect(dataCenter).toBeTruthy();
|
||||||
|
|
||||||
|
const workspace = await dataCenter.getWorkspace('test');
|
||||||
|
expect(workspace).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|||||||
Generated
+64
@@ -133,6 +133,7 @@ importers:
|
|||||||
specifiers:
|
specifiers:
|
||||||
'@playwright/test': ^1.29.1
|
'@playwright/test': ^1.29.1
|
||||||
encoding: ^0.1.13
|
encoding: ^0.1.13
|
||||||
|
fake-indexeddb: 4.0.1
|
||||||
firebase: ^9.15.0
|
firebase: ^9.15.0
|
||||||
idb-keyval: ^6.2.0
|
idb-keyval: ^6.2.0
|
||||||
ky: ^0.33.0
|
ky: ^0.33.0
|
||||||
@@ -140,6 +141,7 @@ importers:
|
|||||||
swr: ^2.0.0
|
swr: ^2.0.0
|
||||||
typescript: ^4.8.4
|
typescript: ^4.8.4
|
||||||
y-protocols: ^1.0.5
|
y-protocols: ^1.0.5
|
||||||
|
yjs: ^13.5.43
|
||||||
dependencies:
|
dependencies:
|
||||||
encoding: 0.1.13
|
encoding: 0.1.13
|
||||||
firebase: 9.15.0_encoding@0.1.13
|
firebase: 9.15.0_encoding@0.1.13
|
||||||
@@ -148,8 +150,10 @@ importers:
|
|||||||
lib0: 0.2.58
|
lib0: 0.2.58
|
||||||
swr: 2.0.0
|
swr: 2.0.0
|
||||||
y-protocols: 1.0.5
|
y-protocols: 1.0.5
|
||||||
|
yjs: 13.5.44
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@playwright/test': 1.29.1
|
'@playwright/test': 1.29.1
|
||||||
|
fake-indexeddb: 4.0.1
|
||||||
typescript: 4.9.3
|
typescript: 4.9.3
|
||||||
|
|
||||||
packages/logger:
|
packages/logger:
|
||||||
@@ -4278,6 +4282,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/base64-arraybuffer-es6/0.7.0:
|
||||||
|
resolution: {integrity: sha512-ESyU/U1CFZDJUdr+neHRhNozeCv72Y7Vm0m1DCbjX3KBjT6eYocvAJlSk6+8+HkVwXlT1FNxhGW6q3UKAlCvvw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/base64-js/1.5.1:
|
/base64-js/1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -4858,6 +4867,12 @@ packages:
|
|||||||
csstype: 3.1.1
|
csstype: 3.1.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/domexception/1.0.1:
|
||||||
|
resolution: {integrity: sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==}
|
||||||
|
dependencies:
|
||||||
|
webidl-conversions: 4.0.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/domino/2.1.6:
|
/domino/2.1.6:
|
||||||
resolution: {integrity: sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==}
|
resolution: {integrity: sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -5617,6 +5632,12 @@ packages:
|
|||||||
tmp: 0.0.33
|
tmp: 0.0.33
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/fake-indexeddb/4.0.1:
|
||||||
|
resolution: {integrity: sha512-hFRyPmvEZILYgdcLBxVdHLik4Tj3gDTu/g7s9ZDOiU3sTNiGx+vEu1ri/AMsFJUZ/1sdRbAVrEcKndh3sViBcA==}
|
||||||
|
dependencies:
|
||||||
|
realistic-structured-clone: 3.0.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/fast-deep-equal/3.1.3:
|
/fast-deep-equal/3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
dev: true
|
dev: true
|
||||||
@@ -8183,6 +8204,14 @@ packages:
|
|||||||
util-deprecate: 1.0.2
|
util-deprecate: 1.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/realistic-structured-clone/3.0.0:
|
||||||
|
resolution: {integrity: sha512-rOjh4nuWkAqf9PWu6JVpOWD4ndI+JHfgiZeMmujYcPi+fvILUu7g6l26TC1K5aBIp34nV+jE1cDO75EKOfHC5Q==}
|
||||||
|
dependencies:
|
||||||
|
domexception: 1.0.1
|
||||||
|
typeson: 6.1.0
|
||||||
|
typeson-registry: 1.0.0-alpha.39
|
||||||
|
dev: true
|
||||||
|
|
||||||
/redent/3.0.0:
|
/redent/3.0.0:
|
||||||
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
|
resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -8944,6 +8973,13 @@ packages:
|
|||||||
punycode: 2.1.1
|
punycode: 2.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/tr46/2.1.0:
|
||||||
|
resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dependencies:
|
||||||
|
punycode: 2.1.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/trim-newlines/3.0.1:
|
/trim-newlines/3.0.1:
|
||||||
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
|
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@@ -9098,6 +9134,20 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/typeson-registry/1.0.0-alpha.39:
|
||||||
|
resolution: {integrity: sha512-NeGDEquhw+yfwNhguLPcZ9Oj0fzbADiX4R0WxvoY8nGhy98IbzQy1sezjoEFWOywOboj/DWehI+/aUlRVrJnnw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
dependencies:
|
||||||
|
base64-arraybuffer-es6: 0.7.0
|
||||||
|
typeson: 6.1.0
|
||||||
|
whatwg-url: 8.7.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/typeson/6.1.0:
|
||||||
|
resolution: {integrity: sha512-6FTtyGr8ldU0pfbvW/eOZrEtEkczHRUtduBnA90Jh9kMPCiFNnXIon3vF41N0S4tV1HHQt4Hk1j4srpESziCaA==}
|
||||||
|
engines: {node: '>=0.1.14'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/unbox-primitive/1.0.2:
|
/unbox-primitive/1.0.2:
|
||||||
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
|
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9263,6 +9313,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/webidl-conversions/6.1.0:
|
||||||
|
resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==}
|
||||||
|
engines: {node: '>=10.4'}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/webpack-sources/1.4.3:
|
/webpack-sources/1.4.3:
|
||||||
resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==}
|
resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9299,6 +9354,15 @@ packages:
|
|||||||
webidl-conversions: 4.0.2
|
webidl-conversions: 4.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/whatwg-url/8.7.0:
|
||||||
|
resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
dependencies:
|
||||||
|
lodash: 4.17.21
|
||||||
|
tr46: 2.1.0
|
||||||
|
webidl-conversions: 6.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/which-boxed-primitive/1.0.2:
|
/which-boxed-primitive/1.0.2:
|
||||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user