// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. import * as cp from "child_process"; import { PromiseUtil } from "../../common/node/promise"; import { Request } from "../../common/node/request"; import { IAttachRequestArgs } from "../debugSessionBase"; import { ErrorHelper } from "../../common/error/errorHelper"; import { InternalErrorCode } from "../../common/error/internalErrorCode"; /** * Helper class to control [ios-webkit-debug-proxy](https://github.com/google/ios-webkit-debug-proxy) */ export class IWDPHelper { private iOSWebkitDebugProxyProcess: cp.ChildProcess | null; public static readonly iOS_WEBKIT_DEBUG_PROXY_DEFAULT_PORT: number = 9221; constructor() { this.iOSWebkitDebugProxyProcess = null; } public async startiOSWebkitDebugProxy( proxyPort: number, proxyRangeStart: number, proxyRangeEnd: number, ): Promise { return new Promise((resolve, reject) => { this.cleanUp(); const portRange = `null:${proxyPort},:${proxyRangeStart}-${proxyRangeEnd}`; this.iOSWebkitDebugProxyProcess = cp.spawn( "ios_webkit_debug_proxy", ["-c", portRange], { shell: true }, ); this.iOSWebkitDebugProxyProcess.on("error", err => { reject(new Error(`Unable to start ios_webkit_debug_proxy: ${String(err)}`)); }); // Allow some time for the spawned process to error out void PromiseUtil.delay(250).then(() => resolve()); }); } public async getSimulatorProxyPort( attachArgs: IAttachRequestArgs, ): Promise<{ targetPort: number; iOSVersion: string }> { const response = await Request.request(`http://localhost:${attachArgs.port}/json`, true); try { // An example of a json response from IWDP // [{ // "deviceId": "00008020-XXXXXXXXXXXXXXXX", // "deviceName": "iPhone name", // "deviceOSVersion": "13.4.1", // "url": "localhost:9223" // }] const endpointsList = JSON.parse(response); let devices = endpointsList; if (attachArgs.target) { devices = endpointsList.filter((entry: { deviceId: string }) => attachArgs.target?.toLowerCase() === "device" ? entry.deviceId !== "SIMULATOR" : entry.deviceId === "SIMULATOR", ); } const device = devices[0]; // device.url is of the form 'localhost:port' return { targetPort: parseInt(device.url.split(":")[1], 10), iOSVersion: device.deviceOSVersion, }; } catch (e) { throw ErrorHelper.getInternalError( InternalErrorCode.IOSCouldNotFoundDeviceForDirectDebugging, ); } } public cleanUp(): void { if (this.iOSWebkitDebugProxyProcess) { this.iOSWebkitDebugProxyProcess.kill(); this.iOSWebkitDebugProxyProcess = null; } } }