Skip to content

feat: only use server listen to detect port #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
test/fixtures
logs
run
coverage
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "eslint-config-egg"
}
4 changes: 0 additions & 4 deletions .jshintignore

This file was deleted.

33 changes: 0 additions & 33 deletions .jshintrc

This file was deleted.

16 changes: 10 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
sudo: false
language: node_js
node_js:
- "4"
- "5"
- "6"
sudo: false
script: make travis
after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"
- '4'
- '6'
- '7'
install:
- npm i npminstall && npminstall
script:
- npm run ci
after_script:
- npminstall codecov && codecov
28 changes: 0 additions & 28 deletions Makefile

This file was deleted.

13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
---

[![NPM version][npm-image]][npm-url]
[![node version][node-image]][node-url]
[![build status][travis-image]][travis-url]
[![Coveralls][coveralls-image]][coveralls-url]
[![Test coverage][codecov-image]][codecov-url]
[![npm download][download-image]][download-url]

[logo-image]: ./logo.png
Expand All @@ -14,22 +13,20 @@
[npm-url]: https://npmjs.org/package/detect-port
[travis-image]: https://img.shields.io/travis/node-modules/detect-port.svg?style=flat-square
[travis-url]: https://travis-ci.org/node-modules/detect-port
[coveralls-image]: https://img.shields.io/coveralls/node-modules/detect-port.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/node-modules/detect-port?branch=master
[node-image]: https://img.shields.io/badge/node.js-%3E=_4-red.svg?style=flat-square
[node-url]: http://nodejs.org/download/
[codecov-image]: https://codecov.io/gh/node-modules/detect-port/branch/master/graph/badge.svg
[codecov-url]: https://codecov.io/gh/node-modules/detect-port
[download-image]: https://img.shields.io/npm/dm/detect-port.svg?style=flat-square
[download-url]: https://npmjs.org/package/detect-port

> JavaScript Implementation of Port Detector

## Usage

