getPort.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _nodeNet = _interopRequireDefault(require("node:net"));
  7. var _nodeOs = _interopRequireDefault(require("node:os"));
  8. function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
  9. /*
  10. * Based on the packages get-port https://www.npmjs.com/package/get-port
  11. * and portfinder https://www.npmjs.com/package/portfinder
  12. * The code structure is similar to get-port, but it searches
  13. * ports deterministically like portfinder
  14. */
  15. const minPort = 1024;
  16. const maxPort = 65_535;
  17. /**
  18. * @returns {Set<string | undefined>} local hosts
  19. */
  20. const getLocalHosts = () => {
  21. const interfaces = _nodeOs.default.networkInterfaces();
  22. // Add undefined value for createServer function to use default host,
  23. // and default IPv4 host in case createServer defaults to IPv6.
  24. const results = new Set([undefined, "0.0.0.0"]);
  25. for (const _interface of Object.values(interfaces)) {
  26. if (_interface) {
  27. for (const config of _interface) {
  28. results.add(config.address);
  29. }
  30. }
  31. }
  32. return results;
  33. };
  34. /**
  35. * @param {number} basePort base port
  36. * @param {string | undefined} host host
  37. * @returns {Promise<number>} resolved port
  38. */
  39. const checkAvailablePort = (basePort, host) => new Promise((resolve, reject) => {
  40. const server = _nodeNet.default.createServer();
  41. server.unref();
  42. server.on("error", reject);
  43. server.listen(basePort, host, () => {
  44. // Next line should return AddressInfo because we're calling it after listen() and before close()
  45. const {
  46. port
  47. } = /** @type {import("net").AddressInfo} */
  48. server.address();
  49. server.close(() => {
  50. resolve(port);
  51. });
  52. });
  53. });
  54. /**
  55. * @param {number} port port
  56. * @param {Set<string | undefined>} hosts hosts
  57. * @returns {Promise<number>} resolved port
  58. */
  59. const getAvailablePort = async (port, hosts) => {
  60. /**
  61. * Errors that mean that host is not available.
  62. * @type {Set<string | undefined>}
  63. */
  64. const nonExistentInterfaceErrors = new Set(["EADDRNOTAVAIL", "EINVAL"]);
  65. /* Check if the post is available on every local host name */
  66. for (const host of hosts) {
  67. try {
  68. await checkAvailablePort(port, host);
  69. } catch (error) {
  70. /* We throw an error only if the interface exists */
  71. if (!nonExistentInterfaceErrors.has(/** @type {NodeJS.ErrnoException} */error.code)) {
  72. throw error;
  73. }
  74. }
  75. }
  76. return port;
  77. };
  78. /**
  79. * @param {number} basePort base port
  80. * @param {string=} host host
  81. * @returns {Promise<number>} resolved port
  82. */
  83. async function getPorts(basePort, host) {
  84. if (basePort < minPort || basePort > maxPort) {
  85. throw new Error(`Port number must lie between ${minPort} and ${maxPort}`);
  86. }
  87. let port = basePort;
  88. const localhosts = getLocalHosts();
  89. const hosts = host && !localhosts.has(host) ? new Set([host]) :
  90. /* If the host is equivalent to localhost
  91. we need to check every equivalent host
  92. else the port might falsely appear as available
  93. on some operating systems */
  94. localhosts;
  95. /** @type {Set<string | undefined>} */
  96. const portUnavailableErrors = new Set(["EADDRINUSE", "EACCES"]);
  97. while (port <= maxPort) {
  98. try {
  99. const availablePort = await getAvailablePort(port, hosts);
  100. return availablePort;
  101. } catch (error) {
  102. /* Try next port if port is busy; throw for any other error */
  103. if (!portUnavailableErrors.has(/** @type {NodeJS.ErrnoException} */error.code)) {
  104. throw error;
  105. }
  106. port += 1;
  107. }
  108. }
  109. throw new Error("No available ports found");
  110. }
  111. var _default = exports.default = getPorts;