mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 22:37:04 +08:00
fix(workspace): should avoid sending providers' update back (#3384)
This commit is contained in:
@@ -53,7 +53,7 @@ export const createSQLiteProvider: DocProviderCreator = (
|
|||||||
passive: true,
|
passive: true,
|
||||||
connect: () => {
|
connect: () => {
|
||||||
datasource = createDatasource(id);
|
datasource = createDatasource(id);
|
||||||
provider = createLazyProvider(rootDoc, datasource);
|
provider = createLazyProvider(rootDoc, datasource, { origin: 'sqlite' });
|
||||||
provider.connect();
|
provider.connect();
|
||||||
connected = true;
|
connected = true;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export const createIndexedDBProvider = (
|
|||||||
return {
|
return {
|
||||||
connect: () => {
|
connect: () => {
|
||||||
datasource = createDatasource({ dbName, mergeCount });
|
datasource = createDatasource({ dbName, mergeCount });
|
||||||
provider = createLazyProvider(doc, datasource);
|
provider = createLazyProvider(doc, datasource, { origin: 'idb' });
|
||||||
provider.connect();
|
provider.connect();
|
||||||
},
|
},
|
||||||
disconnect: () => {
|
disconnect: () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { setTimeout } from 'node:timers/promises';
|
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 { applyUpdate, Doc, encodeStateAsUpdate } from 'yjs';
|
||||||
|
|
||||||
import { createLazyProvider } from '../lazy-provider';
|
import { createLazyProvider } from '../lazy-provider';
|
||||||
@@ -178,4 +178,19 @@ describe('y-provider', () => {
|
|||||||
|
|
||||||
expect(provider.connected).toBe(false);
|
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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import {
|
|||||||
|
|
||||||
import type { DatasourceDocAdapter } from './types';
|
import type { DatasourceDocAdapter } from './types';
|
||||||
|
|
||||||
const selfUpdateOrigin = 'lazy-provider-self-origin';
|
|
||||||
|
|
||||||
function getDoc(doc: Doc, guid: string): Doc | undefined {
|
function getDoc(doc: Doc, guid: string): Doc | undefined {
|
||||||
if (doc.guid === guid) {
|
if (doc.guid === guid) {
|
||||||
return doc;
|
return doc;
|
||||||
@@ -24,12 +22,17 @@ function getDoc(doc: Doc, guid: string): Doc | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LazyProviderOptions {
|
||||||
|
origin?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a lazy provider that connects to a datasource and synchronizes a root document.
|
* Creates a lazy provider that connects to a datasource and synchronizes a root document.
|
||||||
*/
|
*/
|
||||||
export const createLazyProvider = (
|
export const createLazyProvider = (
|
||||||
rootDoc: Doc,
|
rootDoc: Doc,
|
||||||
datasource: DatasourceDocAdapter
|
datasource: DatasourceDocAdapter,
|
||||||
|
options: LazyProviderOptions = {}
|
||||||
): Omit<PassiveDocProvider, 'flavour'> => {
|
): Omit<PassiveDocProvider, 'flavour'> => {
|
||||||
let connected = false;
|
let connected = false;
|
||||||
const pendingMap = new Map<string, Uint8Array[]>(); // guid -> pending-updates
|
const pendingMap = new Map<string, Uint8Array[]>(); // guid -> pending-updates
|
||||||
@@ -37,6 +40,8 @@ export const createLazyProvider = (
|
|||||||
const connectedDocs = new Set<string>();
|
const connectedDocs = new Set<string>();
|
||||||
let datasourceUnsub: (() => void) | undefined;
|
let datasourceUnsub: (() => void) | undefined;
|
||||||
|
|
||||||
|
const { origin = 'lazy-provider' } = options;
|
||||||
|
|
||||||
async function syncDoc(doc: Doc) {
|
async function syncDoc(doc: Doc) {
|
||||||
const guid = doc.guid;
|
const guid = doc.guid;
|
||||||
|
|
||||||
@@ -47,7 +52,7 @@ export const createLazyProvider = (
|
|||||||
pendingMap.set(guid, []);
|
pendingMap.set(guid, []);
|
||||||
|
|
||||||
if (remoteUpdate) {
|
if (remoteUpdate) {
|
||||||
applyUpdate(doc, remoteUpdate, selfUpdateOrigin);
|
applyUpdate(doc, remoteUpdate, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sv = remoteUpdate
|
const sv = remoteUpdate
|
||||||
@@ -67,8 +72,8 @@ export const createLazyProvider = (
|
|||||||
function setupDocListener(doc: Doc) {
|
function setupDocListener(doc: Doc) {
|
||||||
const disposables = new Set<() => void>();
|
const disposables = new Set<() => void>();
|
||||||
disposableMap.set(doc.guid, disposables);
|
disposableMap.set(doc.guid, disposables);
|
||||||
const updateHandler = async (update: Uint8Array, origin: unknown) => {
|
const updateHandler = async (update: Uint8Array, updateOrigin: unknown) => {
|
||||||
if (origin === selfUpdateOrigin) {
|
if (origin === updateOrigin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
datasource.sendDocUpdate(doc.guid, update).catch(console.error);
|
datasource.sendDocUpdate(doc.guid, update).catch(console.error);
|
||||||
@@ -100,10 +105,12 @@ export const createLazyProvider = (
|
|||||||
datasourceUnsub = datasource.onDocUpdate?.((guid, update) => {
|
datasourceUnsub = datasource.onDocUpdate?.((guid, update) => {
|
||||||
const doc = getDoc(rootDoc, guid);
|
const doc = getDoc(rootDoc, guid);
|
||||||
if (doc) {
|
if (doc) {
|
||||||
applyUpdate(doc, update);
|
applyUpdate(doc, update, origin);
|
||||||
//
|
//
|
||||||
if (pendingMap.has(guid)) {
|
if (pendingMap.has(guid)) {
|
||||||
pendingMap.get(guid)?.forEach(update => applyUpdate(doc, update));
|
pendingMap
|
||||||
|
.get(guid)
|
||||||
|
?.forEach(update => applyUpdate(doc, update, origin));
|
||||||
pendingMap.delete(guid);
|
pendingMap.delete(guid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user