```shell
```bash
$ npm i detect-port --save
```

```javascript
```js
const detect = require('detect-port');

/**
Expand Down
16 changes: 16 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
environment:
matrix:
- nodejs_version: '4'
- nodejs_version: '6'
- nodejs_version: '7'

install:
- ps: Install-Product node $env:nodejs_version
- npm i npminstall && node_modules\.bin\npminstall

test_script:
- node --version
- npm --version
- npm run ci

build: off
96 changes: 31 additions & 65 deletions lib/detect-port.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,39 @@
'use strict';

const debug = require('debug')('detect-port');
const net = require('net');

module.exports = function() {
const args = Array.prototype.slice.call(arguments);

const promise = new Promise((resolve, reject) => {
if (!args.length) {
return reject('wrong number of arguments');
}

const port = parseInt(args[0], 10);

if (isNaN(port)) {
return reject(`wrong type of arguments with: '${args[0]}'`);
}

const loop = port => {
const socket = new net.Socket();

socket.once('error', () => {
socket.removeAllListeners('error');
socket.removeAllListeners('connect');
socket.end();
socket.destroy();
socket.unref();

const server = new net.Server();

server.on('error', () => {
port++;
loop(port);
});

server.listen(port, () => {
server.once('close', () => {
resolve(port);
});
server.close();
});
});

socket.once('connect', () => {
port++;
loop(port);
socket.removeAllListeners('error');
socket.removeAllListeners('connect');
socket.end();
socket.destroy();
socket.unref();
});
module.exports = (port, callback) => {
if (typeof port === 'function') {
callback = port;
port = null;
}
if (typeof callback === 'function') {
return tryListen(port, callback);
}
// promise
return new Promise(resolve => {
tryListen(port, (_, realPort) => {
resolve(realPort);
});
});
};

socket.connect({
port: port
});
};
function tryListen(port, callback) {
port = parseInt(port) || 0;
const server = new net.Server();

loop(port);
server.on('error', err => {
debug('listen %s error: %s', port, err);
port = 0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

失败一次之后马上监听随机端口,确保操作系统分配成功。

server.close();
return tryListen(port, callback);
});

if (args.length > 1) {
const cb = args[1];

promise.then(data => {
process.nextTick(cb.bind(null, null, data));
}, err => {
process.nextTick(cb.bind(null, err));
});
} else {
return promise;
}
};
server.listen({ port }, () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 不支持这个解构

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

喔,看错,不是函数签名

port = server.address().port;
server.close();
debug('get free port: %s', port);
callback(null, port);
});
}
25 changes: 13 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,27 @@
"type": "git",
"url": "git://github.com/node-modules/detect-port.git"
},
"dependencies": {},
"dependencies": {
"debug": "^2.6.0"
},
"devDependencies": {
"co-mocha": "*",
"command-line-test": "^1.0.8",
"istanbul": "*",
"jshint": "*",
"mocha": "2.2.4",
"pre-commit": "^1.1.3",
"should": "~6.0.3"
"egg-bin": "^2.0.0",
"egg-ci": "^1.1.0",
"eslint": "^3.13.1",
"eslint-config-egg": "^3.1.0"
},
"scripts": {
"test": "make test",
"jshint": "make jshint"
"test": "egg-bin test",
"ci": "npm run lint && egg-bin cov",
"lint": "eslint ."
},
"precommit": [
"jshint"
],
"engines": {
"node": ">= 4.2.1"
},
"ci": {
"version": "4, 6, 7"
},
"homepage": "https://github.com/node-modules/detect-port",
"license": "MIT"
}
40 changes: 20 additions & 20 deletions test/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,43 @@

const path = require('path');
const CliTest = require('command-line-test');

const assert = require('assert');
const pkg = require('../package');

const cliTest = new CliTest();
const binFile = path.resolve(pkg.bin[pkg.name]);

describe('command-line tool test', () => {

it('should show version and exit', function *() {
var res = yield cliTest.execFile(binFile, ['-v'], {});
res.stdout.should.equal(pkg.version);
res = yield cliTest.execFile(binFile, ['--version'], {});
res.stdout.should.containEql(pkg.version);
it('should show version and exit', function* () {
let res = yield cliTest.execFile(binFile, [ '-v' ], {});
assert(res.stdout === pkg.version);
res = yield cliTest.execFile(binFile, [ '--version' ], {});
assert(res.stdout.includes(pkg.version));
});

it('should output usage information', function *() {
var res = yield cliTest.execFile(binFile, ['-h'], {});
res.stdout.should.containEql(pkg.description);
res = yield cliTest.execFile(binFile, ['--help'], {});
res.stdout.should.containEql(pkg.description);
res = yield cliTest.execFile(binFile, ['help'], {});
res.stdout.should.containEql(pkg.description);
res = yield cliTest.execFile(binFile, ['xxx'], {});
res.stdout.should.containEql(pkg.description);
it('should output usage information', function* () {
let res = yield cliTest.execFile(binFile, [ '-h' ], {});
assert(res.stdout.includes(pkg.description));
res = yield cliTest.execFile(binFile, [ '--help' ], {});
assert(res.stdout.includes(pkg.description));
res = yield cliTest.execFile(binFile, [ 'help' ], {});
assert(res.stdout.includes(pkg.description));
res = yield cliTest.execFile(binFile, [ 'xxx' ], {});
assert(res.stdout.includes(pkg.description));
});

it('should output available port randomly', function *() {
it('should output available port randomly', function* () {
const res = yield cliTest.execFile(binFile, [], {});
const port = parseInt(res.stdout.split(' ')[3], 10);
port.should.within(9000, 65535);
assert(port >= 9000 && port < 65535);
});

it('should output available port from the given port', function *() {
it('should output available port from the given port', function* () {
const givenPort = 9000;
const res = yield cliTest.execFile(binFile, [givenPort], {});
const res = yield cliTest.execFile(binFile, [ givenPort ], {});
const port = parseInt(res.stdout.split(' ')[3], 10);
port.should.within(givenPort, 65535);
assert(port >= givenPort && port < 65535);
});

});
Loading