Skip to content

Commit

Permalink
Merge pull request #6 from namecheap/feat/local-reconnection
Browse files Browse the repository at this point in the history
Add reconnection to local server if the connection is lost
  • Loading branch information
9df906f6 authored May 9, 2024
2 parents 2b79c84 + 44a8bfd commit da6c228
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 12 deletions.
7 changes: 6 additions & 1 deletion bin/et.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ const { argv } = yargs
.option('request-secure-tunnel', {
describe: 'Requests tunel server to create secure tunnel if it is available.',
})
.option('local_max_reconnect_count', {
describe: 'Max number of reconnection retries to local server if it goes offline.',
default: 90,
})
.require('port')
.boolean('local-https')
.boolean('allow-invalid-cert')
Expand All @@ -77,7 +81,8 @@ if (typeof argv.port !== 'number') {
local_key: argv.localKey,
local_ca: argv.localCa,
allow_invalid_cert: argv.allowInvalidCert,
request_secure_tunnel: argv.requestSecureTunnel
request_secure_tunnel: argv.requestSecureTunnel,
local_max_reconnect_count: argv.local_max_reconnect_count
}).catch(err => {
throw err;
});
Expand Down
1 change: 1 addition & 0 deletions easyTunnel.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ declare interface BootstrapOpts {
local_ca?: string;
allow_invalid_cert?: boolean;
request_secure_tunnel?: boolean;
local_max_reconnect_count?: number;
}

declare const localtunnel: (opts: BootstrapOpts) => Promise<Tunnel>;
Expand Down
3 changes: 2 additions & 1 deletion lib/Tunnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module.exports = class Tunnel extends EventEmitter {
/* eslint-disable camelcase */
const { id, ip, port, url, cached_url, max_conn_count, is_tunnel_secure } = body;
const { host, port: local_port, local_host } = this.opts;
const { local_https, local_cert, local_key, local_ca, allow_invalid_cert } = this.opts;
const { local_https, local_cert, local_key, local_ca, allow_invalid_cert, local_max_reconnect_count } = this.opts;
return {
name: id,
url,
Expand All @@ -38,6 +38,7 @@ module.exports = class Tunnel extends EventEmitter {
local_ca,
allow_invalid_cert,
is_tunnel_secure,
local_max_reconnect_count,
};
/* eslint-enable camelcase */
}
Expand Down
22 changes: 15 additions & 7 deletions lib/TunnelCluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ module.exports = class TunnelCluster extends EventEmitter {
constructor(opts = {}) {
super(opts);
this.opts = opts;
this.localReconnectionRetryCount = 0;
}

open() {
const opt = this.opts;
const self = this;

// Prefer IP if returned by the server
const remoteHostOrIp = opt.remote_ip || opt.remote_host;
Expand All @@ -24,6 +26,7 @@ module.exports = class TunnelCluster extends EventEmitter {
const localProtocol = opt.local_https ? 'https' : 'http';
const allowInvalidCert = opt.allow_invalid_cert;
const isTunnelSecure = opt.is_tunnel_secure;
const localReconnectionMaxRetryCount = opt.local_max_reconnect_count !== undefined ? opt.local_max_reconnect_count : 90;

debug(
'establishing tunnel %s://%s:%s <> %s:%s',
Expand Down Expand Up @@ -106,18 +109,23 @@ module.exports = class TunnelCluster extends EventEmitter {
local.end();

remote.removeListener('close', remoteClose);

if (err.code !== 'ECONNREFUSED') {
return remote.end();
}

// retrying connection to local server
setTimeout(connLocal, 1000);
remote.end();

if (self.localReconnectionRetryCount < localReconnectionMaxRetryCount) {
self.localReconnectionRetryCount++;
debug(`Local server connection is lost, reconnnecting. Attempt ${self.localReconnectionRetryCount}/${localReconnectionMaxRetryCount}`);

// retrying connection to local server
setTimeout(connLocal, 1000);
}
});

local.once('connect', () => {
debug('connected locally');
remote.resume();

debug(`Local reconnection counter is reset at value ${self.localReconnectionRetryCount}`);
self.localReconnectionRetryCount = 0;

let stream = remote;

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@namecheap/easy-tunnel",
"description": "Expose localhost to the world",
"version": "1.1.1",
"version": "1.2.0",
"license": "MIT",
"repository": {
"type": "git",
Expand Down

0 comments on commit da6c228

Please sign in to comment.