web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
2.5 KiB

  1. 'use strict';
  2. const debug = require('debug')('detect-port');
  3. const net = require('net');
  4. const address = require('address');
  5. module.exports = (port, host, callback) => {
  6. if (typeof port === 'function') {
  7. callback = port;
  8. port = null;
  9. } else if (typeof host === 'function') {
  10. callback = host;
  11. host = null;
  12. }
  13. port = parseInt(port) || 0;
  14. let maxPort = port + 10;
  15. if (maxPort > 65535) {
  16. maxPort = 65535;
  17. }
  18. debug('detect free port between [%s, %s)', port, maxPort);
  19. if (typeof callback === 'function') {
  20. return tryListen(host, port, maxPort, callback);
  21. }
  22. // promise
  23. return new Promise((resolve, reject) => {
  24. tryListen(host, port, maxPort, (error, realPort) => {
  25. if (error) {
  26. reject(error);
  27. } else {
  28. resolve(realPort);
  29. }
  30. });
  31. });
  32. };
  33. function tryListen(host, port, maxPort, callback) {
  34. function handleError() {
  35. port++;
  36. if (port >= maxPort) {
  37. debug(
  38. 'port: %s >= maxPort: %s, give up and use random port',
  39. port,
  40. maxPort
  41. );
  42. port = 0;
  43. maxPort = 0;
  44. }
  45. tryListen(host, port, maxPort, callback);
  46. }
  47. // 1. check specified host (or null)
  48. listen(port, host, (err, realPort) => {
  49. // ignore random listening
  50. if (port === 0) {
  51. return callback(err, realPort);
  52. }
  53. if (err) {
  54. return handleError(err);
  55. }
  56. // 2. check default host
  57. listen(port, null, err => {
  58. if (err) {
  59. return handleError(err);
  60. }
  61. // 3. check localhost
  62. listen(port, 'localhost', err => {
  63. if (err) {
  64. return handleError(err);
  65. }
  66. // 4. check current ip
  67. let ip;
  68. try {
  69. ip = address.ip();
  70. } catch (err) {
  71. // Skip the `ip` check if `address.ip()` fails
  72. return callback(null, realPort);
  73. }
  74. listen(port, ip, (err, realPort) => {
  75. if (err) {
  76. return handleError(err);
  77. }
  78. callback(null, realPort);
  79. });
  80. });
  81. });
  82. });
  83. }
  84. function listen(port, hostname, callback) {
  85. const server = new net.Server();
  86. server.on('error', err => {
  87. debug('listen %s:%s error: %s', hostname, port, err);
  88. server.close();
  89. if (err.code === 'ENOTFOUND') {
  90. debug('ignore dns ENOTFOUND error, get free %s:%s', hostname, port);
  91. return callback(null, port);
  92. }
  93. return callback(err);
  94. });
  95. server.listen(port, hostname, () => {
  96. port = server.address().port;
  97. server.close();
  98. debug('get free %s:%s', hostname, port);
  99. return callback(null, port);
  100. });
  101. }