UNPKG

@onboardbase/cli

Version:

[![Version](https://img.shields.io/npm/v/@onboardbase/cli.svg)](https://www.npmjs.com/package/@onboardbase/cli) [![Downloads/week](https://img.shields.io/npm/dw/@onboardbase/cli.svg)](https://www.npmjs.com/package/@onboardbase/cli) [![License](https://img

147 lines (146 loc) 5.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable consistent-return, no-underscore-dangle */ const url_1 = require("url"); const events_1 = require("events"); const axios = require("axios"); const _debugger = require("debug"); const tunnelCluster_1 = require("./tunnelCluster"); const debug = _debugger("tunnel:client"); class Tunnel extends events_1.EventEmitter { constructor(opts) { // @ts-ignore super(opts); this.closed = false; this.tunnelCluster = null; this.opts = opts; this.closed = false; if (!this.opts.host) { this.opts.host = "https://tunnels.onboardbase.com"; } } _axiosInstance(uri) { } _getInfo(body) { /* eslint-disable camelcase */ const { id, ip, port, url, cached_url, max_conn_count } = body; const { host, port: local_port, local_host } = this.opts; const { local_https, local_cert, local_key, local_ca, allow_invalid_cert } = this.opts; return { name: id, url, cached_url, max_conn: max_conn_count || 1, remote_host: (0, url_1.parse)(host).hostname, remote_ip: ip, remote_port: port, local_port, local_host, local_https, local_cert, local_key, local_ca, allow_invalid_cert, }; /* eslint-enable camelcase */ } // initialize connection // callback with connection info _init(cb) { const opt = this.opts; const getInfo = this._getInfo.bind(this); const params = { responseType: "json", }; const baseUri = `${opt.host}/`; // no subdomain at first, maybe use requested domain const assignedDomain = opt.subdomain; // where to quest const uri = baseUri + (assignedDomain || "?new"); (function getUrl() { // @ts-ignore const axiosGet = axios.get; axiosGet(uri, params) .then((res) => { const body = res.data; debug("got tunnel information", res.data); if (res.status !== 200) { const err = new Error((body && body.message) || "localtunnel server returned an error, please try again"); return cb(err); } cb(null, getInfo(body)); }) .catch((err) => { debug(`tunnel server offline: ${err.message}, retry 1s`); return setTimeout(getUrl, 1000); }); })(); } _establish(info) { // increase max event listeners so that localtunnel consumers don't get // warning messages as soon as they setup even one listener. See #71 this.setMaxListeners(info.max_conn + (events_1.EventEmitter.defaultMaxListeners || 10)); this.tunnelCluster = new tunnelCluster_1.default(info); // only emit the url the first time this.tunnelCluster.once("open", () => { this.emit("url", info.url); }); // re-emit socket error this.tunnelCluster.on("error", (err) => { debug("got socket error", err.message); this.emit("error", err); }); let tunnelCount = 0; // track open count this.tunnelCluster.on("open", (tunnel) => { tunnelCount++; debug("tunnel open [total: %d]", tunnelCount); const closeHandler = () => { tunnel.destroy(); }; if (this.closed) { return closeHandler(); } this.once("close", closeHandler); tunnel.once("close", () => { this.removeListener("close", closeHandler); }); }); // when a tunnel dies, open a new one this.tunnelCluster.on("dead", () => { tunnelCount--; debug("tunnel dead [total: %d]", tunnelCount); if (this.closed) { return; } this.tunnelCluster.open(); }); this.tunnelCluster.on("request", (req) => { this.emit("request", req); }); // establish as many tunnels as allowed for (let count = 0; count < info.max_conn; ++count) { this.tunnelCluster.open(); } } open(cb) { this._init((err, info) => { if (err) { return cb(err); } this.clientId = info.name; this.url = info.url; // `cached_url` is only returned by proxy servers that support resource caching. if (info.cached_url) { this.cachedUrl = info.cached_url; } this._establish(info); cb(); }); } close() { this.closed = true; this.emit("close"); } } exports.default = Tunnel;