From 5d45d639fbcf7d734f3b0b02134594265746df61 Mon Sep 17 00:00:00 2001 From: Mathias Buus Date: Wed, 16 Jun 2021 10:56:11 +0200 Subject: [PATCH] emit listening and always bind in ready for ease of use --- README.md | 4 ++++ index.js | 31 +++++++++++++++++++++++++++++++ test.js | 17 +++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/README.md b/README.md index 65791dd..e7b43bc 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,10 @@ A boolean indicating if you are currently epheremal or not Emitted when the routing table is fully bootstrapped. Emitted as a conveinience. +#### `node.on('listening')` + +Emitted when the underlying UDP socket is listening. Emitted as a conveinience. + #### `node.on('persistent')` Emitted when the node is no longer in ephemeral mode. diff --git a/index.js b/index.js index a5cd694..fa6d882 100644 --- a/index.js +++ b/index.js @@ -93,6 +93,7 @@ class DHT extends EventEmitter { this._nat = new NatAnalyzer(opts.natSampleSize || 16) this._onrow = (row) => row.on('full', (node) => this._onfullrow(node, row)) this._rotateSecrets = false + this._bound = false this._secrets = [ Buffer.alloc(32), Buffer.alloc(32) @@ -105,6 +106,11 @@ class DHT extends EventEmitter { this.table.on('row', this._onrow) + this.rpc.socket.on('listening', () => { + this._bound = true + this.emit('listening') + }) + if (opts.nodes) { for (const node of opts.nodes) this.addNode(node) } @@ -192,6 +198,10 @@ class DHT extends EventEmitter { this._resolveSampled = null } + if (!this._bound) { + await bind(this.rpc.socket, 0) + } + this.emit('ready') } @@ -666,3 +676,24 @@ function compare (id, a, b) { function randomOffset (n) { return n - ((Math.random() * 0.5 * n) | 0) } + +function bind (socket, port) { + return new Promise((resolve, reject) => { + socket.bind(port) + + socket.on('error', onerror) + socket.on('listening', ondone) + + function onerror (err) { + socket.removeListener('error', onerror) + socket.removeListener('listening', ondone) + reject(err) + } + + function ondone () { + socket.removeListener('error', onerror) + socket.removeListener('listening', ondone) + resolve() + } + }) +} diff --git a/test.js b/test.js index 73904b7..8232645 100644 --- a/test.js +++ b/test.js @@ -163,6 +163,23 @@ tape('shorthand commit', async function (t) { destroy(swarm) }) +tape('after ready it is always bound', async function (t) { + t.plan(2) + + const node = new DHT() + + node.on('listening', function () { + t.pass('is listening') + }) + + await node.ready() + const addr = node.address() + + t.ok(typeof addr.port, 'is number') + + node.destroy() +}) + tape('timeouts when commiting', async function (t) { const [bootstrap, a, b] = await makeSwarm(3) let tries = 0