1*edeec536SEvan Baconimport spawnAsync from '@expo/spawn-async'; 2*edeec536SEvan Baconimport { type ChildProcess } from 'child_process'; 3*edeec536SEvan Baconimport open from 'open'; 4*edeec536SEvan Baconimport path from 'path'; 5*edeec536SEvan Bacon 6*edeec536SEvan Baconimport { 7*edeec536SEvan Bacon LaunchBrowserTypes, 8*edeec536SEvan Bacon type LaunchBrowserImpl, 9*edeec536SEvan Bacon type LaunchBrowserInstance, 10*edeec536SEvan Bacon} from './LaunchBrowser.types'; 11*edeec536SEvan Bacon 12*edeec536SEvan Bacon/** 13*edeec536SEvan Bacon * Browser implementation for Linux 14*edeec536SEvan Bacon */ 15*edeec536SEvan Baconexport default class LaunchBrowserImplLinux implements LaunchBrowserImpl, LaunchBrowserInstance { 16*edeec536SEvan Bacon private _appId: string | undefined; 17*edeec536SEvan Bacon private _process: ChildProcess | undefined; 18*edeec536SEvan Bacon 19*edeec536SEvan Bacon MAP = { 20*edeec536SEvan Bacon [LaunchBrowserTypes.CHROME]: ['google-chrome', 'google-chrome-stable', 'chromium'], 21*edeec536SEvan Bacon [LaunchBrowserTypes.EDGE]: ['microsoft-edge', 'microsoft-edge-dev'], 22*edeec536SEvan Bacon }; 23*edeec536SEvan Bacon 24*edeec536SEvan Bacon /** 25*edeec536SEvan Bacon * On Linux, the supported appId is an array, this function finds the available appId and caches it 26*edeec536SEvan Bacon */ 27*edeec536SEvan Bacon private async getAppId(browserType: LaunchBrowserTypes): Promise<string> { 28*edeec536SEvan Bacon if (this._appId == null || !this.MAP[browserType].includes(this._appId)) { 29*edeec536SEvan Bacon for (const appId of this.MAP[browserType]) { 30*edeec536SEvan Bacon try { 31*edeec536SEvan Bacon const { status } = await spawnAsync('which', [appId], { stdio: 'ignore' }); 32*edeec536SEvan Bacon if (status === 0) { 33*edeec536SEvan Bacon this._appId = appId; 34*edeec536SEvan Bacon break; 35*edeec536SEvan Bacon } 36*edeec536SEvan Bacon } catch {} 37*edeec536SEvan Bacon } 38*edeec536SEvan Bacon } 39*edeec536SEvan Bacon 40*edeec536SEvan Bacon if (this._appId == null) { 41*edeec536SEvan Bacon throw new Error( 42*edeec536SEvan Bacon `Unable to find supported browser - tried[${this.MAP[browserType].join(', ')}]` 43*edeec536SEvan Bacon ); 44*edeec536SEvan Bacon } 45*edeec536SEvan Bacon 46*edeec536SEvan Bacon return this._appId; 47*edeec536SEvan Bacon } 48*edeec536SEvan Bacon 49*edeec536SEvan Bacon async isSupportedBrowser(browserType: LaunchBrowserTypes): Promise<boolean> { 50*edeec536SEvan Bacon let result = false; 51*edeec536SEvan Bacon try { 52*edeec536SEvan Bacon await this.getAppId(browserType); 53*edeec536SEvan Bacon result = true; 54*edeec536SEvan Bacon } catch { 55*edeec536SEvan Bacon result = false; 56*edeec536SEvan Bacon } 57*edeec536SEvan Bacon return result; 58*edeec536SEvan Bacon } 59*edeec536SEvan Bacon 60*edeec536SEvan Bacon async createTempBrowserDir(baseDirName: string) { 61*edeec536SEvan Bacon return path.join(require('temp-dir'), baseDirName); 62*edeec536SEvan Bacon } 63*edeec536SEvan Bacon 64*edeec536SEvan Bacon async launchAsync( 65*edeec536SEvan Bacon browserType: LaunchBrowserTypes, 66*edeec536SEvan Bacon args: string[] 67*edeec536SEvan Bacon ): Promise<LaunchBrowserInstance> { 68*edeec536SEvan Bacon const appId = await this.getAppId(browserType); 69*edeec536SEvan Bacon this._process = await open.openApp(appId, { arguments: args }); 70*edeec536SEvan Bacon return this; 71*edeec536SEvan Bacon } 72*edeec536SEvan Bacon 73*edeec536SEvan Bacon async close(): Promise<void> { 74*edeec536SEvan Bacon this._process?.kill(); 75*edeec536SEvan Bacon this._process = undefined; 76*edeec536SEvan Bacon this._appId = undefined; 77*edeec536SEvan Bacon } 78*edeec536SEvan Bacon} 79