mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
feat(core): doc level awareness (#10646)
This commit is contained in:
@@ -39,6 +39,7 @@ import { type Framework } from '@toeverything/infra';
|
||||
|
||||
import { DocScope } from '../doc/scopes/doc';
|
||||
import { DocService } from '../doc/services/doc';
|
||||
import { EditorScope } from '../editor';
|
||||
import { GlobalCache, GlobalState } from '../storage/providers/global';
|
||||
import { GlobalStateService } from '../storage/services/global';
|
||||
import { UrlService } from '../url';
|
||||
@@ -63,6 +64,7 @@ import { AuthService } from './services/auth';
|
||||
import { CaptchaService } from './services/captcha';
|
||||
import { CloudDocMetaService } from './services/cloud-doc-meta';
|
||||
import { DefaultServerService } from './services/default-server';
|
||||
import { EditorUserCursorLabelService } from './services/editor-user-cursor-label';
|
||||
import { EventSourceService } from './services/eventsource';
|
||||
import { FetchService } from './services/fetch';
|
||||
import { GraphQLService } from './services/graphql';
|
||||
@@ -168,4 +170,10 @@ export function configureCloudModule(framework: Framework) {
|
||||
.entity(WorkspaceInvoices, [WorkspaceService, WorkspaceServerService])
|
||||
.service(SelfhostLicenseService, [SelfhostLicenseStore, WorkspaceService])
|
||||
.store(SelfhostLicenseStore, [WorkspaceServerService]);
|
||||
|
||||
framework
|
||||
.scope(WorkspaceScope)
|
||||
.scope(DocScope)
|
||||
.scope(EditorScope)
|
||||
.service(EditorUserCursorLabelService, [WorkspaceServerService]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { OnEvent, Service } from '@toeverything/infra';
|
||||
|
||||
import type { Editor } from '../../editor';
|
||||
import { EditorInitialized } from '../../editor/events';
|
||||
import type { WorkspaceServerService } from './workspace-server';
|
||||
|
||||
@OnEvent(EditorInitialized, i => i.onEditorInitialized)
|
||||
export class EditorUserCursorLabelService extends Service {
|
||||
constructor(private readonly workspaceServerService: WorkspaceServerService) {
|
||||
super();
|
||||
}
|
||||
|
||||
onEditorInitialized(editor: Editor) {
|
||||
if (this.workspaceServerService.server) {
|
||||
const subscription =
|
||||
this.workspaceServerService.server.account$.subscribe(account => {
|
||||
editor.doc.blockSuiteDoc.awarenessStore.awareness.setLocalStateField(
|
||||
'user',
|
||||
{
|
||||
name: account?.label,
|
||||
}
|
||||
);
|
||||
});
|
||||
this.disposables.push(() => subscription.unsubscribe());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import { createEvent } from '@toeverything/infra';
|
||||
|
||||
import type { Doc } from '../entities/doc';
|
||||
import type { DocRecord } from '../entities/record';
|
||||
|
||||
export const DocCreated = createEvent<DocRecord>('DocCreated');
|
||||
|
||||
export const DocInitialized = createEvent<Doc>('DocInitialized');
|
||||
|
||||
@@ -20,7 +20,7 @@ import { getAFFiNEWorkspaceSchema } from '../../workspace';
|
||||
import type { Doc } from '../entities/doc';
|
||||
import { DocPropertyList } from '../entities/property-list';
|
||||
import { DocRecordList } from '../entities/record-list';
|
||||
import { DocCreated } from '../events';
|
||||
import { DocCreated, DocInitialized } from '../events';
|
||||
import { DocScope } from '../scopes/doc';
|
||||
import type { DocPropertiesStore } from '../stores/doc-properties';
|
||||
import type { DocsStore } from '../stores/docs';
|
||||
@@ -105,6 +105,8 @@ export class DocsService extends Service {
|
||||
|
||||
const doc = docScope.get(DocService).doc;
|
||||
|
||||
doc.scope.emitEvent(DocInitialized, doc);
|
||||
|
||||
const { obj, release } = this.pool.put(docId, doc);
|
||||
|
||||
return { doc: obj, release };
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { createEvent } from '@toeverything/infra';
|
||||
|
||||
import type { Editor } from '../entities/editor';
|
||||
|
||||
export const EditorInitialized = createEvent<Editor>('EditorInitialized');
|
||||
@@ -1,9 +1,12 @@
|
||||
import { Service } from '@toeverything/infra';
|
||||
|
||||
import { Editor } from '../entities/editor';
|
||||
import { EditorInitialized } from '../events';
|
||||
|
||||
export class EditorsService extends Service {
|
||||
createEditor() {
|
||||
return this.framework.createEntity(Editor);
|
||||
const editor = this.framework.createEntity(Editor);
|
||||
editor.scope.emitEvent(EditorInitialized, editor);
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { Workspace as WorkspaceInterface } from '@blocksuite/affine/store';
|
||||
import { Entity, LiveData } from '@toeverything/infra';
|
||||
import { Observable } from 'rxjs';
|
||||
import type { Awareness } from 'y-protocols/awareness.js';
|
||||
|
||||
import { WorkspaceImpl } from '../impls/workspace';
|
||||
import type { WorkspaceScope } from '../scopes/workspace';
|
||||
@@ -58,10 +57,6 @@ export class Workspace extends Entity {
|
||||
return this._docCollection;
|
||||
}
|
||||
|
||||
get awareness() {
|
||||
return this.docCollection.awarenessStore.awareness as Awareness;
|
||||
}
|
||||
|
||||
get rootYDoc() {
|
||||
return this.docCollection.doc;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SpecProvider } from '@blocksuite/affine/blocks';
|
||||
import { Slot } from '@blocksuite/affine/global/utils';
|
||||
import {
|
||||
type AwarenessStore,
|
||||
AwarenessStore,
|
||||
type Doc,
|
||||
type GetBlocksOptions,
|
||||
type Query,
|
||||
@@ -10,13 +10,13 @@ import {
|
||||
type YBlock,
|
||||
} from '@blocksuite/affine/store';
|
||||
import { signal } from '@preact/signals-core';
|
||||
import { Awareness } from 'y-protocols/awareness.js';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
type DocOptions = {
|
||||
id: string;
|
||||
collection: Workspace;
|
||||
doc: Y.Doc;
|
||||
awarenessStore: AwarenessStore;
|
||||
};
|
||||
|
||||
export class DocImpl implements Doc {
|
||||
@@ -155,12 +155,11 @@ export class DocImpl implements Doc {
|
||||
return this._yBlocks;
|
||||
}
|
||||
|
||||
constructor({ id, collection, doc, awarenessStore }: DocOptions) {
|
||||
constructor({ id, collection, doc }: DocOptions) {
|
||||
this.id = id;
|
||||
this.rootDoc = doc;
|
||||
this.awarenessStore = awarenessStore;
|
||||
|
||||
this._ySpaceDoc = this._initSubDoc() as Y.Doc;
|
||||
this.awarenessStore = new AwarenessStore(new Awareness(this._ySpaceDoc));
|
||||
|
||||
this._yBlocks = this._ySpaceDoc.getMap('blocks');
|
||||
this._collection = collection;
|
||||
@@ -228,12 +227,14 @@ export class DocImpl implements Doc {
|
||||
}
|
||||
|
||||
private _destroy() {
|
||||
this.awarenessStore.destroy();
|
||||
this._ySpaceDoc.destroy();
|
||||
this._onLoadSlot.dispose();
|
||||
this._loaded = false;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._destroy();
|
||||
this.slots.historyUpdated.dispose();
|
||||
|
||||
if (this.ready) {
|
||||
@@ -303,6 +304,7 @@ export class DocImpl implements Doc {
|
||||
|
||||
this.spaceDoc.load();
|
||||
this.workspace.onLoadDoc?.(this.spaceDoc);
|
||||
this.workspace.onLoadAwareness?.(this.awarenessStore.awareness);
|
||||
|
||||
this._initYBlocks();
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
} from '@blocksuite/affine/global/exceptions';
|
||||
import { NoopLogger, Slot } from '@blocksuite/affine/global/utils';
|
||||
import {
|
||||
AwarenessStore,
|
||||
type CreateBlocksOptions,
|
||||
type Doc,
|
||||
type GetBlocksOptions,
|
||||
@@ -19,7 +18,7 @@ import {
|
||||
type BlobSource,
|
||||
MemoryBlobSource,
|
||||
} from '@blocksuite/affine/sync';
|
||||
import { Awareness } from 'y-protocols/awareness.js';
|
||||
import type { Awareness } from 'y-protocols/awareness.js';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import { DocImpl } from './doc';
|
||||
@@ -33,8 +32,6 @@ type WorkspaceOptions = {
|
||||
};
|
||||
|
||||
export class WorkspaceImpl implements Workspace {
|
||||
readonly awarenessStore: AwarenessStore;
|
||||
|
||||
readonly blobSync: BlobEngine;
|
||||
|
||||
readonly blockCollections = new Map<string, Doc>();
|
||||
@@ -68,11 +65,9 @@ export class WorkspaceImpl implements Workspace {
|
||||
}: WorkspaceOptions = {}) {
|
||||
this.id = id || '';
|
||||
this.doc = new Y.Doc({ guid: id });
|
||||
this.awarenessStore = new AwarenessStore(new Awareness(this.doc));
|
||||
this.onLoadDoc = onLoadDoc;
|
||||
this.onLoadAwareness = onLoadAwareness;
|
||||
this.onLoadDoc?.(this.doc);
|
||||
this.onLoadAwareness?.(this.awarenessStore.awareness);
|
||||
this.onLoadAwareness = onLoadAwareness;
|
||||
|
||||
blobSource = blobSource ?? new MemoryBlobSource();
|
||||
const logger = new NoopLogger();
|
||||
@@ -91,7 +86,6 @@ export class WorkspaceImpl implements Workspace {
|
||||
id: docId,
|
||||
collection: this,
|
||||
doc: this.doc,
|
||||
awarenessStore: this.awarenessStore,
|
||||
});
|
||||
this.blockCollections.set(doc.id, doc);
|
||||
});
|
||||
@@ -139,10 +133,6 @@ export class WorkspaceImpl implements Workspace {
|
||||
}) as Store;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.awarenessStore.destroy();
|
||||
}
|
||||
|
||||
private _getDoc(docId: string): Doc | null {
|
||||
const space = this.docs.get(docId) as Doc | undefined;
|
||||
return space ?? null;
|
||||
@@ -172,4 +162,8 @@ export class WorkspaceImpl implements Workspace {
|
||||
this.meta.removeDocMeta(docId);
|
||||
this.blockCollections.delete(docId);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.blockCollections.forEach(doc => doc.dispose());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user