115 lines
3.3 KiB
JavaScript
115 lines
3.3 KiB
JavaScript
/**
|
|
* @module utils
|
|
*/
|
|
|
|
import { getStruct } from '../utils/structReferences.js'
|
|
import * as decoding from 'lib0/decoding.js'
|
|
import { GC } from '../structs/GC.js'
|
|
import { Y } from '../utils/Y.js' // eslint-disable-line
|
|
import { Item } from '../structs/Item.js' // eslint-disable-line
|
|
|
|
class MissingEntry {
|
|
constructor (decoder, missing, struct) {
|
|
this.decoder = decoder
|
|
this.missing = missing.length
|
|
this.struct = struct
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @private
|
|
* Integrate remote struct
|
|
* When a remote struct is integrated, other structs might be ready to ready to
|
|
* integrate.
|
|
* @param {Y} y
|
|
* @param {Item} struct
|
|
*/
|
|
function _integrateRemoteStructHelper (y, struct) {
|
|
const id = struct._id
|
|
if (id === undefined) {
|
|
struct._integrate(y)
|
|
} else {
|
|
if (y.ss.getState(id.user) > id.clock) {
|
|
return
|
|
}
|
|
if (!y.gcEnabled || struct.constructor === GC || (struct._parent.constructor !== GC && struct._parent._deleted === false)) {
|
|
// Is either a GC or Item with an undeleted parent
|
|
// save to integrate
|
|
struct._integrate(y)
|
|
} else {
|
|
// Is an Item. parent was deleted.
|
|
struct._gc(y)
|
|
}
|
|
let msu = y._missingStructs.get(id.user)
|
|
if (msu != null) {
|
|
let clock = id.clock
|
|
const finalClock = clock + struct._length
|
|
for (;clock < finalClock; clock++) {
|
|
const missingStructs = msu.get(clock)
|
|
if (missingStructs !== undefined) {
|
|
missingStructs.forEach(missingDef => {
|
|
missingDef.missing--
|
|
if (missingDef.missing === 0) {
|
|
y._readyToIntegrate.push(missingDef)
|
|
}
|
|
})
|
|
msu.delete(clock)
|
|
}
|
|
}
|
|
if (msu.size === 0) {
|
|
y._missingStructs.delete(id.user)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {decoding.Decoder} decoder
|
|
* @param {Y} y
|
|
*/
|
|
export const integrateRemoteStructs = (decoder, y) => {
|
|
const len = decoding.readUint32(decoder)
|
|
for (let i = 0; i < len; i++) {
|
|
let reference = decoding.readVarUint(decoder)
|
|
let Constr = getStruct(reference)
|
|
let struct = new Constr()
|
|
let decoderPos = decoder.pos
|
|
let missing = struct._fromBinary(y, decoder)
|
|
if (missing.length === 0) {
|
|
while (struct !== null) {
|
|
_integrateRemoteStructHelper(y, struct)
|
|
struct = null
|
|
if (y._readyToIntegrate.length > 0) {
|
|
const missingDef = y._readyToIntegrate.shift()
|
|
const decoder = missingDef.decoder
|
|
let oldPos = decoder.pos
|
|
let missing = missingDef.struct._fromBinary(y, decoder)
|
|
decoder.pos = oldPos
|
|
if (missing.length === 0) {
|
|
struct = missingDef.struct
|
|
} else {
|
|
throw new Error('Missing should be empty')
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
let _decoder = decoding.createDecoder(decoder.arr.buffer)
|
|
_decoder.pos = decoderPos
|
|
let missingEntry = new MissingEntry(_decoder, missing, struct)
|
|
let missingStructs = y._missingStructs
|
|
for (let i = missing.length - 1; i >= 0; i--) {
|
|
let m = missing[i]
|
|
if (!missingStructs.has(m.user)) {
|
|
missingStructs.set(m.user, new Map())
|
|
}
|
|
let msu = missingStructs.get(m.user)
|
|
if (!msu.has(m.clock)) {
|
|
msu.set(m.clock, [])
|
|
}
|
|
let mArray = msu = msu.get(m.clock)
|
|
mArray.push(missingEntry)
|
|
}
|
|
}
|
|
}
|
|
}
|