| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import { Origin, YDocStatus } from '@growi/core';
- import type { Delta } from '@growi/editor';
- import type { WSSharedDoc } from 'y-websocket/bin/utils';
- import loggerFactory from '~/utils/logger';
- import { Revision } from '../../models/revision';
- import { normalizeLatestRevisionIfBroken } from '../revision/normalize-latest-revision-if-broken';
- import type { MongodbPersistence } from './extended/mongodb-persistence';
- const logger = loggerFactory('growi:service:yjs:sync-ydoc');
- 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: WSSharedDoc,
- context: true | Context,
- ): Promise<void> => {
- const pageId = doc.name;
- // Normalize the latest revision which was borken by the migration script '20211227060705-revision-path-to-page-id-schema-migration--fixed-7549.js' provided by v6.1.0 - v7.0.15
- await normalizeLatestRevisionIfBroken(pageId);
- 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(),
- );
- }
- };
|