microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
e7a2c40d1102db28f3c062f2c66fc12d706ec850

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/debugger/rnDebugSession.ts

297lines · modeblame

6e1bcd36RedMickey6 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as vscode from "vscode";
5import * as path from "path";
6import * as mkdirp from "mkdirp";
2c19da7fRedMickey6 years ago7import { logger } from "vscode-debugadapter";
6e1bcd36RedMickey6 years ago8import { DebugProtocol } from "vscode-debugprotocol";
9import { ProjectVersionHelper } from "../common/projectVersionHelper";
10import { TelemetryHelper } from "../common/telemetryHelper";
11import { MultipleLifetimesAppWorker } from "./appWorker";
a6562589RedMickey6 years ago12import { RnCDPMessageHandler } from "../cdp-proxy/CDPMessageHandlers/rnCDPMessageHandler";
34472878RedMickey5 years ago13import {
14DebugSessionBase,
15DebugSessionStatus,
16IAttachRequestArgs,
17ILaunchRequestArgs,
18} from "./debugSessionBase";
1bdccb66RedMickey6 years ago19import { JsDebugConfigAdapter } from "./jsDebugConfigAdapter";
5514e287RedMickey6 years ago20import { ErrorHelper } from "../common/error/errorHelper";
21import { InternalErrorCode } from "../common/error/internalErrorCode";
6e1bcd36RedMickey6 years ago22import * as nls from "vscode-nls";
34472878RedMickey5 years ago23nls.config({
24messageFormat: nls.MessageFormat.bundle,
25bundleFormat: nls.BundleFormat.standalone,
26})();
6e1bcd36RedMickey6 years ago27const localize = nls.loadMessageBundle();
28
2c19da7fRedMickey6 years ago29export class RNDebugSession extends DebugSessionBase {
4c757eebRedMickey6 years ago30private readonly terminateCommand: string;
f872f4d5RedMickey6 years ago31
e23d1841RedMickey6 years ago32private appWorker: MultipleLifetimesAppWorker | null;
4c757eebRedMickey6 years ago33private nodeSession: vscode.DebugSession | null;
6e491635RedMickey6 years ago34private onDidStartDebugSessionHandler: vscode.Disposable;
35private onDidTerminateDebugSessionHandler: vscode.Disposable;
6e1bcd36RedMickey6 years ago36
2c19da7fRedMickey6 years ago37constructor(session: vscode.DebugSession) {
38super(session);
4c757eebRedMickey6 years ago39
40// constants definition
41this.terminateCommand = "terminate"; // the "terminate" command is sent from the client to the debug adapter in order to give the debuggee a chance for terminating itself
42
43// variables definition
e23d1841RedMickey6 years ago44this.appWorker = null;
45
6e491635RedMickey6 years ago46this.onDidStartDebugSessionHandler = vscode.debug.onDidStartDebugSession(
34472878RedMickey5 years ago47this.handleStartDebugSession.bind(this),
4c757eebRedMickey6 years ago48);
49
6e491635RedMickey6 years ago50this.onDidTerminateDebugSessionHandler = vscode.debug.onDidTerminateDebugSession(
34472878RedMickey5 years ago51this.handleTerminateDebugSession.bind(this),
4c757eebRedMickey6 years ago52);
6e1bcd36RedMickey6 years ago53}
54
34472878RedMickey5 years ago55protected async launchRequest(
56response: DebugProtocol.LaunchResponse,
57launchArgs: ILaunchRequestArgs,
58// eslint-disable-next-line @typescript-eslint/no-unused-vars
59request?: DebugProtocol.Request,
60): Promise<void> {
0d77292aJiglioNero4 years ago61try {
62try {
63await this.initializeSettings(launchArgs);
64logger.log("Launching the application");
65logger.verbose(`Launching the application: ${JSON.stringify(launchArgs, null, 2)}`);
34472878RedMickey5 years ago66
0d77292aJiglioNero4 years ago67await this.appLauncher.launch(launchArgs);
68
69if (!launchArgs.enableDebug) {
70this.sendResponse(response);
71// if debugging is not enabled skip attach request
72return;
73}
74} catch (error) {
75throw ErrorHelper.getInternalError(
76InternalErrorCode.ApplicationLaunchFailed,
77error.message || error,
78);
79}
80// if debugging is enabled start attach request
81await this.attachRequest(response, launchArgs);
82} catch (error) {
83this.showError(error, response);
84}
6e1bcd36RedMickey6 years ago85}
86
34472878RedMickey5 years ago87protected async attachRequest(
88response: DebugProtocol.AttachResponse,
89attachArgs: IAttachRequestArgs,
90// eslint-disable-next-line @typescript-eslint/no-unused-vars
91request?: DebugProtocol.Request,
92): Promise<void> {
6e1bcd36RedMickey6 years ago93let extProps = {
94platform: {
95value: attachArgs.platform,
96isPii: false,
97},
98};
99
100this.previousAttachArgs = attachArgs;
0d77292aJiglioNero4 years ago101
102return new Promise<void>(async (resolve, reject) => {
103try {
104await this.initializeSettings(attachArgs);
105logger.log("Attaching to the application");
106logger.verbose(
107`Attaching to the application: ${JSON.stringify(attachArgs, null, 2)}`,
108);
109
110const versions = await ProjectVersionHelper.getReactNativeVersions(
111this.projectRootPath,
112ProjectVersionHelper.generateAdditionalPackagesToCheckByPlatform(attachArgs),
113);
114extProps = TelemetryHelper.addPlatformPropertiesToTelemetryProperties(
115attachArgs,
116versions,
117extProps,
118);
119
120// eslint-disable-next-line @typescript-eslint/no-unused-vars
121await TelemetryHelper.generate("attach", extProps, async generator => {
122attachArgs.port =
123attachArgs.port || this.appLauncher.getPackagerPort(attachArgs.cwd);
124
125const cdpProxy = this.appLauncher.getRnCdpProxy();
126await cdpProxy.stopServer();
127await cdpProxy.initializeServer(
128new RnCDPMessageHandler(),
129this.cdpProxyLogLevel,
dcabd9c8RedMickey4 years ago130this.cancellationTokenSource.token,
34472878RedMickey5 years ago131);
0d77292aJiglioNero4 years ago132
133await this.appLauncher.getPackager().start();
134
135logger.log(
136localize("StartingDebuggerAppWorker", "Starting debugger app worker."),
34472878RedMickey5 years ago137);
0d77292aJiglioNero4 years ago138
139const sourcesStoragePath = path.join(this.projectRootPath, ".vscode", ".react");
140// Create folder if not exist to avoid problems if
141// RN project root is not a ${workspaceFolder}
142mkdirp.sync(sourcesStoragePath);
143
144// If launch is invoked first time, appWorker is undefined, so create it here
145this.appWorker = new MultipleLifetimesAppWorker(
34472878RedMickey5 years ago146attachArgs,
0d77292aJiglioNero4 years ago147sourcesStoragePath,
148this.projectRootPath,
149this.cancellationTokenSource.token,
150undefined,
34472878RedMickey5 years ago151);
0d77292aJiglioNero4 years ago152this.appLauncher.setAppWorker(this.appWorker);
153
154this.appWorker.on("connected", (port: number) => {
155if (this.cancellationTokenSource.token.isCancellationRequested) {
156return this.appWorker?.stop();
157}
158
159logger.log(
160localize(
161"DebuggerWorkerLoadedRuntimeOnPort",
162"Debugger worker loaded runtime on port {0}",
163port,
164),
165);
166
167cdpProxy.setApplicationTargetPort(port);
168
169if (this.debugSessionStatus === DebugSessionStatus.ConnectionPending) {
170return;
171}
34472878RedMickey5 years ago172
0d77292aJiglioNero4 years ago173if (this.debugSessionStatus === DebugSessionStatus.FirstConnection) {
174this.debugSessionStatus = DebugSessionStatus.FirstConnectionPending;
175this.establishDebugSession(attachArgs, resolve);
176} else if (
177this.debugSessionStatus === DebugSessionStatus.ConnectionAllowed
178) {
179if (this.nodeSession) {
180this.debugSessionStatus = DebugSessionStatus.ConnectionPending;
181this.nodeSession.customRequest(this.terminateCommand);
182}
183}
34472878RedMickey5 years ago184});
0d77292aJiglioNero4 years ago185
186if (this.cancellationTokenSource.token.isCancellationRequested) {
187return this.appWorker.stop();
188}
189return await this.appWorker.start();
190});
191} catch (error) {
192reject(error);
193}
194}).catch(err =>
195this.showError(
196ErrorHelper.getInternalError(
197InternalErrorCode.CouldNotAttachToDebugger,
198err.message || err,
199),
200response,
201),
202);
6e1bcd36RedMickey6 years ago203}
204
34472878RedMickey5 years ago205protected async disconnectRequest(
206response: DebugProtocol.DisconnectResponse,
207args: DebugProtocol.DisconnectArguments,
208request?: DebugProtocol.Request,
209): Promise<void> {
6e1bcd36RedMickey6 years ago210// The client is about to disconnect so first we need to stop app worker
211if (this.appWorker) {
212this.appWorker.stop();
213}
214
6e491635RedMickey6 years ago215this.onDidStartDebugSessionHandler.dispose();
216this.onDidTerminateDebugSessionHandler.dispose();
217
0d77292aJiglioNero4 years ago218return super.disconnectRequest(response, args, request);
4c757eebRedMickey6 years ago219}
220
34472878RedMickey5 years ago221protected establishDebugSession(
222attachArgs: IAttachRequestArgs,
223resolve?: (value?: void | PromiseLike<void> | undefined) => void,
224): void {
1bdccb66RedMickey6 years ago225const attachConfiguration = JsDebugConfigAdapter.createDebuggingConfigForPureRN(
226attachArgs,
227this.appLauncher.getCdpProxyPort(),
34472878RedMickey5 years ago228this.session.id,
1bdccb66RedMickey6 years ago229);
a6562589RedMickey6 years ago230
34472878RedMickey5 years ago231vscode.debug
232.startDebugging(this.appLauncher.getWorkspaceFolder(), attachConfiguration, {
ebbd64f1RedMickey6 years ago233parentSession: this.session,
234consoleMode: vscode.DebugConsoleMode.MergeWithParent,
34472878RedMickey5 years ago235})
236.then(
237(childDebugSessionStarted: boolean) => {
238if (childDebugSessionStarted) {
239this.debugSessionStatus = DebugSessionStatus.ConnectionDone;
240this.setConnectionAllowedIfPossible();
241if (resolve) {
242this.debugSessionStatus = DebugSessionStatus.ConnectionAllowed;
243resolve();
244}
245} else {
246this.debugSessionStatus = DebugSessionStatus.ConnectionFailed;
247this.setConnectionAllowedIfPossible();
248this.resetFirstConnectionStatus();
249throw new Error("Cannot start child debug session");
250}
251},
252err => {
253this.debugSessionStatus = DebugSessionStatus.ConnectionFailed;
254this.setConnectionAllowedIfPossible();
255this.resetFirstConnectionStatus();
256throw err;
257},
258);
4c757eebRedMickey6 years ago259}
6e1bcd36RedMickey6 years ago260
0d77292aJiglioNero4 years ago261private handleStartDebugSession(debugSession: vscode.DebugSession): void {
4c757eebRedMickey6 years ago262if (
34472878RedMickey5 years ago263debugSession.configuration.rnDebugSessionId === this.session.id &&
264debugSession.type === this.pwaNodeSessionName
4c757eebRedMickey6 years ago265) {
266this.nodeSession = debugSession;
267}
268}
269
0d77292aJiglioNero4 years ago270private handleTerminateDebugSession(debugSession: vscode.DebugSession): void {
4c757eebRedMickey6 years ago271if (
34472878RedMickey5 years ago272debugSession.configuration.rnDebugSessionId === this.session.id &&
273debugSession.type === this.pwaNodeSessionName
4c757eebRedMickey6 years ago274) {
ebbd64f1RedMickey6 years ago275if (this.debugSessionStatus === DebugSessionStatus.ConnectionPending) {
5d47053fRedMickey6 years ago276this.establishDebugSession(this.previousAttachArgs);
ebbd64f1RedMickey6 years ago277} else {
a2ddbba5RedMickey5 years ago278vscode.commands.executeCommand(this.stopCommand, this.session);
ebbd64f1RedMickey6 years ago279}
4c757eebRedMickey6 years ago280}
281}
282
283private setConnectionAllowedIfPossible(): void {
284if (
34472878RedMickey5 years ago285this.debugSessionStatus === DebugSessionStatus.ConnectionDone ||
286this.debugSessionStatus === DebugSessionStatus.ConnectionFailed
4c757eebRedMickey6 years ago287) {
288this.debugSessionStatus = DebugSessionStatus.ConnectionAllowed;
289}
290}
291
292private resetFirstConnectionStatus(): void {
293if (this.debugSessionStatus === DebugSessionStatus.FirstConnectionPending) {
294this.debugSessionStatus = DebugSessionStatus.FirstConnection;
295}
296}
6e1bcd36RedMickey6 years ago297}