format import type { CrashLog } from 'flipper-common' ; import { DeviceListener } from '../../utils/DeviceListener' ; import fs from 'fs-extra' ; import os from 'os' ; import path from 'path' ; import { ServerDevice } from '../ServerDevice' ; export function parseIosCrash ( content ) { const regex = /Exception Type: *\w*/ ; const arr = regex . exec ( content ) ; const exceptionString = arr ? arr [ 0 ] : '' ; const exceptionRegex = /\w*$/ ; const tmp = exceptionRegex . exec ( exceptionString ) ; const exception = tmp && tmp [ 0 ] . length ? tmp [ 0 ] : 'Unknown' ; const dateRegex = /Date\/Time: *[\w\s\.:-]*/ ; const dateArr = dateRegex . exec ( content ) ; const dateString = dateArr ? dateArr [ 0 ] : '' ; const dateRegex2 = /[\w\s\.:-]*$/ ; const tmp1 = dateRegex2 . exec ( dateString ) ; const extractedDateString = tmp1 && tmp1 [ 0 ] . length ? tmp1 [ 0 ] : null ; const date = extractedDateString ? new Date ( extractedDateString ) . getTime ( ) : Date . now ( ) ; const crash = { callstack : content , name : exception , reason : exception , date , } ; return crash ; } export function shouldShowiOSCrashNotification ( serial , content ) { const appPath = parsePath ( content ) ; if ( ! appPath || ! appPath . includes ( serial ) ) { return false ; } return true ; } export function parsePath ( content ) { const regex = /(?<=.*Path: *)[^\n]*/ ; const arr = regex . exec ( content ) ; if ( ! arr || arr . length <= 0 ) { return null ; } const path = arr [ 0 ] ; return path . trim ( ) ; } export class iOSCrashWatcher extends DeviceListener { constructor ( private readonly device ) { super ( ( ) => device . connected ) ; } protected async startListener ( ) { const dir = path . join ( os . homedir ( ) , 'Library' , 'Logs' , 'DiagnosticReports' ) ; if ( ! ( await fs . pathExists ( dir ) ) ) { throw new Error ( 'Failed to start iOS crash watcher: path does not exist' ) ; } const watcher = fs . watch ( dir , async ( _eventType , filename ) => { const checkFileExtension = /.crash$/ . exec ( filename ) ; if ( ! filename || ! checkFileExtension ) { return ; } const filepath = path . join ( dir , filename ) ; const exists = await fs . pathExists ( filepath ) ; if ( ! exists ) { return ; } fs . readFile ( filepath , 'utf8' , ( err , data ) => { if ( err ) { console . warn ( 'Failed to read crash file' , err ) ; return ; } if ( shouldShowiOSCrashNotification ( this . device . serial , data ) ) { this . device . flipperServer . emit ( 'device-crash' , { crash : parseIosCrash ( data ) , serial : this . device . serial , } ) ; } } ) ; } ) ; watcher . on ( 'error' , ( e ) => { console . error ( 'iOS crash watcher error' , e ) ; } ) ; return ( ) => watcher . close ( ) ; } }