in backend/sync.js [420:473]
function receiveSyncMessage(backend, oldSyncState, binaryMessage) {
if (!backend) {
throw new Error("generateSyncMessage called with no Automerge document")
}
if (!oldSyncState) {
throw new Error("generateSyncMessage requires a syncState, which can be created with initSyncState()")
}
let { sharedHeads, lastSentHeads, sentHashes } = oldSyncState, patch = null
const message = decodeSyncMessage(binaryMessage)
const beforeHeads = Backend.getHeads(backend)
// If we received changes, we try to apply them to the document. There may still be missing
// dependencies due to Bloom filter false positives, in which case the backend will enqueue the
// changes without applying them. The set of changes may also be incomplete if the sender decided
// to break a large set of changes into chunks.
if (message.changes.length > 0) {
[backend, patch] = Backend.applyChanges(backend, message.changes)
sharedHeads = advanceHeads(beforeHeads, Backend.getHeads(backend), sharedHeads)
}
// If heads are equal, indicate we don't need to send a response message
if (message.changes.length === 0 && compareArrays(message.heads, beforeHeads)) {
lastSentHeads = message.heads
}
// If all of the remote heads are known to us, that means either our heads are equal, or we are
// ahead of the remote peer. In this case, take the remote heads to be our shared heads.
const knownHeads = message.heads.filter(head => Backend.getChangeByHash(backend, head))
if (knownHeads.length === message.heads.length) {
sharedHeads = message.heads
// If the remote peer has lost all its data, reset our state to perform a full resync
if (message.heads.length === 0) {
lastSentHeads = []
sentHashes = []
}
} else {
// If some remote heads are unknown to us, we add all the remote heads we know to
// sharedHeads, but don't remove anything from sharedHeads. This might cause sharedHeads to
// contain some redundant hashes (where one hash is actually a transitive dependency of
// another), but this will be cleared up as soon as we know all the remote heads.
sharedHeads = [...new Set(knownHeads.concat(sharedHeads))].sort()
}
const syncState = {
sharedHeads, // what we have in common to generate an efficient bloom filter
lastSentHeads,
theirHave: message.have, // the information we need to calculate the changes they need
theirHeads: message.heads,
theirNeed: message.need,
sentHashes
}
return [backend, syncState, patch]
}