mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-29 00:06:09 +08:00
refactor(infra): migrate to new infra (#5565)
This commit is contained in:
@@ -203,6 +203,25 @@ export class ServiceCollection {
|
||||
this.services.set(normalizedScope, services);
|
||||
}
|
||||
|
||||
remove(identifier: ServiceIdentifierValue, scope: ServiceScope = ROOT_SCOPE) {
|
||||
const normalizedScope = stringifyScope(scope);
|
||||
const normalizedIdentifier = parseIdentifier(identifier);
|
||||
const normalizedVariant =
|
||||
normalizedIdentifier.variant ?? DEFAULT_SERVICE_VARIANT;
|
||||
|
||||
const services = this.services.get(normalizedScope);
|
||||
if (!services) {
|
||||
return;
|
||||
}
|
||||
|
||||
const variants = services.get(normalizedIdentifier.identifierName);
|
||||
if (!variants) {
|
||||
return;
|
||||
}
|
||||
|
||||
variants.delete(normalizedVariant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a service provider from the collection.
|
||||
*
|
||||
@@ -365,7 +384,7 @@ class ServiceCollectionEditor {
|
||||
*/
|
||||
override = <
|
||||
Arg1 extends ServiceIdentifier<any>,
|
||||
Arg2 extends Type<Trait> | ServiceFactory<Trait> | Trait,
|
||||
Arg2 extends Type<Trait> | ServiceFactory<Trait> | Trait | null,
|
||||
Trait = ServiceIdentifierType<Arg1>,
|
||||
Deps extends Arg2 extends Type<Trait>
|
||||
? TypesToDeps<ConstructorParameters<Arg2>>
|
||||
@@ -378,7 +397,10 @@ class ServiceCollectionEditor {
|
||||
arg2: Arg2,
|
||||
...[arg3]: Arg3 extends [] ? [] : [Arg3]
|
||||
): this => {
|
||||
if (arg2 instanceof Function) {
|
||||
if (arg2 === null) {
|
||||
this.collection.remove(identifier, this.currentScope);
|
||||
return this;
|
||||
} else if (arg2 instanceof Function) {
|
||||
this.collection.addFactory<any>(
|
||||
identifier,
|
||||
dependenciesToFactory(arg2, arg3 as any[]),
|
||||
|
||||
@@ -26,6 +26,6 @@ export function configureInfraServices(services: ServiceCollection) {
|
||||
|
||||
export function configureTestingInfraServices(services: ServiceCollection) {
|
||||
configureTestingWorkspaceServices(services);
|
||||
services.addImpl(GlobalCache, MemoryMemento);
|
||||
services.addImpl(GlobalState, MemoryMemento);
|
||||
services.override(GlobalCache, MemoryMemento);
|
||||
services.override(GlobalState, MemoryMemento);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export function configurePageServices(services: ServiceCollection) {
|
||||
services
|
||||
.scope(WorkspaceScope)
|
||||
.add(PageListService, [Workspace])
|
||||
.add(PageManager, [Workspace, ServiceProvider]);
|
||||
.add(PageManager, [Workspace, PageListService, ServiceProvider]);
|
||||
services
|
||||
.scope(PageScope)
|
||||
.add(CleanupService)
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { PageMeta } from '@blocksuite/store';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { LiveData } from '../livedata';
|
||||
import type { Workspace } from '../workspace';
|
||||
import { SyncEngineStep, type Workspace } from '../workspace';
|
||||
|
||||
export class PageListService {
|
||||
constructor(private readonly workspace: Workspace) {}
|
||||
@@ -25,4 +25,26 @@ export class PageListService {
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
public readonly isReady = LiveData.from<boolean>(
|
||||
new Observable(subscriber => {
|
||||
subscriber.next(
|
||||
this.workspace.engine.status.sync.step === SyncEngineStep.Synced
|
||||
);
|
||||
|
||||
const dispose = this.workspace.engine.onStatusChange.on(() => {
|
||||
subscriber.next(
|
||||
this.workspace.engine.status.sync.step === SyncEngineStep.Synced
|
||||
);
|
||||
}).dispose;
|
||||
return () => {
|
||||
dispose();
|
||||
};
|
||||
}),
|
||||
false
|
||||
);
|
||||
|
||||
public getPageMetaById(id: string) {
|
||||
return this.pages.value.find(page => page.id === id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
|
||||
import type { ServiceProvider } from '../di';
|
||||
import { ObjectPool, type RcRef } from '../utils/object-pool';
|
||||
import { ObjectPool } from '../utils/object-pool';
|
||||
import type { Workspace } from '../workspace';
|
||||
import { configurePageContext } from './context';
|
||||
import type { PageListService } from './list';
|
||||
import { Page } from './page';
|
||||
import { PageScope } from './service-scope';
|
||||
|
||||
@@ -12,10 +13,20 @@ export class PageManager {
|
||||
|
||||
constructor(
|
||||
private readonly workspace: Workspace,
|
||||
private readonly pageList: PageListService,
|
||||
private readonly serviceProvider: ServiceProvider
|
||||
) {}
|
||||
|
||||
open(pageMeta: PageMeta): RcRef<Page> {
|
||||
openByPageId(pageId: string) {
|
||||
const pageMeta = this.pageList.getPageMetaById(pageId);
|
||||
if (!pageMeta) {
|
||||
throw new Error('Page not found');
|
||||
}
|
||||
|
||||
return this.open(pageMeta);
|
||||
}
|
||||
|
||||
open(pageMeta: PageMeta) {
|
||||
const blockSuitePage = this.workspace.blockSuiteWorkspace.getPage(
|
||||
pageMeta.id
|
||||
);
|
||||
@@ -25,7 +36,7 @@ export class PageManager {
|
||||
|
||||
const exists = this.pool.get(pageMeta.id);
|
||||
if (exists) {
|
||||
return exists;
|
||||
return { page: exists.obj, release: exists.release };
|
||||
}
|
||||
|
||||
const serviceCollection = this.serviceProvider.collection
|
||||
@@ -41,6 +52,8 @@ export class PageManager {
|
||||
|
||||
const page = provider.get(Page);
|
||||
|
||||
return this.pool.put(pageMeta.id, page);
|
||||
const { obj, release } = this.pool.put(pageMeta.id, page);
|
||||
|
||||
return { page: obj, release };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,6 @@ export const AwarenessProvider =
|
||||
export class AwarenessEngine {
|
||||
constructor(public readonly providers: AwarenessProvider[]) {}
|
||||
|
||||
static get EMPTY() {
|
||||
return new AwarenessEngine([]);
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.providers.forEach(provider => provider.connect());
|
||||
}
|
||||
|
||||
@@ -54,10 +54,6 @@ export class BlobEngine {
|
||||
private readonly remotes: BlobStorage[]
|
||||
) {}
|
||||
|
||||
static get EMPTY() {
|
||||
return new BlobEngine(createEmptyBlobStorage(), []);
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.abort || this._status.isStorageOverCapacity) {
|
||||
return;
|
||||
@@ -222,21 +218,19 @@ export class BlobEngine {
|
||||
}
|
||||
}
|
||||
|
||||
export function createEmptyBlobStorage() {
|
||||
return {
|
||||
name: 'empty',
|
||||
readonly: true,
|
||||
async get(_key: string) {
|
||||
return null;
|
||||
},
|
||||
async set(_key: string, _value: Blob) {
|
||||
throw new Error('not supported');
|
||||
},
|
||||
async delete(_key: string) {
|
||||
throw new Error('not supported');
|
||||
},
|
||||
async list() {
|
||||
return [];
|
||||
},
|
||||
} satisfies BlobStorage;
|
||||
}
|
||||
export const EmptyBlobStorage: BlobStorage = {
|
||||
name: 'empty',
|
||||
readonly: true,
|
||||
async get(_key: string) {
|
||||
return null;
|
||||
},
|
||||
async set(_key: string, _value: Blob) {
|
||||
throw new Error('not supported');
|
||||
},
|
||||
async delete(_key: string) {
|
||||
throw new Error('not supported');
|
||||
},
|
||||
async list() {
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
@@ -23,3 +23,22 @@ export interface SyncStorage {
|
||||
disconnect: (reason: string) => void
|
||||
): Promise<() => void>;
|
||||
}
|
||||
|
||||
export const EmptySyncStorage: SyncStorage = {
|
||||
name: 'empty',
|
||||
pull: async () => null,
|
||||
push: async () => {},
|
||||
subscribe: async () => () => {},
|
||||
};
|
||||
|
||||
export const ReadonlyMappingSyncStorage = (map: {
|
||||
[key: string]: Uint8Array;
|
||||
}): SyncStorage => ({
|
||||
name: 'map',
|
||||
pull: async (id: string) => {
|
||||
const data = map[id];
|
||||
return data ? { data } : null;
|
||||
},
|
||||
push: async () => {},
|
||||
subscribe: async () => () => {},
|
||||
});
|
||||
|
||||
@@ -74,8 +74,14 @@ export function configureWorkspaceServices(services: ServiceCollection) {
|
||||
|
||||
export function configureTestingWorkspaceServices(services: ServiceCollection) {
|
||||
services
|
||||
.addImpl(WorkspaceListProvider, TestingLocalWorkspaceListProvider, [
|
||||
.override(WorkspaceListProvider('affine-cloud'), null)
|
||||
.override(WorkspaceFactory('affine-cloud'), null)
|
||||
.override(
|
||||
WorkspaceListProvider('local'),
|
||||
TestingLocalWorkspaceListProvider,
|
||||
[GlobalState]
|
||||
)
|
||||
.override(WorkspaceFactory('local'), TestingLocalWorkspaceFactory, [
|
||||
GlobalState,
|
||||
])
|
||||
.addImpl(WorkspaceFactory, TestingLocalWorkspaceFactory, [GlobalState]);
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||
import { applyUpdate, encodeStateAsUpdate } from 'yjs';
|
||||
|
||||
import { fixWorkspaceVersion } from '../blocksuite';
|
||||
import type { ServiceProvider } from '../di';
|
||||
import type { ServiceCollection, ServiceProvider } from '../di';
|
||||
import { ObjectPool } from '../utils/object-pool';
|
||||
import { configureWorkspaceContext } from './context';
|
||||
import type { BlobStorage } from './engine';
|
||||
@@ -90,6 +90,9 @@ export class WorkspaceManager {
|
||||
}
|
||||
|
||||
const workspace = this.instantiate(metadata);
|
||||
// sync information with workspace list, when workspace's avatar and name changed, information will be updated
|
||||
this.list.getInformation(metadata).syncWithWorkspace(workspace);
|
||||
|
||||
const ref = this.pool.put(workspace.meta.id, workspace);
|
||||
|
||||
return {
|
||||
@@ -164,14 +167,21 @@ export class WorkspaceManager {
|
||||
return factory.getWorkspaceBlob(metadata.id, blobKey);
|
||||
}
|
||||
|
||||
private instantiate(metadata: WorkspaceMetadata) {
|
||||
instantiate(
|
||||
metadata: WorkspaceMetadata,
|
||||
configureWorkspace?: (serviceCollection: ServiceCollection) => void
|
||||
) {
|
||||
logger.info(`open workspace [${metadata.flavour}] ${metadata.id} `);
|
||||
const factory = this.factories.find(x => x.name === metadata.flavour);
|
||||
if (!factory) {
|
||||
throw new Error(`Unknown workspace flavour: ${metadata.flavour}`);
|
||||
}
|
||||
const serviceCollection = this.serviceProvider.collection.clone();
|
||||
factory.configureWorkspace(serviceCollection);
|
||||
if (configureWorkspace) {
|
||||
configureWorkspace(serviceCollection);
|
||||
} else {
|
||||
const factory = this.factories.find(x => x.name === metadata.flavour);
|
||||
if (!factory) {
|
||||
throw new Error(`Unknown workspace flavour: ${metadata.flavour}`);
|
||||
}
|
||||
factory.configureWorkspace(serviceCollection);
|
||||
}
|
||||
configureWorkspaceContext(serviceCollection, metadata);
|
||||
const provider = serviceCollection.provider(
|
||||
WorkspaceScope,
|
||||
@@ -179,9 +189,6 @@ export class WorkspaceManager {
|
||||
);
|
||||
const workspace = provider.get(Workspace);
|
||||
|
||||
// sync information with workspace list, when workspace's avatar and name changed, information will be updated
|
||||
this.list.getInformation(metadata).syncWithWorkspace(workspace);
|
||||
|
||||
// apply compatibility fix
|
||||
fixWorkspaceVersion(workspace.blockSuiteWorkspace.doc);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user