| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- import { Origin, YDocStatus } from '@growi/core';
- import type { Document } from 'y-socket.io/dist/server';
- import loggerFactory from '~/utils/logger';
- import { Revision } from '../../models/revision';
- import type { MongodbPersistence } from './extended/mongodb-persistence';
- const logger = loggerFactory('growi:service:yjs:sync-ydoc');
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- type Delta = Array<{insert?:Array<any>|string, delete?:number, retain?:number}>;
- type Context = {
- ydocStatus: YDocStatus,
- }
- /**
- * Sync the text and the meta data with the latest revision body
- * @param mdb
- * @param doc
- * @param context true to force sync
- */
- export const syncYDoc = async(mdb: MongodbPersistence, doc: Document, context: true | Context): Promise<void> => {
- const pageId = doc.name;
- const revision = await Revision
- .findOne(
- // filter
- { pageId },
- // projection
- { body: 1, createdAt: 1, origin: 1 },
- // options
- { sort: { createdAt: -1 } },
- )
- .lean();
- if (revision == null) {
- logger.warn(`Synchronization has been canceled since the revision of the page ('${pageId}') could not be found`);
- return;
- }
- const shouldSync = context === true
- || (() => {
- switch (context.ydocStatus) {
- case YDocStatus.NEW:
- return true;
- case YDocStatus.OUTDATED:
- // should skip when the YDoc is outdated and the latest revision is created by the editor
- return revision.origin !== Origin.Editor;
- default:
- return false;
- }
- })();
- if (shouldSync) {
- logger.debug(`YDoc for the page ('${pageId}') is synced with the latest revision body`);
- const ytext = doc.getText('codemirror');
- const delta: Delta = [];
- if (ytext.length > 0) {
- delta.push({ delete: ytext.length });
- }
- if (revision.body != null) {
- delta.push({ insert: revision.body });
- }
- ytext.applyDelta(delta, { sanitize: false });
- }
- const shouldSyncMeta = context === true
- || context.ydocStatus === YDocStatus.NEW
- || context.ydocStatus === YDocStatus.OUTDATED;
- if (shouldSyncMeta) {
- mdb.setMeta(doc.name, 'updatedAt', revision.createdAt.getTime() ?? Date.now());
- }
- };
|