apps/vs-code-designer/src/app/commands/pickCustomCodeNetHostProcess.ts (104 lines of code) (raw):

/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { Platform } from '../../constants'; import { getMatchingWorkspaceFolder } from '../debug/validatePreDebug'; import { runningFuncTaskMap } from '../utils/funcCoreTools/funcHostTask'; import type { IRunningFuncTask } from '../utils/funcCoreTools/funcHostTask'; import type { IActionContext } from '@microsoft/vscode-azext-utils'; import type * as vscode from 'vscode'; import * as path from 'path'; import { getUnixChildren, getWindowsChildren, pickChildProcess } from './pickFuncProcess'; import { localize } from '../../localize'; import { tryGetLogicAppProjectRoot } from '../utils/verifyIsProject'; type OSAgnosticProcess = { command: string | undefined; pid: number | string }; /** * Picks the .NET host child process for the custom code project by polling the running function tasks for the workspace folder. * @param context The action context. * @param debugConfig The debug configuration. * @returns A promise that resolves to the .NET host child process ID or undefined if not found. */ export async function pickCustomCodeNetHostProcess( context: IActionContext, debugConfig: vscode.DebugConfiguration ): Promise<string | undefined> { context.telemetry.properties.lastStep = 'getMatchingWorkspaceFolder'; const workspaceFolder: vscode.WorkspaceFolder = getMatchingWorkspaceFolder(debugConfig); if (!workspaceFolder) { const errorMessage = 'Failed to find a workspace folder matching the debug configuration.'; context.telemetry.properties.result = 'Failed'; context.telemetry.properties.error = errorMessage; throw new Error(localize('noMatchingWorkspaceFolder', errorMessage)); } context.telemetry.properties.lastStep = 'tryGetLogicAppProjectRoot'; const projectPath: string | undefined = await tryGetLogicAppProjectRoot(context, workspaceFolder); if (!projectPath) { const errorMessage = 'Failed to find a logic app project in the workspace folder "{0}".'; context.telemetry.properties.result = 'Failed'; context.telemetry.properties.error = errorMessage.replace('{0}', workspaceFolder?.uri?.fsPath); throw new Error(localize('noLogicAppProject', errorMessage, workspaceFolder?.uri?.fsPath)); } const logicAppName = path.basename(projectPath); context.telemetry.properties.lastStep = 'getRunningFuncTask'; let taskInfo: IRunningFuncTask | undefined; const maxRetries = 10; const delayMs = 5000; for (let i = 0; i < maxRetries; i++) { taskInfo = runningFuncTaskMap.get(workspaceFolder); if (taskInfo) { break; } await new Promise((resolve) => setTimeout(resolve, delayMs)); } if (!taskInfo) { const errorMessage = 'Failed to find a running func task for the logic app "{0}". The logic app must be running to attach the function debugger.'; context.telemetry.properties.result = 'Failed'; context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); throw new Error(localize('noFuncTask', errorMessage, logicAppName)); } context.telemetry.properties.lastStep = 'pickNetHostChildProcess'; let customCodeNetHostProcess: string | undefined; for (let i = 0; i < maxRetries; i++) { customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo); if (customCodeNetHostProcess) { break; } await new Promise((resolve) => setTimeout(resolve, delayMs)); } if (!customCodeNetHostProcess) { const errorMessage = 'Failed to find the .NET host child process for the functions project for logic app "{0}".'; context.telemetry.properties.result = 'Failed'; context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); throw new Error(localize('netHostProcessNotFound', errorMessage, logicAppName)); } context.telemetry.properties.result = 'Succeeded'; return customCodeNetHostProcess; } /** * Picks the .NET host child process of the running function task for the custom code project. * @param context The action context. * @param workspaceFolder The workspace folder containing the logic app. * @param projectPath The path to the logic app project root. * @returns A promise that resolves to the .NET host child process ID or undefined if not found. */ export async function pickCustomCodeNetHostProcessInternal( context: IActionContext, workspaceFolder: vscode.WorkspaceFolder, projectPath: string ): Promise<string | undefined> { const logicAppName = path.basename(projectPath); context.telemetry.properties.lastStep = 'getRunningFuncTask'; const taskInfo = runningFuncTaskMap.get(workspaceFolder); if (!taskInfo) { const errorMessage = 'Failed to find a running func task for the logic app "{0}". The logic app must be running to attach the function debugger.'; context.telemetry.properties.result = 'Failed'; context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); throw new Error(localize('noFuncTask', errorMessage, logicAppName)); } context.telemetry.properties.lastStep = 'pickNetHostChildProcess'; const customCodeNetHostProcess = await pickNetHostChildProcess(taskInfo); if (!customCodeNetHostProcess) { const errorMessage = 'Failed to find the .NET host child process for the functions project for logic app "{0}".'; context.telemetry.properties.result = 'Failed'; context.telemetry.properties.error = errorMessage.replace('{0}', logicAppName); throw new Error(localize('netHostProcessNotFound', errorMessage, logicAppName)); } context.telemetry.properties.result = 'Succeeded'; return customCodeNetHostProcess; } async function pickNetHostChildProcess(taskInfo: IRunningFuncTask): Promise<string | undefined> { const funcPid = Number(await pickChildProcess(taskInfo)); if (!funcPid) { return undefined; } const children: OSAgnosticProcess[] = process.platform === Platform.windows ? await getWindowsChildren(funcPid) : await getUnixChildren(funcPid); const child: OSAgnosticProcess | undefined = children.reverse().find((c) => /(dotnet)(\.exe|)$/i.test(c.command || '')); return child ? child.pid.toString() : undefined; }