11const net = require ( 'node:net' ) ;
22
3- function isPortAvailable ( port , host = '0.0.0.0' ) {
3+ const minRandomPort = 15000 ;
4+ const maxRandomPort = 45000 ;
5+
6+ async function isPortAvailable ( port , host = '0.0.0.0' ) {
47 try {
58 const server = net . createServer ( ) ;
69
710 server . unref ( ) ;
811
9- return new Promise ( ( resolve ) => {
12+ return await new Promise ( ( resolve ) => {
1013 server . on ( 'listening' , ( ) => {
1114 server . close ( ( ) => {
1215 resolve ( true ) ;
@@ -24,33 +27,15 @@ function isPortAvailable(port, host = '0.0.0.0') {
2427
2528const portMap = new Map ( ) ;
2629
27- /**
28- * Get a random port.
29- * Available port ranges: 1024 ~ 65535
30- * `10080` is not available on macOS CI, `> 50000` gets "permission denied" on Windows,
31- * so we use `15000` ~ `45000`.
32- */
33- async function getRandomPort (
34- defaultPort = Math . ceil ( Math . random ( ) * 30000 ) + 15000 ,
35- host ,
36- ) {
37- let port = defaultPort ;
38-
39- while ( true ) {
40- if ( ! portMap . get ( port ) && ( await isPortAvailable ( port , host ) ) ) {
41- portMap . set ( port , 1 ) ;
42-
43- return port ;
44- }
45-
46- port += 1 ;
47- }
30+ function getDefaultPort ( ) {
31+ return Math . ceil ( Math . random ( ) * 30000 ) + minRandomPort ;
4832}
4933
50- async function getRandomPorts ( count , host ) {
51- let port = await getRandomPort ( undefined , host ) ;
34+ async function findAvailablePort ( startPort , count , host ) {
35+ let port = Math . max ( startPort , minRandomPort ) ;
36+ const maxStartPort = maxRandomPort - count + 1 ;
5237
53- while ( true ) {
38+ while ( port <= maxStartPort ) {
5439 let isAvailable = true ;
5540
5641 for ( let index = 0 ; index < count ; index += 1 ) {
@@ -61,27 +46,60 @@ async function getRandomPorts(count, host) {
6146 ! ( await isPortAvailable ( currentPort , host ) )
6247 ) {
6348 isAvailable = false ;
64- port = currentPort + 1 ;
6549 break ;
6650 }
6751 }
6852
6953 if ( isAvailable ) {
70- const ports = [ ] ;
54+ return port ;
55+ }
7156
72- for ( let index = 0 ; index < count ; index += 1 ) {
73- const currentPort = port + index ;
57+ port += 1 ;
58+ }
7459
75- portMap . set ( currentPort , 1 ) ;
76- ports . push ( currentPort ) ;
77- }
60+ throw new Error ( 'No available ports found' ) ;
61+ }
7862
79- return ports ;
80- }
63+ /**
64+ * Get a random port.
65+ * Available port ranges: 1024 ~ 65535
66+ * `10080` is not available on macOS CI, `> 50000` gets "permission denied" on Windows,
67+ * so we use `15000` ~ `45000`.
68+ */
69+ async function getRandomPort ( defaultPort = getDefaultPort ( ) , host ) {
70+ const port = await findAvailablePort ( defaultPort , 1 , host ) ;
71+
72+ portMap . set ( port , 1 ) ;
73+
74+ return port ;
75+ }
76+
77+ async function getRandomPorts ( count , host ) {
78+ if ( count < 1 ) {
79+ throw new Error ( 'Port count must be greater than 0' ) ;
80+ }
81+
82+ const port = await findAvailablePort ( getDefaultPort ( ) , count , host ) ;
83+ const ports = [ ] ;
84+
85+ for ( let index = 0 ; index < count ; index += 1 ) {
86+ const currentPort = port + index ;
87+
88+ portMap . set ( currentPort , 1 ) ;
89+ ports . push ( currentPort ) ;
90+ }
91+
92+ return ports ;
93+ }
94+
95+ function releaseRandomPorts ( ports = [ ] ) {
96+ for ( const port of ports ) {
97+ portMap . delete ( port ) ;
8198 }
8299}
83100
84101module . exports = {
85102 getRandomPort,
86103 getRandomPorts,
104+ releaseRandomPorts,
87105} ;
0 commit comments