microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
b7451aef6bd5846d7333cd23872aaadd1d57136c

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/debugger/rnDebugSession.ts

234lines · 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";
2c19da7fRedMickey6 years ago13import { DebugSessionBase, DebugSessionStatus, IAttachRequestArgs, ILaunchRequestArgs } from "./debugSessionBase";
6e1bcd36RedMickey6 years ago14import * as nls from "vscode-nls";
15const localize = nls.loadMessageBundle();
16
2c19da7fRedMickey6 years ago17export class RNDebugSession extends DebugSessionBase {
6e1bcd36RedMickey6 years ago18
4c757eebRedMickey6 years ago19private readonly terminateCommand: string;
20private readonly pwaNodeSessionName: string;
f872f4d5RedMickey6 years ago21
4c757eebRedMickey6 years ago22private nodeSession: vscode.DebugSession | null;
6e491635RedMickey6 years ago23private onDidStartDebugSessionHandler: vscode.Disposable;
24private onDidTerminateDebugSessionHandler: vscode.Disposable;
6e1bcd36RedMickey6 years ago25
2c19da7fRedMickey6 years ago26constructor(session: vscode.DebugSession) {
27super(session);
4c757eebRedMickey6 years ago28
29// constants definition
30this.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
31this.pwaNodeSessionName = "pwa-node"; // the name of node debug session created by js-debug extension
32
33// variables definition
6e491635RedMickey6 years ago34this.onDidStartDebugSessionHandler = vscode.debug.onDidStartDebugSession(
4c757eebRedMickey6 years ago35this.handleStartDebugSession.bind(this)
36);
37
6e491635RedMickey6 years ago38this.onDidTerminateDebugSessionHandler = vscode.debug.onDidTerminateDebugSession(
4c757eebRedMickey6 years ago39this.handleTerminateDebugSession.bind(this)
40);
6e1bcd36RedMickey6 years ago41}
42
43protected launchRequest(response: DebugProtocol.LaunchResponse, launchArgs: ILaunchRequestArgs, request?: DebugProtocol.Request): Promise<void> {
44return new Promise<void>((resolve, reject) => this.initializeSettings(launchArgs)
45.then(() => {
46logger.log("Launching the application");
47logger.verbose(`Launching the application: ${JSON.stringify(launchArgs, null , 2)}`);
48
49this.appLauncher.launch(launchArgs)
50.then(() => {
51return this.appLauncher.getPackagerPort(launchArgs.cwd);
52})
53.then((packagerPort: number) => {
54launchArgs.port = launchArgs.port || packagerPort;
55this.attachRequest(response, launchArgs).then(() => {
56resolve();
57}).catch((e) => reject(e));
58})
59.catch((err) => {
2c19da7fRedMickey6 years ago60logger.error("An error occurred while launching the application. " + err.message || err);
6e1bcd36RedMickey6 years ago61reject(err);
62});
63}));
64}
65
66protected attachRequest(response: DebugProtocol.AttachResponse, attachArgs: IAttachRequestArgs, request?: DebugProtocol.Request): Promise<void> {
67let extProps = {
68platform: {
69value: attachArgs.platform,
70isPii: false,
71},
72};
73
74this.previousAttachArgs = attachArgs;
75return new Promise<void>((resolve, reject) => this.initializeSettings(attachArgs)
76.then(() => {
77logger.log("Attaching to the application");
78logger.verbose(`Attaching to the application: ${JSON.stringify(attachArgs, null , 2)}`);
79return ProjectVersionHelper.getReactNativeVersions(attachArgs.cwd, true)
80.then(versions => {
81extProps = TelemetryHelper.addPropertyToTelemetryProperties(versions.reactNativeVersion, "reactNativeVersion", extProps);
82if (!ProjectVersionHelper.isVersionError(versions.reactNativeWindowsVersion)) {
83extProps = TelemetryHelper.addPropertyToTelemetryProperties(versions.reactNativeWindowsVersion, "reactNativeWindowsVersion", extProps);
84}
85return TelemetryHelper.generate("attach", extProps, (generator) => {
a324603aRedMickey6 years ago86attachArgs.port = attachArgs.port || this.appLauncher.getPackagerPort(attachArgs.cwd);
a6562589RedMickey6 years ago87this.appLauncher.getRnCdpProxy().stopServer();
88return this.appLauncher.getRnCdpProxy().initializeServer(new RnCDPMessageHandler(), this.cdpProxyLogLevel)
f872f4d5RedMickey6 years ago89.then(() => {
90logger.log(localize("StartingDebuggerAppWorker", "Starting debugger app worker."));
91
92const sourcesStoragePath = path.join(this.projectRootPath, ".vscode", ".react");
93// Create folder if not exist to avoid problems if
94// RN project root is not a ${workspaceFolder}
95mkdirp.sync(sourcesStoragePath);
96
97// If launch is invoked first time, appWorker is undefined, so create it here
98this.appWorker = new MultipleLifetimesAppWorker(
99attachArgs,
100sourcesStoragePath,
101this.projectRootPath,
a324603aRedMickey6 years ago102undefined
103);
7e74daf7Yuri Skorokhodov6 years ago104this.appLauncher.setAppWorker(this.appWorker);
f872f4d5RedMickey6 years ago105
106this.appWorker.on("connected", (port: number) => {
107logger.log(localize("DebuggerWorkerLoadedRuntimeOnPort", "Debugger worker loaded runtime on port {0}", port));
108
a6562589RedMickey6 years ago109this.appLauncher.getRnCdpProxy().setApplicationTargetPort(port);
4c757eebRedMickey6 years ago110
111if (this.debugSessionStatus === DebugSessionStatus.ConnectionPending) {
112return;
113}
d9c9ddcbRedMickey6 years ago114
4c757eebRedMickey6 years ago115if (this.debugSessionStatus === DebugSessionStatus.FirstConnection) {
116this.debugSessionStatus = DebugSessionStatus.FirstConnectionPending;
117this.establishDebugSession(resolve);
118} else if (this.debugSessionStatus === DebugSessionStatus.ConnectionAllowed) {
119if (this.nodeSession) {
120this.debugSessionStatus = DebugSessionStatus.ConnectionPending;
121this.nodeSession.customRequest(this.terminateCommand);
122}
f872f4d5RedMickey6 years ago123}
124});
125return this.appWorker.start();
6e1bcd36RedMickey6 years ago126});
127})
128.catch((err) => {
129logger.error("An error occurred while attaching to the debugger. " + err.message || err);
130reject(err);
131});
132});
133}));
134}
135
136protected disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments, request?: DebugProtocol.Request): void {
137// The client is about to disconnect so first we need to stop app worker
138if (this.appWorker) {
139this.appWorker.stop();
140}
141
a6562589RedMickey6 years ago142this.appLauncher.getRnCdpProxy().stopServer();
f872f4d5RedMickey6 years ago143
6e491635RedMickey6 years ago144this.onDidStartDebugSessionHandler.dispose();
145this.onDidTerminateDebugSessionHandler.dispose();
146
6e1bcd36RedMickey6 years ago147// Then we tell the extension to stop monitoring the logcat, and then we disconnect the debugging session
148if (this.previousAttachArgs.platform === "android") {
149try {
150this.appLauncher.stopMonitoringLogCat();
151} catch (err) {
152logger.warn(localize("CouldNotStopMonitoringLogcat", "Couldn't stop monitoring logcat: {0}", err.message || err));
153}
154}
155
156super.disconnectRequest(response, args, request);
4c757eebRedMickey6 years ago157}
158
b7451aefRedMickey6 years ago159protected establishDebugSession(resolve?: (value?: void | PromiseLike<void> | undefined) => void): void {
a6562589RedMickey6 years ago160const attachArguments = {
161type: "pwa-node",
162request: "attach",
163name: "Attach",
164continueOnAttach: true,
165port: this.appLauncher.getCdpProxyPort(),
166smartStep: false,
167// The unique identifier of the debug session. It is used to distinguish React Native extension's
168// debug sessions from other ones. So we can save and process only the extension's debug sessions
169// in vscode.debug API methods "onDidStartDebugSession" and "onDidTerminateDebugSession".
170rnDebugSessionId: this.session.id,
171};
172
173vscode.debug.startDebugging(
174this.appLauncher.getWorkspaceFolder(),
175attachArguments,
176this.session
177)
178.then((childDebugSessionStarted: boolean) => {
179if (childDebugSessionStarted) {
180this.debugSessionStatus = DebugSessionStatus.ConnectionDone;
181this.setConnectionAllowedIfPossible();
182if (resolve) {
183this.debugSessionStatus = DebugSessionStatus.ConnectionAllowed;
184resolve();
4c757eebRedMickey6 years ago185}
a6562589RedMickey6 years ago186} else {
4c757eebRedMickey6 years ago187this.debugSessionStatus = DebugSessionStatus.ConnectionFailed;
188this.setConnectionAllowedIfPossible();
189this.resetFirstConnectionStatus();
a6562589RedMickey6 years ago190throw new Error("Cannot start child debug session");
191}
192},
193err => {
194this.debugSessionStatus = DebugSessionStatus.ConnectionFailed;
195this.setConnectionAllowedIfPossible();
4c757eebRedMickey6 years ago196this.resetFirstConnectionStatus();
a6562589RedMickey6 years ago197throw err;
198});
4c757eebRedMickey6 years ago199}
6e1bcd36RedMickey6 years ago200
4c757eebRedMickey6 years ago201private handleStartDebugSession(debugSession: vscode.DebugSession) {
202if (
203debugSession.configuration.rnDebugSessionId === this.session.id
204&& debugSession.type === this.pwaNodeSessionName
205) {
206this.nodeSession = debugSession;
207}
208}
209
210private handleTerminateDebugSession(debugSession: vscode.DebugSession) {
211if (
212debugSession.configuration.rnDebugSessionId === this.session.id
2c19da7fRedMickey6 years ago213&& this.debugSessionStatus === DebugSessionStatus.ConnectionPending
4c757eebRedMickey6 years ago214&& debugSession.type === this.pwaNodeSessionName
215) {
2c19da7fRedMickey6 years ago216this.establishDebugSession();
4c757eebRedMickey6 years ago217}
218}
219
220private setConnectionAllowedIfPossible(): void {
221if (
222this.debugSessionStatus === DebugSessionStatus.ConnectionDone
223|| this.debugSessionStatus === DebugSessionStatus.ConnectionFailed
224) {
225this.debugSessionStatus = DebugSessionStatus.ConnectionAllowed;
226}
227}
228
229private resetFirstConnectionStatus(): void {
230if (this.debugSessionStatus === DebugSessionStatus.FirstConnectionPending) {
231this.debugSessionStatus = DebugSessionStatus.FirstConnection;
232}
233}
6e1bcd36RedMickey6 years ago234}