find-free-ports
Advanced tools
Comparing version 1.0.0 to 1.1.0
60
index.js
@@ -10,35 +10,41 @@ "use strict"; | ||
}; | ||
const net_1 = require("net"); | ||
function findFreePorts(count = 1) { | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
const isFree_1 = __importDefault(require("./isFree")); | ||
const MIN_PORT = 1025; | ||
const MAX_PORT = 65535; | ||
const DEFAULT_PARALLEL = 10; | ||
function findFreePorts(count = 1, opts = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const servers = yield Promise.all((function () { | ||
const servers = []; | ||
for (let i = 0; i < count; ++i) { | ||
servers.push(new Promise((accept, reject) => { | ||
const server = net_1.createServer(); | ||
server.once('listening', () => accept(server)); | ||
server.once('error', reject); | ||
server.listen(); | ||
})); | ||
} | ||
return servers; | ||
})()); | ||
const startPort = opts.startPort !== undefined ? opts.startPort : MIN_PORT; | ||
const endPort = opts.endPort !== undefined ? opts.endPort : MAX_PORT; | ||
const parallel = Math.min(count, opts.maxParallell !== undefined ? opts.maxParallell : DEFAULT_PARALLEL); | ||
const ports = []; | ||
let port = startPort; | ||
return new Promise((accept, reject) => { | ||
function tryAccept() { | ||
for (const server of servers) | ||
if (!server.closed) | ||
return; | ||
accept(servers.map(s => s.port)); | ||
for (let i = 0; i < parallel; i++) { | ||
const next = () => { | ||
if (ports.length === count) { | ||
accept(ports); | ||
} | ||
else if (count - ports.length > parallel || ports.length % parallel < i) { | ||
test(port++).then(next).catch(reject); | ||
} | ||
}; | ||
test(port++).then(next).catch(reject); | ||
} | ||
for (const server of servers) { | ||
server.once('close', () => { | ||
server.closed = true; | ||
tryAccept(); | ||
}); | ||
server.port = server.address().port; | ||
server.close(); | ||
} | ||
}); | ||
function test(port) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (port > endPort) { | ||
throw new Error(`Could not find free ports: not enough free ports available.`); | ||
} | ||
if (yield isFree_1.default(port)) { | ||
ports.push(port); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
module.exports = findFreePorts; |
66
index.ts
import { Server, createServer } from "net" | ||
import isFree from "./isFree" | ||
type Assignable<T> = { [P in keyof T]: T[P] } & { [key: string]: any }; | ||
const MIN_PORT = 1025; | ||
const MAX_PORT = 65535; | ||
const DEFAULT_PARALLEL = 10; | ||
async function findFreePorts(count: number = 1) { | ||
interface FindFreePortsOptions { | ||
startPort?: number; | ||
endPort?: number; | ||
maxParallell?: number; | ||
} | ||
async function findFreePorts(count: number = 1, opts: FindFreePortsOptions = {}): Promise<number[]> { | ||
const servers = await Promise.all((function () { | ||
const startPort = opts.startPort !== undefined ? opts.startPort : MIN_PORT; | ||
const endPort = opts.endPort !== undefined ? opts.endPort : MAX_PORT; | ||
const servers = []; | ||
const parallel = Math.min(count, opts.maxParallell !== undefined ? opts.maxParallell : DEFAULT_PARALLEL); | ||
for (let i = 0; i < count; ++i) { | ||
servers.push(new Promise<Server>((accept, reject) => { | ||
const server = createServer(); | ||
server.once('listening', () => accept(server)); | ||
server.once('error', reject); | ||
server.listen(); | ||
})); | ||
const ports: number[] = []; | ||
let port = startPort; | ||
return new Promise((accept, reject) => { | ||
for (let i = 0; i < parallel; i++) { | ||
const next = () => { | ||
if (ports.length === count) { | ||
accept(ports); | ||
} else if (count - ports.length > parallel || ports.length % parallel < i) { | ||
test(port++).then(next).catch(reject); | ||
} | ||
} | ||
test(port++).then(next).catch(reject) | ||
} | ||
return servers; | ||
})()); | ||
}); | ||
return new Promise<number[]>((accept, reject) => { | ||
function tryAccept() { | ||
for (const server of servers) | ||
if (!server.closed) | ||
return; | ||
accept(servers.map(s => s.port)); | ||
async function test(port: number) { | ||
if (port > endPort) { | ||
throw new Error(`Could not find free ports: not enough free ports available.`); | ||
} | ||
for (const server of servers) { | ||
server.once('close', () => { | ||
server.closed = true; | ||
tryAccept(); | ||
}); | ||
server.port = server.address().port; | ||
server.close(); | ||
if (await isFree(port)) { | ||
ports.push(port); | ||
} | ||
} | ||
}); | ||
} | ||
@@ -47,0 +49,0 @@ |
"use strict"; | ||
const net_1 = require("net"); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
const net = __importStar(require("net")); | ||
function isFree(port) { | ||
return new Promise((accept, reject) => { | ||
const server = net_1.createServer(); | ||
server.once('error', (e) => { | ||
if (e.code === 'EADDRINUSE' || e.code === 'EACCES') { | ||
accept(false); | ||
const sock = net.createConnection(port); | ||
sock.once('connect', () => { sock.end(); }); | ||
sock.once('close', () => { accept(false); }); | ||
sock.once('error', (e) => { | ||
sock.destroy(); | ||
if (e.code === 'ECONNREFUSED') { | ||
accept(true); | ||
} | ||
@@ -14,9 +24,4 @@ else { | ||
}); | ||
server.once('listening', function () { | ||
server.once('close', () => { accept(true); }); | ||
server.close(); | ||
}); | ||
server.listen(port); | ||
}); | ||
} | ||
module.exports = isFree; |
import { createServer } from "net" | ||
import * as net from "net" | ||
function isFree(port: number) { | ||
return new Promise<boolean>((accept, reject) => { | ||
const server = createServer(); | ||
server.once('error', (e: NodeJS.ErrnoException) => { | ||
if (e.code === 'EADDRINUSE' || e.code === 'EACCES') { | ||
accept(false); | ||
function isFree(port: number): Promise<boolean> { | ||
return new Promise((accept, reject) => { | ||
const sock = net.createConnection(port); | ||
sock.once('connect', () => { sock.end() }); | ||
sock.once('close', () => { accept(false); }) | ||
sock.once('error', (e: NodeJS.ErrnoException) => { | ||
sock.destroy(); | ||
if (e.code === 'ECONNREFUSED') { | ||
accept(true) | ||
} else { | ||
@@ -14,7 +17,2 @@ reject(e); | ||
}); | ||
server.once('listening', function () { | ||
server.once('close', () => { accept(true); }); | ||
server.close(); | ||
}); | ||
server.listen(port); | ||
}); | ||
@@ -21,0 +19,0 @@ } |
{ | ||
"name": "find-free-ports", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"description": "Find multiple free ports on localhost", | ||
@@ -8,3 +8,3 @@ "main": "index.js", | ||
"prepare": "tsc", | ||
"test": "tsc && mocha" | ||
"test": "mocha --timeout 30000" | ||
}, | ||
@@ -27,9 +27,11 @@ "repository": { | ||
"homepage": "https://github.com/OrionGroup/node-find-free-ports#readme", | ||
"dependencies": { | ||
"@types/node": "^8.0.22" | ||
}, | ||
"devDependencies": { | ||
"@types/mocha": "^2.2.41", | ||
"chai": "^4.1.1" | ||
"@types/chai": "^4.2.0", | ||
"@types/chai-as-promised": "^7.1.2", | ||
"@types/mocha": "^5.2.7", | ||
"@types/node": "^12.7.3", | ||
"chai": "^4.2.0", | ||
"chai-as-promised": "^7.1.1", | ||
"mocha": "^6.2.0" | ||
} | ||
} |
This is a very simple package that allows developers to find free ports | ||
This is a very small package that allows developers to find free ports | ||
on the local system. Unlike most other "find-free-port" utilities, this library | ||
@@ -7,2 +7,10 @@ allows scanning for multiple free ports at once, making sure that there are no | ||
This library has been benchmarked and parallelises the port checks using a | ||
customisable number of workers for optimal performance. | ||
🔍 Found an issue? Please let me know in the [issue tracker][1] and we'll get | ||
it fixed ASAP. | ||
[1]: https://github.com/samvv/node-find-free-ports/issues | ||
``` | ||
@@ -23,4 +31,23 @@ npm i find-free-ports | ||
## Development | ||
We use [TypeScript](https://www.typescriptlang.org/) to check for human mistakes. | ||
``` | ||
tsc --watch | ||
``` | ||
You can run the tests with the following command: | ||
``` | ||
npm test | ||
``` | ||
⚠️ The tests may use a lot of resources so make sure your computer is up for the | ||
task. Also, due to race conditios with other applications that cannot be | ||
avoided, the tests may falsly fail or succeed in rare cases. Be sure to | ||
double-check any changes you make. | ||
## Similar Packages | ||
- [portfinder](https://www.npmjs.com/package/portfinder) | ||
@@ -27,0 +54,0 @@ - [get-port](https://www.npmjs.com/package/get-port) |
42
test.js
@@ -10,12 +10,42 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const chai_1 = require("chai"); | ||
const findFreePorts = require("./"); | ||
const isFree = require("./isFree"); | ||
const index_1 = __importDefault(require("./index")); | ||
const isFree_1 = __importDefault(require("./isFree")); | ||
const chai = __importStar(require("chai")); | ||
const chai_as_promised_1 = __importDefault(require("chai-as-promised")); | ||
chai.use(chai_as_promised_1.default); | ||
const { expect, assert } = chai; | ||
const PORT_COUNT = 28; | ||
describe('a free port finder', () => { | ||
it('crashes properly when there are not enough free ports', () => __awaiter(this, void 0, void 0, function* () { | ||
expect(index_1.default(10, { startPort: 65530 })).to.eventually.be.rejectedWith(Error); | ||
})); | ||
it('can find some free ports', () => __awaiter(this, void 0, void 0, function* () { | ||
const ports = yield findFreePorts(2); | ||
for (const port of ports) | ||
chai_1.expect(yield isFree(port)).to.be.true; | ||
for (let i = 0; i < 10; i++) { | ||
const ports = yield index_1.default(PORT_COUNT); | ||
expect(ports).to.have.lengthOf(PORT_COUNT); | ||
const set = new Set(); | ||
for (const port of ports) { | ||
if (set.has(port)) { | ||
assert.fail('Duplicate port found in result set.'); | ||
} | ||
else { | ||
set.add(port); | ||
} | ||
} | ||
for (const port of ports) { | ||
expect(isFree_1.default(port)).to.eventually.be.true; | ||
} | ||
} | ||
})); | ||
}); |
45
test.ts
import { expect } from "chai" | ||
import findFreePorts from './index'; | ||
import isFree from "./isFree" | ||
import * as chai from "chai" | ||
import chaiAsPromised from "chai-as-promised" | ||
import findFreePorts = require('./'); | ||
import isFree = require('./isFree'); | ||
chai.use(chaiAsPromised); | ||
const { expect, assert } = chai; | ||
const PORT_COUNT = 28; | ||
describe('a free port finder', () => { | ||
it('crashes properly when there are not enough free ports', async () => { | ||
expect(findFreePorts(10, { startPort: 65530 })).to.eventually.be.rejectedWith(Error); | ||
}) | ||
it('can find some free ports', async () => { | ||
const ports = await findFreePorts(2); | ||
for (const port of ports) | ||
expect(await isFree(port)).to.be.true | ||
for (let i = 0; i < 10; i++) { | ||
const ports = await findFreePorts(PORT_COUNT); | ||
expect(ports).to.have.lengthOf(PORT_COUNT); | ||
const set = new Set(); | ||
for (const port of ports) { | ||
if (set.has(port)) { | ||
assert.fail('Duplicate port found in result set.') | ||
} else { | ||
set.add(port); | ||
} | ||
} | ||
for (const port of ports) { | ||
expect(isFree(port)).to.eventually.be.true; | ||
} | ||
} | ||
}); | ||
@@ -17,1 +46,3 @@ | ||
{ | ||
"compilerOptions": { | ||
"module": "commonjs", | ||
"target": "es6" | ||
"target": "es6", | ||
"esModuleInterop": true | ||
} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
11692
0
215
0
59
7
10
- Removed@types/node@^8.0.22
- Removed@types/node@8.10.66(transitive)