format import MetroDevice from './MetroDevice' ; import http from 'http' ; import { parseEnvironmentVariableAsNumber } from '../../utils/environmentVariables' ; import { FlipperServerImpl } from '../../FlipperServerImpl' ; import WebSocket from 'ws' ; const METRO_HOST = 'localhost' ; const METRO_PORT = parseEnvironmentVariableAsNumber ( 'METRO_SERVER_PORT' , 8081 ) ; const METRO_URL = `http://${ METRO_HOST }:${ METRO_PORT }` ; const METRO_LOGS_ENDPOINT = `ws://${ METRO_HOST }:${ METRO_PORT }/events` ; const METRO_MESSAGE = [ 'React Native packager is running' , 'Metro is running' ] ; const QUERY_INTERVAL = 5000 ; async function isMetroRunning ( ) { return new Promise ( ( resolve ) => { http . get ( METRO_URL , ( resp ) => { let data = '' ; resp . on ( 'data' , ( chunk ) => { data += chunk ; } ) . on ( 'end' , ( ) => { const isMetro = METRO_MESSAGE . some ( ( msg ) => data . includes ( msg ) ) ; resolve ( isMetro ) ; } ) ; } ) . on ( 'error' , ( err ) => { if ( err . code !== 'ECONNREFUSED' && err . code !== 'ECONNRESET' ) { console . error ( 'Could not connect to METRO ' + err ) ; } resolve ( false ) ; } ) ; } ) ; } async function registerMetroDevice ( ws , flipperServer ) { const metroDevice = new MetroDevice ( flipperServer , METRO_URL , ws ) ; flipperServer . registerDevice ( metroDevice ) ; } export default ( flipperServer ) => { let timeoutHandle ; let ws ; let unregistered = false ; async function tryConnectToMetro ( ) { if ( ws ) { return ; } if ( await isMetroRunning ( ) ) { try { const _ws = new WebSocket ( METRO_LOGS_ENDPOINT , { origin : 'http://localhost:3000/flipper' , } ) ; _ws . onopen = ( ) => { clearTimeout ( guard ) ; ws = _ws ; registerMetroDevice ( ws , flipperServer ) ; } ; _ws . onclose = _ws . onerror = function ( event ? ) { if ( event ?. type === 'error' ) { console . error ( `Failed to connect to Metro on ${ METRO_LOGS_ENDPOINT }` , event ) ; } if ( ! unregistered ) { unregistered = true ; clearTimeout ( guard ) ; ws = undefined ; flipperServer . unregisterDevice ( METRO_URL ) ; scheduleNext ( ) ; } } ; const guard = setTimeout ( ( ) => { flipperServer . emit ( 'notification' , { type : 'error' , title : 'Failed to connect to Metro' , description : `Flipper did find a running Metro instance, but couldn't connect to the logs. Probably your React Native version is too old to support Flipper. Cause: Failed to get a connection to ${ METRO_LOGS_ENDPOINT } in a timely fashion` , } ) ; registerMetroDevice ( undefined , flipperServer ) ; } , 5000 ) ; } catch ( e ) { console . error ( 'Error while setting up Metro websocket connect' , e ) ; } } else { scheduleNext ( ) ; } } function scheduleNext ( ) { timeoutHandle = setTimeout ( tryConnectToMetro , QUERY_INTERVAL ) ; } tryConnectToMetro ( ) ; return ( ) => { if ( ws ) { ws . close ( ) ; } if ( timeoutHandle ) { clearInterval ( timeoutHandle ) ; } } ; } ;