Skip to content

Commit

Permalink
Support array of preferred ports (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
nagen010 authored and sindresorhus committed Jul 24, 2018
1 parent e9a39e0 commit f5c9753
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 15 deletions.
34 changes: 22 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
'use strict';
const net = require('net');

const getPort = options => new Promise((resolve, reject) => {
// For backwards compatibility with number-only input
// TODO: Remove this in the next major version
if (typeof options === 'number') {
options = {
port: options
};
}

const isAvailable = options => new Promise((resolve, reject) => {
const server = net.createServer();

server.unref();
server.on('error', reject);

server.listen(options, () => {
const port = server.address().port;
const {port} = server.address();
server.close(() => {
resolve(port);
});
});
});

const getPort = options => new Promise((resolve, reject) => {
// For backwards compatibility with number-only input
// TODO: Remove this in the next major version
if (typeof options === 'number') {
options = {port: options};
}

if (typeof options.port === 'number') {
options.port = [options.port];
}

options.port.reduce((seq, port) => {
return seq.catch(() => {
return isAvailable(Object.assign({}, options, {port}))
.then(port => port)
.catch(Promise.reject.bind(Promise));
});
}, Promise.reject()).then(resolve).catch(reject);
});

module.exports = options => options ?
getPort(options).catch(() => getPort(0)) :
getPort(0);
14 changes: 11 additions & 3 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ getPort().then(port => {
});
```

Optionally, pass in a preferred port:
To pass in a preferred port:

```js
getPort({port: 3000}).then(port => {
Expand All @@ -30,6 +30,14 @@ getPort({port: 3000}).then(port => {
});
```

To pass in an array of preferred ports:

```js
getPort({port: [3000, 3001, 3002]}).then(port => {
console.log(port);
// Will use any element in the preferred ports array if available, otherwise fall back to a random port
});
```

## API

Expand All @@ -43,9 +51,9 @@ Type: `Object`

##### port

Type: `number`
Type: `number` `number[]`

The preferred port to use.
A preferred port or an array of preferred ports to use.

##### host

Expand Down
41 changes: 41 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,44 @@ test('preferred port given IPv4 host', async t => {

t.is(port, desiredPort);
});

test('preferred ports', async t => {
const desiredPorts = [9910, 9912, 9913];
const port = await m({
port: desiredPorts,
host: '0.0.0.0'
});

t.is(port, desiredPorts[0]);
});

test('first port in preferred ports array is unavailable', async t => {
const desiredPorts = [9090, 9091];

const server = net.createServer();
await pify(server.listen.bind(server))(desiredPorts[0]);

const port = await m({
port: desiredPorts
});

t.is(port, desiredPorts[1]);
});

test('all preferred ports in array are unavailable', async t => {
const desiredPorts = [9990, 9991];

const server1 = net.createServer();
await pify(server1.listen.bind(server1))(desiredPorts[0]);
const server2 = net.createServer();
await pify(server2.listen.bind(server2))(desiredPorts[1]);

const port = await m({
port: desiredPorts
});

t.is(typeof port, 'number');
t.true(port > 0 && port < 65536);
t.not(port, desiredPorts[0]);
t.not(port, desiredPorts[1]);
});

0 comments on commit f5c9753

Please sign in to comment.