fix(workspace): should avoid sending providers' update back (#3384)

This commit is contained in:
liuyi 2023-07-26 17:47:24 +08:00 committed by GitHub
parent 2c249781a2
commit 6bafa83cef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 11 deletions

View File

@ -53,7 +53,7 @@ export const createSQLiteProvider: DocProviderCreator = (
passive: true,
connect: () => {
datasource = createDatasource(id);
provider = createLazyProvider(rootDoc, datasource);
provider = createLazyProvider(rootDoc, datasource, { origin: 'sqlite' });
provider.connect();
connected = true;
},

View File

@ -114,7 +114,7 @@ export const createIndexedDBProvider = (
return {
connect: () => {
datasource = createDatasource({ dbName, mergeCount });
provider = createLazyProvider(doc, datasource);
provider = createLazyProvider(doc, datasource, { origin: 'idb' });
provider.connect();
},
disconnect: () => {

View File

@ -1,6 +1,6 @@
import { setTimeout } from 'node:timers/promises';
import { describe, expect, test } from 'vitest';
import { describe, expect, test, vi } from 'vitest';
import { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
import { createLazyProvider } from '../lazy-provider';
@ -178,4 +178,19 @@ describe('y-provider', () => {
expect(provider.connected).toBe(false);
});
test('should not send remote update back', async () => {
const remoteRootDoc = new Doc(); // this is the remote doc lives in remote
const datasource = createMemoryDatasource(remoteRootDoc);
const spy = vi.spyOn(datasource, 'sendDocUpdate');
const rootDoc = new Doc({ guid: remoteRootDoc.guid }); // this is the doc that we want to sync
const provider = createLazyProvider(rootDoc, datasource);
provider.connect();
remoteRootDoc.getText('text').insert(0, 'test-value');
expect(spy).not.toBeCalled();
});
});

View File

@ -9,8 +9,6 @@ import {
import type { DatasourceDocAdapter } from './types';
const selfUpdateOrigin = 'lazy-provider-self-origin';
function getDoc(doc: Doc, guid: string): Doc | undefined {
if (doc.guid === guid) {
return doc;
@ -24,12 +22,17 @@ function getDoc(doc: Doc, guid: string): Doc | undefined {
return undefined;
}
interface LazyProviderOptions {
origin?: string;
}
/**
* Creates a lazy provider that connects to a datasource and synchronizes a root document.
*/
export const createLazyProvider = (
rootDoc: Doc,
datasource: DatasourceDocAdapter
datasource: DatasourceDocAdapter,
options: LazyProviderOptions = {}
): Omit<PassiveDocProvider, 'flavour'> => {
let connected = false;
const pendingMap = new Map<string, Uint8Array[]>(); // guid -> pending-updates
@ -37,6 +40,8 @@ export const createLazyProvider = (
const connectedDocs = new Set<string>();
let datasourceUnsub: (() => void) | undefined;
const { origin = 'lazy-provider' } = options;
async function syncDoc(doc: Doc) {
const guid = doc.guid;
@ -47,7 +52,7 @@ export const createLazyProvider = (
pendingMap.set(guid, []);
if (remoteUpdate) {
applyUpdate(doc, remoteUpdate, selfUpdateOrigin);
applyUpdate(doc, remoteUpdate, origin);
}
const sv = remoteUpdate
@ -67,8 +72,8 @@ export const createLazyProvider = (
function setupDocListener(doc: Doc) {
const disposables = new Set<() => void>();
disposableMap.set(doc.guid, disposables);
const updateHandler = async (update: Uint8Array, origin: unknown) => {
if (origin === selfUpdateOrigin) {
const updateHandler = async (update: Uint8Array, updateOrigin: unknown) => {
if (origin === updateOrigin) {
return;
}
datasource.sendDocUpdate(doc.guid, update).catch(console.error);
@ -100,10 +105,12 @@ export const createLazyProvider = (
datasourceUnsub = datasource.onDocUpdate?.((guid, update) => {
const doc = getDoc(rootDoc, guid);
if (doc) {
applyUpdate(doc, update);
applyUpdate(doc, update, origin);
//
if (pendingMap.has(guid)) {
pendingMap.get(guid)?.forEach(update => applyUpdate(doc, update));
pendingMap
.get(guid)
?.forEach(update => applyUpdate(doc, update, origin));
pendingMap.delete(guid);
}
} else {