import net from 'net' ; import address from './address' ; import { BalmError } from '@balm-core/index' ; const UTIL_NAME = 'detect port' ; const MAX_PORT = 65535 ; function listen ( port , host , callback ) { const server = new net . Server ( ) ; server . on ( 'error' , ( error ) => { server . close ( ) ; if ( error . code === 'ENOTFOUND' ) { BalmJS . logger . error ( UTIL_NAME , `ignore dns ENOTFOUND error, get free ${ host as string }:${ port }` , { logLevel : BalmJS . LogLevel . Debug } ) ; return callback ( null , port ) ; } return callback ( error ) ; } ) ; server . listen ( port , host as string , ( ) => { port = ( server . address ( ) as { port : number ; } ) . port ; server . close ( ) ; BalmJS . logger . debug ( UTIL_NAME , `get free ${ host as string }:${ port }` ) ; return callback ( null , port ) ; } ) ; } function tryListen ( port , maxPort , host , callback ) { function handleError ( err ? ) { if ( err ) { BalmJS . logger . error ( UTIL_NAME , err . message , { logLevel : BalmJS . LogLevel . Debug } ) ; } port ++ ; if ( port >= maxPort ) { BalmJS . logger . warn ( UTIL_NAME , `port: ${ port } >= maxPort: ${ maxPort }, give up and use random port` , { logLevel : BalmJS . LogLevel . Debug } ) ; port = 0 ; maxPort = 0 ; } tryListen ( port , maxPort , host , callback ) ; } if ( host ) { listen ( port , host , ( error , realPort ) => { if ( error ) { if ( error . code === 'EADDRNOTAVAIL' ) { return callback ( new Error ( 'the ip that is not unkonwn on the machine' ) ) ; } return handleError ( ) ; } callback ( null , realPort ) ; } ) ; } else { listen ( port , null , ( error , realPort ) => { if ( port === 0 ) { return callback ( error , realPort ) ; } if ( error ) { return handleError ( error ) ; } listen ( port , '0.0.0.0' , ( error ) => { if ( error ) { return handleError ( error ) ; } listen ( port , 'localhost' , ( error ) => { if ( error && error . code !== 'EADDRNOTAVAIL' ) { return handleError ( error ) ; } listen ( port , address . ip ( ) , ( error , realPort ) => { if ( error ) { return handleError ( error ) ; } callback ( null , realPort ) ; } ) ; } ) ; } ) ; } ) ; } } function detectPort ( port , host ) { let maxPort = port + 10 ; if ( maxPort > MAX_PORT ) { maxPort = MAX_PORT ; } BalmJS . logger . debug ( UTIL_NAME , `detect free port between [${ port }, ${ maxPort }]` ) ; return new Promise ( ( resolve ) => { tryListen ( port , maxPort , host , ( error , realPort ) => { resolve ( realPort ) ; } ) ; } ) ; } export default detectPort ;