tasq/node_modules/pipenet/dist/Tunnel.js

133 lines
4.0 KiB
JavaScript

import axios from 'axios';
import debug from 'debug';
import { EventEmitter } from 'events';
import { TunnelCluster } from './TunnelCluster.js';
const log = debug('pipenet:client');
export class Tunnel extends EventEmitter {
cachedUrl;
clientId;
closed;
opts;
tunnelCluster;
url;
constructor(opts = {}) {
super();
this.opts = opts;
this.closed = false;
if (!this.opts.host) {
this.opts.host = 'https://pipenet.dev';
}
}
close() {
this.closed = true;
this.emit('close');
}
open(cb) {
this._init((err, info) => {
if (err) {
cb(err);
return;
}
this.clientId = info.name;
this.url = info.url;
if (info.cachedUrl) {
this.cachedUrl = info.cachedUrl;
}
this._establish(info);
cb();
});
}
_establish(info) {
this.setMaxListeners(info.maxConn + (EventEmitter.defaultMaxListeners || 10));
this.tunnelCluster = new TunnelCluster(info);
this.tunnelCluster.once('open', () => {
this.emit('url', info.url);
});
this.tunnelCluster.on('error', (err) => {
log('got socket error', err.message);
this.emit('error', err);
});
let tunnelCount = 0;
this.tunnelCluster.on('open', (tunnel) => {
tunnelCount++;
log('tunnel open [total: %d]', tunnelCount);
const closeHandler = () => {
tunnel.destroy();
};
if (this.closed) {
closeHandler();
return;
}
this.once('close', closeHandler);
tunnel.once('close', () => {
this.removeListener('close', closeHandler);
});
});
this.tunnelCluster.on('dead', () => {
tunnelCount--;
log('tunnel dead [total: %d]', tunnelCount);
if (this.closed) {
return;
}
this.tunnelCluster.open();
});
this.tunnelCluster.on('request', (req) => {
this.emit('request', req);
});
for (let count = 0; count < info.maxConn; ++count) {
this.tunnelCluster.open();
}
}
_getInfo(body) {
const { cachedUrl, id, ip, maxConnCount, port, sharedTunnel, url } = body;
const { host, localHost, port: localPort } = this.opts;
const { allowInvalidCert, localCa, localCert, localHttps, localKey } = this.opts;
return {
allowInvalidCert,
cachedUrl,
localCa,
localCert,
localHost,
localHttps,
localKey,
localPort,
maxConn: maxConnCount || 1,
name: id,
remoteHost: new URL(host).hostname,
remoteIp: ip,
remotePort: port,
sharedTunnel,
url,
};
}
_init(cb) {
const opt = this.opts;
const getInfo = this._getInfo.bind(this);
const params = {
headers: opt.headers || {},
responseType: 'json',
};
const baseUri = `${opt.host}/`;
const assignedDomain = opt.subdomain;
const uri = baseUri + (assignedDomain || '?new');
const getUrl = () => {
axios
.get(uri, params)
.then((res) => {
const body = res.data;
log('got tunnel information', res.data);
if (res.status !== 200) {
const err = new Error(body?.message || 'pipenet server returned an error, please try again');
return cb(err);
}
cb(null, getInfo(body));
})
.catch((err) => {
log(`tunnel server offline: ${err.message}, retry 1s`);
setTimeout(getUrl, 1000);
});
};
getUrl();
}
}
//# sourceMappingURL=Tunnel.js.map