adds auto port generation

This commit is contained in:
Sam Eaton 2016-04-08 14:28:58 -06:00
parent 37624b4b1a
commit 0bfb740253
4 changed files with 130 additions and 46 deletions

View file

@ -26,8 +26,9 @@ autossh({
.on('error', err => {
console.error('ERROR: ', err);
})
.on('init', () => {
console.log('connected. Ready to do other stuff.');
.on('connect', connection => {
console.log('connected. Tunnel established on port ' + connection.localPort);
console.log('pid: ' + connection.pid);
});
```
@ -37,11 +38,21 @@ autossh({
ssh -NL 64444:localhost:5432 root@111.22.333.444
```
#### To Kill
#### Generate Dynamic Local Port
If you want to dynamically/randomly generate a port number, provide a string `auto` for the `localPort`.
Port conflicts will automatically be avoided and the generated port will not be in use.
See `demo.js` for ean example.
#### Killing the Autossh Process
The autossh process will automatically die if the node process is closed, but you can manually kill the process using `kill`.
**Example**
If you try to kill the ssh process from the command line while the node process is active, a new ssh tunnel will be established (which is the point of autossh). You will need to kill the node process first or call the `kill` method on the instance.
**Example 1**
``` javascript
const myAutossh = autossh({
@ -50,12 +61,24 @@ const myAutossh = autossh({
localPort: 64444,
remotePort: 5432
})
.on('error', err => {
console.error('ERROR: ', err);
})
.on('init', () => {
console.log('connected. Ready to do other stuff.');
.on('connect', connection => {
console.log('connected: ', connection);
});
myAutossh.kill();
```
**Example 2**
``` javascript
const myAutossh = autossh({
host: '111.22.333.444',
username: 'root',
localPort: 64444,
remotePort: 5432
})
.on('connect', connection => {
console.log('connected: ', connection);
connection.kill();
});
```

47
demo.js
View file

@ -1,17 +1,52 @@
'use strict';
const autossh = require('./index.js');
// open 10 ssh tunnels
for (let i = 0; i < 5; i++) {
// set up config
autossh({
host: '104.131.150.215',
username: 'same',
localPort: 60001,
host: '104.131.150.215', // enter host address
username: 'same', // enter username
localPort: 'auto', // 'auto' or port number
remotePort: 5432
})
// listen for errors
.on('error', err => {
console.error('ERROR: ', err);
})
.on('init', connection => {
console.log('connected.');
// listen for connection
.on('connect', connection => {
console.log('\n**connected**');
console.log('localPort: \t' + connection.localPort);
console.log('pid: \t\t' + connection.pid);
console.log(`tunnel established from localhost:${connection.localPort} to ${connection.host}:${connection.remotePort} as ${connection.username}`);
});
}
/* Possible output example (localPort results are be random)
**connected**
localPort: 39570
pid: 7477
tunnel established from localhost:39570 to xyz.xy.xyz.yz:5432 as same
**connected**
localPort: 53139
pid: 7478
tunnel established from localhost:53139 to xyz.xy.xyz.yz:5432 as same
**connected**
localPort: 56421
pid: 7479
tunnel established from localhost:56421 to xyz.xy.xyz.yz:5432 as same
**connected**
localPort: 5360
pid: 7480
tunnel established from localhost:5360 to xyz.xy.xyz.yz:5432 as same
**connected**
localPort: 40321
pid: 7481
tunnel established from localhost:40321 to xyz.xy.xyz.yz:5432 as same
*/

View file

@ -36,19 +36,31 @@ var AutoSSH = function (_EventEmitter) {
_this.remotePort = conf.remotePort;
_this.localPort = conf.localPort;
_portfinder2.default.basePort = _this.localPort;
_portfinder2.default.getPort({ port: _this.localPort }, function (err, result) {
console.log('Error: ', err);
console.log('result: ', result);
});
setImmediate(function () {
if (!conf.localPort) return _this.emit('error', 'Missing localPort');
_portfinder2.default.getPort({
port: _this.localPort === 'auto' ? _this.generateRandomPort() : _this.localPort
}, function (err, freePort) {
if (err) return _this.emit('error', 'Port error: ' + err);
if (_this.localPort !== 'auto' && _this.localPort !== freePort) return _this.emit('error', 'Port ' + _this.localPort + ' is not available');
if (!conf.host) return _this.emit('error', 'Missing host');
if (!conf.username) return _this.emit('error', 'Missing username');
if (!conf.remotePort) return _this.emit('error', 'Missing remotePort');
if (!conf.localPort) return _this.emit('error', 'Missing localPort');
_this.localPort = freePort;
_this.execTunnel();
_this.emit('init', { kill: _this.kill, pid: _this.currentProcess.pid, currentProcess: _this.currentProcess });
_this.emit('connect', {
kill: _this.kill,
pid: _this.currentProcess.pid,
host: _this.host,
username: _this.username,
remotePort: _this.remotePort,
localPort: _this.localPort
});
});
});
process.on('exit', function () {
@ -58,6 +70,13 @@ var AutoSSH = function (_EventEmitter) {
}
_createClass(AutoSSH, [{
key: 'generateRandomPort',
value: function generateRandomPort() {
var minPort = 3000;
var maxPort = 65535;
return Math.floor(Math.random() * (maxPort - minPort + 1)) + minPort;
}
}, {
key: 'execTunnel',
value: function execTunnel() {
var _this2 = this;
@ -66,7 +85,7 @@ var AutoSSH = function (_EventEmitter) {
var userAtHost = this.username + '@' + this.host;
var exitOnFailure = '-o "ExitOnForwardFailure yes"';
var execString = 'ssh -NL ' + bindAddress + ' ' + exitOnFailure + ' ' + userAtHost;
console.log('execString: ', execString);
this.currentProcess = (0, _child_process.exec)(execString, function (err, stdout, stderr) {
if (/Address already in use/i.test(stderr)) {
_this2.kill();

View file

@ -13,48 +13,55 @@ class AutoSSH extends EventEmitter {
this.remotePort = conf.remotePort;
this.localPort = conf.localPort;
portfinder.getPort({port: this.localPort === 'auto' ? 8000 : this.localPort}, (err, freePort) => {
console.log('Error: ', err);
if (this.localPort !== 'auto' && this.localPort !== freePort) {
return console.error(`Port ${this.localPort} is not available`);
}
this.localPort = result;
setImmediate(() => {
if (!conf.localPort)
return this.emit('error', 'Missing localPort');
portfinder.getPort({
port: this.localPort === 'auto' ? this.generateRandomPort() : this.localPort
}, (err, freePort) => {
if (err)
return this.emit('error', 'Port error: ' + err);
if (this.localPort !== 'auto' && this.localPort !== freePort)
return this.emit('error', `Port ${this.localPort} is not available`);
if (!conf.host)
return this.emit('error', 'Missing host');
if (!conf.username)
return this.emit('error', 'Missing username');
if (!conf.remotePort)
return this.emit('error', 'Missing remotePort');
if (!conf.localPort)
return this.emit('error', 'Missing localPort');
this.localPort = freePort;
this.execTunnel();
this.emit('init', {
this.emit('connect', {
kill: this.kill,
pid: this.currentProcess.pid,
host: this.host,
username: this.username,
remotePort: this.remotePort,
localPort: this.localPort,
localPort: this.localPort
});
});
});
process.on('exit', () => {
this.kill();
});
}
generateRandomPort() {
const minPort = 3000;
const maxPort = 65535;
return Math.floor(Math.random() * (maxPort - minPort + 1)) + minPort;
}
execTunnel() {
const bindAddress = `${this.localPort}:localhost:${this.remotePort}`;
const userAtHost = `${this.username}@${this.host}`;
const exitOnFailure = '-o "ExitOnForwardFailure yes"'
const execString = `ssh -NL ${bindAddress} ${exitOnFailure} ${userAtHost}`;
console.log('execString: ', execString);
this.currentProcess = exec(execString, (err, stdout, stderr) => {
if (/Address already in use/i.test(stderr)) {
this.kill();