From 68456851e5d42b5ac86c30f2a40bc30bab80befd Mon Sep 17 00:00:00 2001 From: xudafeng Date: Mon, 24 Oct 2016 20:46:50 +0800 Subject: [PATCH 1/2] tweak async interface --- .travis.yml | 6 ++- README.md | 93 ++++++++++++++------------------ bin/detect-port | 112 +++++++++++++-------------------------- lib/index.js | 80 +++++++++++++++------------- package.json | 17 +++--- test/cli.test.js | 57 ++++++++++++++++++++ test/detect-port.test.js | 78 ++++++++++++++++----------- 7 files changed, 233 insertions(+), 210 deletions(-) create mode 100644 test/cli.test.js diff --git a/.travis.yml b/.travis.yml index 20b521e..a614bf7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: node_js -sudo: false node_js: - - "4.1.2" + - "4" + - "5" + - "6" +sudo: false script: make travis after_script: "npm install coveralls@2 && cat ./coverage/lcov.info | coveralls" diff --git a/README.md b/README.md index effddcf..f272a70 100644 --- a/README.md +++ b/README.md @@ -17,57 +17,34 @@ [download-image]: https://img.shields.io/npm/dm/detect-port.svg?style=flat-square [download-url]: https://npmjs.org/package/detect-port -> port detector +> JavaScript Implementation of Port Detector -## Installment - -```shell -$ npm i detect-port -g -``` - -## Quick Start - -```shell -# detect port 80 -$ detect -p 80 - -# or like this -$ detect --port 80 - -# will get result below -$ port: 80 was occupied, try port: 1024 - -# with verbose -$ detect --port 80 --verbose - -# more help? -$ detect -h -``` - -## Use As Module +## Usage ```shell $ npm i detect-port --save ``` ```javascript -var detect = require('detect-port'); +const detect = require('detect-port'); /** - * normal usage + * callback usage */ -detect(port, function(error, _port) { +detect(port, (err, _port) => { + if (err) { + console.log(err); + } if (port === _port) { - console.log('port: %d was not occupied', port); + console.log(`port: ${port} was not occupied`); } else { - console.log('port: %d was occupied, try port: %d', port, _port); + console.log(`port: ${port} was occupied, try port: ${_port}`); } }); /** - * use in co v3 * for a yield syntax instead of callback function implement */ @@ -77,9 +54,9 @@ co(function *() { var _port = yield detect(port); if (port === _port) { - console.log('port: %d was not occupied', port); + console.log(`port: ${port} was not occupied`); } else { - console.log('port: %d was occupied, try port: %d', port, _port); + console.log(`port: ${port} was occupied, try port: ${_port}`); } })(); @@ -87,36 +64,44 @@ co(function *() { * use as a promise */ -var promisePort = detect(port); - -promisePort.then(function(_port) { - if (port === _port) { - console.log('port: %d was not occupied', port); - } else { - console.log('port: %d was occupied, try port: %d', port, _port); - } -}); +detect(port) + .then(_port => { + if (port === _port) { + console.log(`port: ${port} was not occupied`); + } else { + console.log(`port: ${port} was occupied, try port: ${_port}`); + } + }) + .catch(err => { + console.log(err); + }); ``` -## Clone and Run test +## Cli Tool ```shell +$ npm i detect-port -g +``` -# clone from git -$ git clone git://github.com/xudafeng/detect-port.git +### Quick Start -$ cd detect-port +```shell +# get an available port randomly +$ detect -# install dependencies -$ make install +# detect pointed port +$ detect 80 -# test and coverage -$ make test +# more help +$ detect --help ``` +## Authors + +- [xudafeng](//github.com/xudafeng) +- [zenzhu](//github.com/zenzhu) + ## License [MIT](LICENSE) - -Copyright (c) 2015 xdf diff --git a/bin/detect-port b/bin/detect-port index c1b18f7..a4ad11a 100755 --- a/bin/detect-port +++ b/bin/detect-port @@ -14,87 +14,51 @@ 'use strict'; -var fs = require('fs'); -var path = require('path'); -var program = require('commander'); -var pkg = require('../package'); +const pkg = require('../package'); -var options = { - port: 8080, - verbose: false -}; +const args = process.argv.slice(2); +const arg_0 = args[0]; -program - .usage('[options] [arguments]') - .option('-v, --versions', 'show version and exit') - .option('-p, --port ', 'set port for detect (default: 8080)') - .option('--verbose', 'show more debugging information') - .helpInformation = function() { - return [ - '', - ' \u001b[37m' + pkg.description + '\u001b[0m', - '', - ' Usage:', - ' ' + this._name + ' or detect-port ' + this.usage(), - '', - ' Options:', - '' + this.optionHelp().replace(/^/gm, ' '), - '', - ' Further help:', - '', - ' \u001b[4m' + pkg.homepage + '\u001b[0m', - '', - '' - ].join('\n'); - }; - -program.parse(process.argv); - -if (program.versions) { - console.log('%s version: %s', pkg.name, pkg.version); +if (!!~['-v', '--version'].indexOf(arg_0)) { + console.log(pkg.version); process.exit(0); } -var camelcase = function(str) { - return str.split('-').reduce(function(str, word){ - return str + word[0].toUpperCase() + word.slice(1); - }); -}; - -var getConfig = function(program) { - var cfg = {}; +const port = parseInt(arg_0, 10); - program.options.forEach(function(item) { - var key = camelcase(item.name()); +const main = require('..'); - if(key in program) { +if (!arg_0) { + const random = Math.floor(9000 + Math.random() * (65535 - 9000)); - if (typeof program[key] !== 'function') { - cfg[key] = program[key]; - } + main(random, (err, port) => { + if (err) { + console.log(`get available port failed with ${err}`); } + console.log(`get available port ${port} randomly`); }); - return cfg; -}; - -var merge = function(r, s) { - for (var i in s) { - r[i] = s[i]; - } -}; - -merge(options, getConfig(program)); - -global.__detect = global.__detect || {}; -global.__detect.options = options; - -var detect = require('../lib'); -var port = options.port; - -detect(port, function(error, _port) { - if (port === _port) { - console.log('port: %d was not occupied', port); - } else { - console.log('port: %d was occupied, try port: %d', port, _port); - } -}); +} else if (isNaN(port)) { + console.log(); + console.log(` \u001b[37m${pkg.description}\u001b[0m`); + console.log(); + console.log(' Usage:'); + console.log(); + console.log(` ${pkg.name} [port]`); + console.log(); + console.log(' Options:'); + console.log(); + console.log(' -v, --version show version and exit'); + console.log(' -h, --help output usage information'); + console.log(); + console.log(' Further help:'); + console.log(); + console.log(` ${pkg.homepage}`); + console.log(); +} else { + main(port, (err, port) => { + if (err) { + console.log(`get available port failed with ${err}`); + } + console.log(`get available port ${port}`); + }); +} diff --git a/lib/index.js b/lib/index.js index 776c510..3859484 100644 --- a/lib/index.js +++ b/lib/index.js @@ -13,68 +13,74 @@ 'use strict'; -var net = require('net'); +const net = require('net'); -var inject = function(port) { - var options = global.__detect ? global.__detect.options : {}; +module.exports = function() { + const args = Array.prototype.slice.call(arguments); - if (options.verbose) { - console.log('port %d was occupied', port); - } -}; + const promise = new Promise((resolve, reject) => { + if (!args.length) { + reject('wrong number of arguments'); + } -function detect(port, fn) { + const port = args[0]; - var _detect = function(port) { - return new Promise(function(resolve, reject) { - var socket = new net.Socket(); - socket.once('error', function() { - socket.removeAllListeners('connect'); + if (typeof port !== 'number') { + reject(`wrong type of arguments with: ${port}`); + } + + const loop = port => { + const socket = new net.Socket(); + + socket.once('error', () => { socket.removeAllListeners('error'); + socket.removeAllListeners('connect'); socket.end(); socket.destroy(); socket.unref(); - var server = new net.Server(); - server.on('error', function() { - inject(port); + + const server = new net.Server(); + + server.on('error', () => { port++; - resolve(_detect(port)); + loop(port); }); - server.listen(port, function() { - server.once('close', function() { + server.listen(port, () => { + server.once('close', () => { resolve(port); }); server.close(); }); }); - socket.once('connect', function() { - inject(port); + + socket.once('connect', () => { port++; - resolve(_detect(port)); - socket.removeAllListeners('connect'); + loop(port); socket.removeAllListeners('error'); + socket.removeAllListeners('connect'); socket.end(); socket.destroy(); socket.unref(); }); + socket.connect({ port: port }); - }); - } + }; - var _detect_with_cb = function(_fn) { - _detect(port) - .then(function(result) { - _fn(null, result); - }) - .catch(function(e) { - _fn(e); - }); - }; + loop(port); + }); - return fn ? _detect_with_cb(fn) : _detect(port); -} + if (args.length > 1) { + const cb = args[1]; -module.exports = detect; + promise.then(data => { + cb.call(this, null, data); + }).catch(err => { + cb.call(this, err); + }); + } else { + return promise; + } +}; diff --git a/package.json b/package.json index a5ed516..1b75469 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,10 @@ { "name": "detect-port", - "version": "1.0.1", - "description": "port detector", + "version": "1.0.2", + "description": "detect available port", "keywords": [ "detect", - "port", - "detect-port" + "port" ], "bin": { "detect": "./bin/detect-port", @@ -16,15 +15,14 @@ "type": "git", "url": "git://github.com/xudafeng/detect-port.git" }, - "dependencies": { - "commander": "~2.8.1" - }, + "dependencies": {}, "devDependencies": { "co-mocha": "*", - "command-line-test": "^1.0.3", + "command-line-test": "^1.0.8", "istanbul": "*", "jshint": "*", "mocha": "2.2.4", + "pre-commit": "^1.1.3", "should": "~6.0.3" }, "scripts": { @@ -37,9 +35,6 @@ "engines": { "node": ">= 4.2.1" }, - "author": "xudafeng", "homepage": "https://github.com/xudafeng/detect-port", - "email": "xudafeng@126.com", - "blog": "http://xdf.me", "license": "MIT" } diff --git a/test/cli.test.js b/test/cli.test.js new file mode 100644 index 0000000..4fdc4a4 --- /dev/null +++ b/test/cli.test.js @@ -0,0 +1,57 @@ +/* ================================================================ + * detect-port by xdf(xudafeng[at]126.com) + * + * first created at : Tue Mar 17 2015 00:16:10 GMT+0800 (CST) + * + * ================================================================ + * Copyright xdf + * + * Licensed under the MIT License + * You may not use this file except in compliance with the License. + * + * ================================================================ */ + +'use strict'; + +const path = require('path'); +const CliTest = require('command-line-test'); + +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 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 available port randomly', function *() { + const res = yield cliTest.execFile(binFile, [], {}); + const port = parseInt(res.stdout.split(' ')[3], 10); + port.should.within(9000, 65535); + }); + + it('should output available port from the given port', function *() { + const givenPort = 8080; + var res = yield cliTest.execFile(binFile, [givenPort], {}); + const port = parseInt(res.stdout.split(' ')[3], 10); + port.should.within(givenPort, 65535); + }); + +}); diff --git a/test/detect-port.test.js b/test/detect-port.test.js index 1f7fe9f..8ea25a4 100644 --- a/test/detect-port.test.js +++ b/test/detect-port.test.js @@ -13,47 +13,61 @@ 'use strict'; -var path = require('path'); -var detect = require('..'); -var CliTest = require('command-line-test'); +const detectPort = require('..'); -var pkg = require('../package'); +describe('detect port test', () => { -describe('lib/index.js', function() { - describe('detect()', function() { - - it('should be a function', function() { - detect.should.be.a.Function; + it('callback with occupied port', done => { + var _port = 80; + detectPort(_port, (err, port) => { + if (err) { + console.log(err); + } + port.should.within(_port, 65535); + done(); }); + }); - it('should return correct port number', function *() { - var port = yield detect(8080); - port.should.be.a.Number; + it('callback with wrong arguments', done => { + detectPort('8080', err => { + if (err) { + err.should.containEql('wrong type of arguments'); + } + done(); }); + }); - it('should with verbose', function *() { - global.__detect = global.__detect || { - options: { - verbose: true - } - }; - var port = yield detect(8080); - port.should.be.a.Number; - }); + it('generator usage', function *() { + var _port = 8080; + try { + var port = yield detectPort(8080); + port.should.within(_port, 65535); + } catch (err) { + console.log(err); + } + }); - it('should get correct port number in callback', function() { - detect(8080, function(error, port) { - port.should.be.a.Number; + it('promise usage', function *() { + detectPort(8080) + .then(port => { + console.log(port); + }) + .catch(err => { + console.log(err); }); - }); }); - describe('command-line tool', function() { - it('command-line tool should be ok', function *() { - var cliTest = new CliTest(); - var binFile = path.resolve(pkg.bin['detect-port']); - var res = yield cliTest.execFile(binFile, [], {}); - res.stdout.should.containEql('port'); - }); + it('generator with wrong arguments', function *() { + try { + yield detectPort(); + } catch (err) { + err.should.containEql('wrong number of arguments'); + } + + try { + yield detectPort('8080'); + } catch (err) { + err.should.containEql('wrong type of arguments'); + } }); }); From 0578e6f2dbb9ffb7278f733ae5a22c18926d4df7 Mon Sep 17 00:00:00 2001 From: xudafeng Date: Sat, 29 Oct 2016 22:50:46 +0800 Subject: [PATCH 2/2] tweak testcase --- Makefile | 18 +++++++++++------- test/detect-port.test.js | 29 +++++++++++++++++++---------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index f66cdd7..da2dd7a 100644 --- a/Makefile +++ b/Makefile @@ -4,20 +4,24 @@ npm_bin= $$(npm bin) all: test install: @npm install +server: + npm i startserver --save-dev + ${npm_bin}/startserver -s -p 8080 & +pre-test: server + sleep 5 test: - @node --harmony \ + @node \ ${npm_bin}/istanbul cover ${npm_bin}/_mocha \ -- \ --timeout 10000 \ --require co-mocha -travis: install - @NODE_ENV=test $(BIN) $(FLAGS) \ - ./node_modules/.bin/istanbul cover \ - ./node_modules/.bin/_mocha \ +travis: install pre-test + @node \ + ${npm_bin}/istanbul cover ${npm_bin}/_mocha \ --report lcovonly \ -- -u exports \ - $(REQUIRED) \ - $(TESTS) \ + --timeout 10000 \ + --require co-mocha \ --bail jshint: @${npm_bin}/jshint . diff --git a/test/detect-port.test.js b/test/detect-port.test.js index 8ea25a4..25e9091 100644 --- a/test/detect-port.test.js +++ b/test/detect-port.test.js @@ -40,34 +40,43 @@ describe('detect port test', () => { it('generator usage', function *() { var _port = 8080; try { - var port = yield detectPort(8080); + var port = yield detectPort(_port); port.should.within(_port, 65535); } catch (err) { console.log(err); } }); - it('promise usage', function *() { - detectPort(8080) + it('promise usage', done => { + var _port = 8080; + detectPort(_port) .then(port => { - console.log(port); + port.should.within(_port, 65535); + done(); }) .catch(err => { console.log(err); + done(); }); }); - it('generator with wrong arguments', function *() { - try { - yield detectPort(); - } catch (err) { - err.should.containEql('wrong number of arguments'); - } + it('promise with wrong arguments', done => { + detectPort() + .then(() => { + done(); + }) + .catch(err => { + err.should.containEql('wrong number of arguments'); + done(); + }); + }); + it('generator with wrong arguments', function *() { try { yield detectPort('8080'); } catch (err) { err.should.containEql('wrong type of arguments'); } }); + });