diff --git a/README.md b/README.md index f39f1063..54943342 100644 --- a/README.md +++ b/README.md @@ -763,6 +763,10 @@ Emitted when a new connection has been established with a peer. Emitted when a peer's connection has been closed. +#### `core.on('peer-synchronize', peer)` + +Emitted when a synchronize message from a peer has been processed, meaning the peer's remote state (`peer.remoteLength`, `peer.remoteFork`, etc) has been updated. The first emission for a peer means its handshake has completed: `peer-add` fires before the peer has sent anything, so this is the earliest point at which the peer's remote state can be read. + #### `core.on('upload', index, byteLength, peer)` Emitted when a block is uploaded to a peer. diff --git a/lib/replicator.js b/lib/replicator.js index bf1eb9e7..65e792d3 100644 --- a/lib/replicator.js +++ b/lib/replicator.js @@ -807,6 +807,8 @@ class Peer { this.remoteHasManifest = hasManifest this.remoteAllowPush = allowPush + this.replicator._onpeersynchronize(this) + if (this.closeIfIdle()) return this.lengthAcked = sameFork ? remoteLength : 0 @@ -3217,6 +3219,14 @@ module.exports = class Replicator { } } + _onpeersynchronize(peer) { + const sessions = this.core.monitors + + for (let i = sessions.length - 1; i >= 0; i--) { + sessions[i].emit('peer-synchronize', peer) + } + } + _ondownload(index, byteLength, from, req) { const sessions = this.core.monitors diff --git a/test/replicate.js b/test/replicate.js index da5b4572..9c125455 100644 --- a/test/replicate.js +++ b/test/replicate.js @@ -2937,6 +2937,25 @@ test('delayed updateAll timer doesnt keep event loop alive', async function (t) t.is(r._updateAllBump, null, 'timer reset to null') }) +test('peer-synchronize is emitted when a synchronize message is processed', async function (t) { + const a = await create(t) + await a.append(['a', 'b', 'c']) + + const b = await create(t, a.key) + + const aSynchronized = new Promise((resolve) => a.once('peer-synchronize', resolve)) + const bSynchronized = new Promise((resolve) => b.once('peer-synchronize', resolve)) + + replicate(a, b, t) + + const peerOnA = await aSynchronized + t.is(peerOnA.remoteSynced, true, 'peer remote state is set when emitted') + + const peerOnB = await bSynchronized + t.is(peerOnB.remoteSynced, true, 'peer remote state is set when emitted') + t.is(peerOnB.remoteLength, 3, 'peer remote length is known when emitted') +}) + async function createAndDownload(t, core) { const b = await create(t, core.key) replicate(core, b, t, { teardown: false })