From 6031c21d394ec3cbaccee4f7d5ad36e6020b275e Mon Sep 17 00:00:00 2001 From: Lucas Date: Mon, 1 Aug 2022 18:24:03 -0300 Subject: [PATCH] Add test case for bootstrapper (#50) * add test case for bootstrapper * fix port/host/opts args in bootstrapper * add more test cases for bootstrapper * feedback from mafintosh * added options.host for bind --- README.md | 3 +++ examples/bootstrap.mjs | 2 +- index.js | 3 +++ lib/io.js | 9 ++++--- test.js | 55 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d6fc269..3d25504 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,8 @@ Options include: nodes: [{ host, port }, ...], // Optionally pass a port you prefer to bind to instead of a random one port: 0, + // Optionally pass a host you prefer to bind to instead of all networks + host: '0.0.0.0', // Optionally pass a UDX instance on which sockets will be created. udx, // dht-rpc will automatically detect if you are firewalled. If you know that you are not set this to false @@ -132,6 +134,7 @@ Your DHT routing id is `hash(publicIp + publicPort)` and will be autoconfigured #### `const node = DHT.bootrapper(port, host, [options])` Make a bootstrap node for your DHT. The port and host needs to be it's globally accessable port and host. +Note: `port` and `host` parameters are used to create the node id. Use `options.host` if you want to bind to i.e. 127.0.0.1. DHT nodes can use any other DHT node to bootstrap, but a bootstrap node can bootstrap itself, by itself. #### `await node.ready()` diff --git a/examples/bootstrap.mjs b/examples/bootstrap.mjs index 231f0ff..75d3b9d 100644 --- a/examples/bootstrap.mjs +++ b/examples/bootstrap.mjs @@ -1,5 +1,5 @@ import DHT from '../index.js' -const bootstrap = new DHT({ ephemeral: false, firewalled: false, port: 10001 }) +const bootstrap = DHT.bootstrapper(10001, '127.0.0.1') await bootstrap.ready() console.log(bootstrap.address()) diff --git a/index.js b/index.js index 0f34198..431e982 100644 --- a/index.js +++ b/index.js @@ -45,6 +45,7 @@ class DHT extends EventEmitter { this._nat = new NatSampler() this._port = opts.port || 0 + this._host = opts.host || '0.0.0.0' this._quickFirewall = opts.quickFirewall !== false this._forcePersistent = opts.ephemeral === false this._repinging = 0 @@ -72,6 +73,8 @@ class DHT extends EventEmitter { } static bootstrapper (port, host, opts) { + if (!port) throw new Error('Port is required') + if (!host) throw new Error('Host is required') const id = peer.id(host, port) return new this({ port, id, ephemeral: false, firewalled: false, anyPort: false, bootstrap: [], ...opts }) } diff --git a/lib/io.js b/lib/io.js index be9fc3d..85750e8 100644 --- a/lib/io.js +++ b/lib/io.js @@ -12,7 +12,7 @@ const TMP = b4a.alloc(32) const EMPTY_ARRAY = [] module.exports = class IO { - constructor (table, udx, { maxWindow = 80, port = 0, anyPort = true, firewalled = true, onrequest, onresponse = noop, ontimeout = noop } = {}) { + constructor (table, udx, { maxWindow = 80, port = 0, host = '0.0.0.0', anyPort = true, firewalled = true, onrequest, onresponse = noop, ontimeout = noop } = {}) { this.table = table this.udx = udx this.inflight = [] @@ -35,6 +35,7 @@ module.exports = class IO { this._destroying = null this._binding = null this._port = port + this._host = host this._anyPort = anyPort !== false } @@ -135,7 +136,7 @@ module.exports = class IO { const serverSocket = this.udx.createSocket() try { - serverSocket.bind(this._port) + serverSocket.bind(this._port, this._host) } catch (err) { if (!this._anyPort) { await serverSocket.close() @@ -143,7 +144,7 @@ module.exports = class IO { } try { - serverSocket.bind() + serverSocket.bind(0, this._host) } catch (err) { await serverSocket.close() throw err @@ -153,7 +154,7 @@ module.exports = class IO { const clientSocket = this.udx.createSocket() try { - clientSocket.bind() + clientSocket.bind(0, this._host) } catch (err) { await serverSocket.close() await clientSocket.close() diff --git a/test.js b/test.js index 710500b..be2acc8 100644 --- a/test.js +++ b/test.js @@ -2,6 +2,61 @@ const test = require('brittle') const dgram = require('dgram') const DHT = require('./') +test('bootstrapper', async function (t) { + const node = DHT.bootstrapper(49737, '127.0.0.1') + + await node.ready() + t.is(node.address().host, '0.0.0.0') + t.is(node.address().family, 4) + t.is(node.address().port, 49737) + + await node.destroy() +}) + +test('bootstrapper - bind host', async function (t) { + const node = DHT.bootstrapper(49737, '127.0.0.1', { host: '127.0.0.1' }) + + await node.ready() + t.is(node.address().host, '127.0.0.1') + t.is(node.address().family, 4) + t.is(node.address().port, 49737) + + await node.destroy() +}) + +test('bootstrapper - opts', async function (t) { + const node = DHT.bootstrapper(49737, '127.0.0.1', { port: 49738 }) + + await node.ready() + t.is(node.address().host, '0.0.0.0') + t.is(node.address().family, 4) + t.is(node.address().port, 49738) + + await node.destroy() +}) + +test('bootstrapper - port and host are required', function (t) { + t.plan(3) + + try { + DHT.bootstrapper() + } catch (error) { + t.is(error.message, 'Port is required') + } + + try { + DHT.bootstrapper(0) + } catch (error) { + t.is(error.message, 'Port is required') + } + + try { + DHT.bootstrapper(49737) + } catch (error) { + t.is(error.message, 'Host is required') + } +}) + test('make tiny swarm', async function (t) { await makeSwarm(2, t) t.pass('could make swarm')