feat: dc provider

This commit is contained in:
DarkSky
2022-12-29 21:20:26 +08:00
committed by DarkSky
parent e6e4c775a8
commit 2bf6bf7ed8
9 changed files with 155 additions and 42 deletions

View File

@@ -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 {
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();
dc.addProvider(MemoryProvider);
return dc;
}
private constructor() {
// TODO
this._config = getKVConfigure('sys');
}
addProvider<P extends DCProvider>(provider: P) {
addProvider(provider: typeof BaseProvider) {
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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -0,0 +1,2 @@
export { BaseProvider } from './base.js';
export { MemoryProvider } from './memory.js';

View File

@@ -0,0 +1,7 @@
import { BaseProvider } from './base.js';
export class MemoryProvider extends BaseProvider {
constructor() {
super();
}
}

View File

@@ -1,13 +1,13 @@
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>;
set: (key: string, value: T) => Promise<void>;
keys: () => Promise<string[]>;
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');
return {
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 storeCache = new Map<string, Readonly<ConfigStore>>();
return <T = any>(scope: string): IdbInstance<T> => ({
get: (key: string) => idb.get(`${scope}:${key}`),
set: (key: string, value: T) => idb.set(`${scope}:${key}`, value),
keys: () =>
idb
.keys()
.then(keys =>
keys
.filter(k => k.startsWith(`${scope}:`))
.map(k => k.replace(`${scope}:`, ''))
),
delete: (key: string) => del(`${scope}:${key}`),
});
return <T = any>(scope: string): Readonly<ConfigStore<T>> => {
if (!storeCache.has(scope)) {
const store = {
get: (key: string) => idb.get(`${scope}:${key}`),
set: (key: string, value: T) => idb.set(`${scope}:${key}`, value),
keys: () =>
idb
.keys()
.then(keys =>
keys
.filter(k => k.startsWith(`${scope}:`))
.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();