11import net from 'net' ;
22import { createLock } from './locks' ;
33
4- const getAvailablePort = ( portToTry : number ) =>
5- new Promise < 'available' | 'unavailable' > ( ( resolve ) => {
6- let status : 'available' | 'unavailable' = 'unavailable' ;
4+ type PortStatus = 'available' | 'unavailable' ;
5+
6+ const isPortAvailableOnHost = ( {
7+ portToTry,
8+ host,
9+ } : {
10+ portToTry : number ;
11+ host : string ;
12+ } ) : Promise < PortStatus > => {
13+ return new Promise < PortStatus > ( ( resolve ) => {
14+ let status : PortStatus = 'unavailable' ;
715
8- const host = '127.0.0.1' ;
916 const socket = new net . Socket ( ) ;
1017
1118 socket . on ( 'connect' , ( ) => {
@@ -28,12 +35,42 @@ const getAvailablePort = (portToTry: number) =>
2835
2936 socket . connect ( portToTry , host ) ;
3037 } ) ;
38+ } ;
39+
40+ export const testPortAvailableOnMultipleHosts = async ( {
41+ hosts,
42+ port,
43+ } : {
44+ port : number ;
45+ hosts : string [ ] ;
46+ } ) : Promise < PortStatus > => {
47+ const results = await Promise . all (
48+ hosts . map ( ( host ) => {
49+ return isPortAvailableOnHost ( { portToTry : port , host} ) ;
50+ } ) ,
51+ ) ;
52+
53+ return results . every ( ( r ) => r === 'available' ) ? 'available' : 'unavailable' ;
54+ } ;
3155
32- const getPort = async ( from : number , to : number ) => {
56+ const getPort = async ( {
57+ from,
58+ to,
59+ hostsToTest,
60+ } : {
61+ from : number ;
62+ to : number ;
63+ hostsToTest : string [ ] ;
64+ } ) => {
3365 const ports = makeRange ( from , to ) ;
3466
3567 for ( const port of ports ) {
36- if ( ( await getAvailablePort ( port ) ) === 'available' ) {
68+ if (
69+ ( await testPortAvailableOnMultipleHosts ( {
70+ port,
71+ hosts : hostsToTest ,
72+ } ) ) === 'available'
73+ ) {
3774 return port ;
3875 }
3976 }
@@ -43,22 +80,31 @@ const getPort = async (from: number, to: number) => {
4380
4481const portLocks = createLock ( { timeout : 10000 } ) ;
4582
46- export const getDesiredPort = async (
47- desiredPort : number | undefined ,
48- from : number ,
49- to : number ,
50- ) => {
83+ export const getDesiredPort = async ( {
84+ desiredPort,
85+ from,
86+ hostsToTry,
87+ to,
88+ } : {
89+ desiredPort : number | undefined ;
90+ from : number ;
91+ to : number ;
92+ hostsToTry : string [ ] ;
93+ } ) => {
5194 await portLocks . waitForAllToBeDone ( ) ;
5295 const lockPortSelection = portLocks . lock ( ) ;
5396 const didUsePort = ( ) => portLocks . unlock ( lockPortSelection ) ;
5497 if (
5598 typeof desiredPort !== 'undefined' &&
56- ( await getAvailablePort ( desiredPort ) ) === 'available'
99+ ( await testPortAvailableOnMultipleHosts ( {
100+ port : desiredPort ,
101+ hosts : [ '0.0.0.0' , '127.0.0.1' ] ,
102+ } ) ) === 'available'
57103 ) {
58104 return { port : desiredPort , didUsePort} ;
59105 }
60106
61- const actualPort = await getPort ( from , to ) ;
107+ const actualPort = await getPort ( { from, to, hostsToTest : hostsToTry } ) ;
62108
63109 // If did specify a port but did not get that one, fail hard.
64110 if ( desiredPort && desiredPort !== actualPort ) {
0 commit comments