diff --git a/README.md b/README.md index beef5d407..a8a1db3f4 100644 --- a/README.md +++ b/README.md @@ -470,10 +470,14 @@ Emitted when the core has been appended to (i.e. has a new length / byteLength), Emitted when the core has been truncated, either locally or remotely. -#### `core.on('peer-add')` +#### `core.on('peer-add', peer)` Emitted when a new connection has been established with a peer. -#### `core.on('peer-remove')` +#### `core.on('peer-update', peer)` + +Emitted when a peer updates its properties like `peer.remoteContiguousLength`. + +#### `core.on('peer-remove', peer)` Emitted when a peer's connection has been closed. diff --git a/index.js b/index.js index 7ad78f650..db214f37c 100644 --- a/index.js +++ b/index.js @@ -391,6 +391,7 @@ module.exports = class Hypercore extends EventEmitter { eagerUpgrade: true, allowFork: opts.allowFork !== false, onpeerupdate: this._onpeerupdate.bind(this), + onpeerchange: this._onpeerchange.bind(this), onupload: this._onupload.bind(this) }) @@ -732,6 +733,12 @@ module.exports = class Hypercore extends EventEmitter { } } + _onpeerchange (peer) { + for (let i = 0; i < this.sessions.length; i++) { + this.sessions[i].emit('peer-update', peer) + } + } + async setUserData (key, value, { flush = false } = {}) { if (this.opened === false) await this.opening return this.core.userData(key, value, flush) diff --git a/lib/replicator.js b/lib/replicator.js index 6c97662bb..77a301183 100644 --- a/lib/replicator.js +++ b/lib/replicator.js @@ -719,6 +719,7 @@ class Peer { onbitfield ({ start, bitfield }) { if (this.remoteBitfield.insert(start, bitfield)) { this.skipList.setRange(start, bitfield.byteLength * 8, false) + this.replicator.onpeerchange(this) this._update() } } @@ -729,6 +730,7 @@ class Peer { if (length === 1) { this.remoteBitfield.setRange(start, length, has) this.skipList.set(start, false) + this.replicator.onpeerchange(this) } else { const rangeStart = this.remoteBitfield.findFirst(!has, start) const rangeLength = length - (rangeStart - start) @@ -736,6 +738,7 @@ class Peer { if (rangeLength > 0) { this.remoteBitfield.setRange(rangeStart, rangeLength, has) this.skipList.setRange(rangeStart, rangeLength, false) + this.replicator.onpeerchange(this) } } @@ -1081,13 +1084,14 @@ class Peer { } module.exports = class Replicator { - constructor (core, key, { eagerUpgrade = true, allowFork = true, onpeerupdate = noop, onupload = noop } = {}) { + constructor (core, key, { eagerUpgrade = true, allowFork = true, onpeerupdate = noop, onpeerchange = noop, onupload = noop } = {}) { this.key = key this.discoveryKey = core.crypto.discoveryKey(key) this.core = core this.eagerUpgrade = eagerUpgrade this.allowFork = allowFork this.onpeerupdate = onpeerupdate + this.onpeerchange = onpeerchange this.onupload = onupload this.ondownloading = null // optional external hook for monitoring downloading status this.peers = [] diff --git a/test/remote-length.js b/test/remote-length.js index 40ae24fce..8a09ae8db 100644 --- a/test/remote-length.js +++ b/test/remote-length.js @@ -63,6 +63,25 @@ test('peer truncates the remote contiguous length', async function (t) { t.is(getPeer(a, b).remoteContiguousLength, 1) }) +test('peer-update event is emitted when remote contiguous length changes', async function (t) { + t.plan(2) + + const a = await create() + const b = await create(a.key) + + replicate(a, b, t) + + await a.append('a') + + b.download() + + t.is(getPeer(a, b).remoteContiguousLength, 0) + + a.once('peer-update', function (peer) { + t.is(getPeer(a, b).remoteContiguousLength, 1) + }) +}) + // "A" wants to know if "B" is finished syncing, so find the corresponding peer function getPeer (a, b) { return a.replicator.peers.find(peer => b4a.equals(peer.remotePublicKey, b.replicator.peers[0].stream.publicKey))