format import { DeviceType , timeout } from 'flipper-common' ; import child_process , { ChildProcess } from 'child_process' ; import { IOSBridge } from './IOSBridge' ; import { ServerDevice } from '../ServerDevice' ; import { FlipperServerImpl } from '../../FlipperServerImpl' ; import { iOSCrashWatcher } from './iOSCrashUtils' ; import { iOSLogListener } from './iOSLogListener' ; export default class IOSDevice extends ServerDevice { log ? : child_process . ChildProcessWithoutNullStreams ; buffer : string ; private recordingProcess ? : ChildProcess ; private recordingLocation ? : string ; private iOSBridge : IOSBridge ; readonly logListener : iOSLogListener ; readonly crashWatcher : iOSCrashWatcher ; constructor ( flipperServer , iOSBridge , serial , deviceType , title ) { super ( flipperServer , { serial , deviceType , title , os : 'iOS' , icon : 'mobile' , } ) ; this . buffer = '' ; this . iOSBridge = iOSBridge ; this . logListener = new iOSLogListener ( ( ) => this . connected , ( logEntry ) => this . addLogEntry ( logEntry ) , this . iOSBridge , this . serial , this . info . deviceType ) ; this . logListener . start ( ) . catch ( ( e ) => console . error ( 'IOSDevice.logListener.start -> unexpected error' , e ) ) ; this . crashWatcher = new iOSCrashWatcher ( this ) ; this . crashWatcher . start ( ) . catch ( ( e ) => console . error ( 'IOSDevice.crashWatcher.start -> unexpected error' , e ) ) ; } async screenshot ( ) { if ( ! this . connected ) { return Buffer . from ( [ ] ) ; } return await this . iOSBridge . screenshot ( this . serial ) ; } async navigateToLocation ( location ) { return this . iOSBridge . navigate ( this . serial , location ) . catch ( ( err ) => { console . warn ( `Failed to navigate to location ${ location }:` , err ) ; return err ; } ) ; } async screenCaptureAvailable ( ) { return this . info . deviceType === 'emulator' && this . connected ; } async startScreenCapture ( destination ) { this . recordingProcess = this . iOSBridge . recordVideo ( this . serial , destination ) ; this . recordingLocation = destination ; } async stopScreenCapture ( ) { if ( this . recordingProcess && this . recordingLocation ) { const prom = new Promise < void > ( ( resolve , _reject ) => { this . recordingProcess ! . on ( 'exit' , async ( _code , _signal ) => { resolve ( ) ; } ) ; this . recordingProcess ! . kill ( 'SIGINT' ) ; } ) ; const output = await timeout < void > ( 5000 , prom , 'Timed out to stop a screen capture.' ) . then ( ( ) => { const { recordingLocation } = this ; this . recordingLocation = undefined ; return recordingLocation ! ; } ) . catch ( ( e ) => { this . recordingLocation = undefined ; console . warn ( 'Failed to terminate iOS screen recording:' , e ) ; throw e ; } ) ; return output ; } throw new Error ( 'No recording in progress' ) ; } disconnect ( ) { if ( this . recordingProcess && this . recordingLocation ) { this . stopScreenCapture ( ) ; } super . disconnect ( ) ; } }