Tunnel.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. const events_1 = require("events");
  7. const url_1 = require("url");
  8. const axios_1 = __importDefault(require("axios"));
  9. const debug_1 = __importDefault(require("debug"));
  10. const TunnelCluster_1 = __importDefault(require("./TunnelCluster"));
  11. const debugLog = (0, debug_1.default)('localtunnel:client');
  12. class Tunnel extends events_1.EventEmitter {
  13. constructor(opts = {}) {
  14. super();
  15. this.opts = opts;
  16. this.closed = false;
  17. if (!this.opts.host) {
  18. this.opts.host = 'https://localtunnel.me';
  19. }
  20. }
  21. _getInfo(body) {
  22. const { id, ip, port, url, cached_url, max_conn_count } = body;
  23. const { host, port: local_port, local_host } = this.opts;
  24. const { local_https, local_cert, local_key, local_ca, allow_invalid_cert } = this.opts;
  25. return {
  26. name: id,
  27. url,
  28. cached_url,
  29. max_conn: max_conn_count || 1,
  30. remote_host: (0, url_1.parse)(host).hostname,
  31. remote_ip: ip,
  32. remote_port: port,
  33. local_port,
  34. local_host,
  35. local_https,
  36. local_cert,
  37. local_key,
  38. local_ca,
  39. allow_invalid_cert,
  40. };
  41. }
  42. _init(callback) {
  43. const opt = this.opts;
  44. const getInfo = this._getInfo.bind(this);
  45. const params = {
  46. responseType: 'json',
  47. };
  48. const baseUri = `${opt.host}/`;
  49. // no subdomain at first, maybe use requested domain
  50. const assignedDomain = opt.subdomain;
  51. // where to quest
  52. const uri = baseUri + (assignedDomain || '?new') +
  53. (opt.port ? `&port=${opt.port}` : '');
  54. debugLog('请求隧道服务器: %s', uri);
  55. const getUrl = () => {
  56. axios_1.default
  57. .get(uri, params)
  58. .then(res => {
  59. const body = res.data;
  60. debugLog('got tunnel information', body);
  61. if (res.status !== 200) {
  62. const err = new Error((body && body.message) || 'localtunnel server returned an error, please try again');
  63. return callback(err);
  64. }
  65. callback(null, getInfo(body));
  66. })
  67. .catch(err => {
  68. debugLog(`tunnel server offline: ${err.message}, retry 1s`);
  69. return setTimeout(getUrl, 1000);
  70. });
  71. };
  72. getUrl();
  73. }
  74. _establish(info) {
  75. // 为 max_conn 设置默认值
  76. const maxConn = info.max_conn || 1; // 如果 max_conn 未定义,默认为 1
  77. // increase max event listeners so that localtunnel consumers don't get
  78. // warning messages as soon as they setup even one listener. See #71
  79. this.setMaxListeners(maxConn + (events_1.EventEmitter.defaultMaxListeners || 10));
  80. this.tunnelCluster = new TunnelCluster_1.default(info);
  81. // only emit the url the first time
  82. this.tunnelCluster.once('open', () => {
  83. this.emit('url', info.url);
  84. });
  85. // re-emit socket error
  86. this.tunnelCluster.on('error', err => {
  87. debugLog('got socket error', err.message);
  88. this.emit('error', err);
  89. });
  90. let tunnelCount = 0;
  91. // track open count
  92. this.tunnelCluster.on('open', tunnel => {
  93. tunnelCount++;
  94. debugLog('tunnel open [total: %d]', tunnelCount);
  95. const closeHandler = () => {
  96. tunnel.destroy();
  97. };
  98. if (this.closed) {
  99. return closeHandler();
  100. }
  101. this.once('close', closeHandler);
  102. tunnel.once('close', () => {
  103. this.removeListener('close', closeHandler);
  104. });
  105. });
  106. // when a tunnel dies, open a new one
  107. this.tunnelCluster.on('dead', () => {
  108. var _a;
  109. tunnelCount--;
  110. debugLog('tunnel dead [total: %d]', tunnelCount);
  111. if (this.closed) {
  112. return;
  113. }
  114. (_a = this.tunnelCluster) === null || _a === void 0 ? void 0 : _a.open();
  115. });
  116. this.tunnelCluster.on('request', req => {
  117. this.emit('request', req);
  118. });
  119. // establish as many tunnels as allowed
  120. for (let count = 0; count < maxConn; ++count) { // 使用 maxConn 变量
  121. this.tunnelCluster.open();
  122. }
  123. }
  124. open(callback) {
  125. this._init((err, info) => {
  126. if (err) {
  127. return callback(err);
  128. }
  129. this.clientId = info.name;
  130. this.url = info.url;
  131. // `cached_url` is only returned by proxy servers that support resource caching.
  132. if (info.cached_url) {
  133. this.cachedUrl = info.cached_url;
  134. }
  135. this._establish(info);
  136. callback(null);
  137. });
  138. }
  139. close() {
  140. this.closed = true;
  141. this.emit('close');
  142. }
  143. }
  144. exports.default = Tunnel;