From 11aab57c03bd1ce0673ea316214e65cabf1ae9d0 Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 30 Apr 2024 11:04:00 +0300 Subject: [PATCH 1/3] feat: implemented ability to reconnect to local server if the connection is lost. --- bin/et.js | 6 +++++- easyTunnel.d.ts | 1 + lib/Tunnel.js | 3 ++- lib/TunnelCluster.js | 23 ++++++++++++++++------- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/bin/et.js b/bin/et.js index 35c25f8..421b83c 100644 --- a/bin/et.js +++ b/bin/et.js @@ -52,6 +52,9 @@ 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.', + }) .require('port') .boolean('local-https') .boolean('allow-invalid-cert') @@ -77,7 +80,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; }); diff --git a/easyTunnel.d.ts b/easyTunnel.d.ts index 3a57e0a..36e8dfb 100644 --- a/easyTunnel.d.ts +++ b/easyTunnel.d.ts @@ -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; diff --git a/lib/Tunnel.js b/lib/Tunnel.js index bbe02af..2855636 100644 --- a/lib/Tunnel.js +++ b/lib/Tunnel.js @@ -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, @@ -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 */ } diff --git a/lib/TunnelCluster.js b/lib/TunnelCluster.js index c94c81b..124252c 100644 --- a/lib/TunnelCluster.js +++ b/lib/TunnelCluster.js @@ -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; @@ -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', @@ -106,18 +109,24 @@ 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; From 993cf7d13fd343fff56bfbc4cfc50a7741c8f4fd Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 30 Apr 2024 11:05:52 +0300 Subject: [PATCH 2/3] chore: bumped package version. --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8f72a58..d30f36d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@namecheap/easy-tunnel", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@namecheap/easy-tunnel", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "dependencies": { "axios": "0.27.2", diff --git a/package.json b/package.json index e26c765..fb875eb 100644 --- a/package.json +++ b/package.json @@ -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", From 44a8bfda7d7ce7b384eba14daa6eed094293b544 Mon Sep 17 00:00:00 2001 From: Vlad Date: Thu, 2 May 2024 11:27:08 +0300 Subject: [PATCH 3/3] feat: added default options, fixed code style. --- bin/et.js | 1 + lib/TunnelCluster.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/et.js b/bin/et.js index 421b83c..3a5c420 100644 --- a/bin/et.js +++ b/bin/et.js @@ -54,6 +54,7 @@ const { argv } = yargs }) .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') diff --git a/lib/TunnelCluster.js b/lib/TunnelCluster.js index 124252c..7667d45 100644 --- a/lib/TunnelCluster.js +++ b/lib/TunnelCluster.js @@ -111,8 +111,7 @@ module.exports = class TunnelCluster extends EventEmitter { remote.removeListener('close', remoteClose); remote.end(); - if(self.localReconnectionRetryCount < localReconnectionMaxRetryCount) - { + if (self.localReconnectionRetryCount < localReconnectionMaxRetryCount) { self.localReconnectionRetryCount++; debug(`Local server connection is lost, reconnnecting. Attempt ${self.localReconnectionRetryCount}/${localReconnectionMaxRetryCount}`);