change client id when duplicate content is detected

This commit is contained in:
Kevin Jahns 2020-05-03 16:10:58 +02:00
parent b399ffa765
commit 9f5bc9ddfe
5 changed files with 31 additions and 2 deletions

View File

@ -47,6 +47,7 @@ export {
typeMapGetSnapshot, typeMapGetSnapshot,
iterateDeletedStructs, iterateDeletedStructs,
applyUpdate, applyUpdate,
readUpdate,
encodeStateAsUpdate, encodeStateAsUpdate,
encodeStateVector, encodeStateVector,
UndoManager, UndoManager,

View File

@ -17,6 +17,8 @@ import { Observable } from 'lib0/observable.js'
import * as random from 'lib0/random.js' import * as random from 'lib0/random.js'
import * as map from 'lib0/map.js' import * as map from 'lib0/map.js'
export const generateNewClientId = random.uint32
/** /**
* A Yjs instance handles the state of shared data. * A Yjs instance handles the state of shared data.
* @extends Observable<string> * @extends Observable<string>
@ -31,7 +33,7 @@ export class Doc extends Observable {
super() super()
this.gc = gc this.gc = gc
this.gcFilter = gcFilter this.gcFilter = gcFilter
this.clientID = random.uint32() this.clientID = generateNewClientId()
/** /**
* @type {Map<string, AbstractType<YEvent>>} * @type {Map<string, AbstractType<YEvent>>}
*/ */

View File

@ -10,6 +10,7 @@ import {
findIndexSS, findIndexSS,
callEventHandlerListeners, callEventHandlerListeners,
Item, Item,
generateNewClientId,
StructStore, ID, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line StructStore, ID, AbstractType, AbstractStruct, YEvent, Doc // eslint-disable-line
} from '../internals.js' } from '../internals.js'
@ -17,6 +18,7 @@ import * as encoding from 'lib0/encoding.js'
import * as map from 'lib0/map.js' import * as map from 'lib0/map.js'
import * as math from 'lib0/math.js' import * as math from 'lib0/math.js'
import * as set from 'lib0/set.js' import * as set from 'lib0/set.js'
import * as logging from 'lib0/logging.js'
import { callAll } from 'lib0/function.js' import { callAll } from 'lib0/function.js'
/** /**
@ -313,6 +315,10 @@ const cleanupTransactions = (transactionCleanups, i) => {
tryToMergeWithLeft(structs, replacedStructPos) tryToMergeWithLeft(structs, replacedStructPos)
} }
} }
if (!transaction.local && transaction.afterState.get(doc.clientID) !== transaction.beforeState.get(doc.clientID)) {
doc.clientID = generateNewClientId()
logging.print(logging.ORANGE, logging.BOLD, '[yjs] ', logging.UNBOLD, logging.RED, 'Changed the client-id because another client seems to be using it.')
}
// @todo Merge all the transactions into one and provide send the data as a single update message // @todo Merge all the transactions into one and provide send the data as a single update message
doc.emit('afterTransactionCleanup', [transaction, doc]) doc.emit('afterTransactionCleanup', [transaction, doc])
if (doc._observers.has('update')) { if (doc._observers.has('update')) {

View File

@ -0,0 +1,19 @@
import * as Y from '../src/index.js'
import * as t from 'lib0/testing.js'
/**
* Client id should be changed when an instance receives updates from another client using the same client id.
*
* @param {t.TestCase} tc
*/
export const testClientIdDuplicateChange = tc => {
const doc1 = new Y.Doc()
doc1.clientID = 0
const doc2 = new Y.Doc()
doc2.clientID = 0
t.assert(doc2.clientID === doc1.clientID)
doc1.getArray('a').insert(0, [1, 2])
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc1))
t.assert(doc2.clientID !== doc1.clientID)
}

View File

@ -5,6 +5,7 @@ import * as text from './y-text.tests.js'
import * as xml from './y-xml.tests.js' import * as xml from './y-xml.tests.js'
import * as encoding from './encoding.tests.js' import * as encoding from './encoding.tests.js'
import * as undoredo from './undo-redo.tests.js' import * as undoredo from './undo-redo.tests.js'
import * as consistency from './consistency.tests.js'
import { runTests } from 'lib0/testing.js' import { runTests } from 'lib0/testing.js'
import { isBrowser, isNode } from 'lib0/environment.js' import { isBrowser, isNode } from 'lib0/environment.js'
@ -14,7 +15,7 @@ if (isBrowser) {
log.createVConsole(document.body) log.createVConsole(document.body)
} }
runTests({ runTests({
map, array, text, xml, encoding, undoredo map, array, text, xml, consistency, encoding, undoredo
}).then(success => { }).then(success => {
/* istanbul ignore next */ /* istanbul ignore next */
if (isNode) { if (isNode) {