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