microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
60ad4ec06bdc0f0e5e8c8114e1cc685f1dbc2568

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/cdp-proxy/reactNativeCDPProxy.ts

215lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import {
5 Connection,
6 Server,
7 WebSocketTransport,
8 IProtocolCommand,
9 IProtocolError,
10 IProtocolSuccess,
11} from "vscode-cdp-proxy";
12import { IncomingMessage } from "http";
13import { CancellationToken } from "vscode";
14import { OutputChannelLogger } from "../extension/log/OutputChannelLogger";
15import { LogLevel } from "../extension/log/LogHelper";
16import { DebuggerEndpointHelper } from "./debuggerEndpointHelper";
17import { BaseCDPMessageHandler } from "./CDPMessageHandlers/baseCDPMessageHandler";
18
19export class ReactNativeCDPProxy {
20 private readonly PROXY_LOG_TAGS = {
21 DEBUGGER_COMMAND: "Command Debugger To Target",
22 APPLICATION_COMMAND: "Command Target To Debugger",
23 DEBUGGER_REPLY: "Reply From Debugger To Target",
24 APPLICATION_REPLY: "Reply From Target To Debugger",
25 };
26
27 private server: Server | null;
28 private hostAddress: string;
29 private port: number;
30 private debuggerTarget: Connection | null;
31 private applicationTarget: Connection | null;
32 private logger: OutputChannelLogger;
33 private logLevel: LogLevel;
34 private debuggerEndpointHelper: DebuggerEndpointHelper;
35 private CDPMessageHandler: BaseCDPMessageHandler;
36 private applicationTargetPort: number;
37 private browserInspectUri: string;
38 private cancellationToken: CancellationToken | undefined;
39
40 constructor(hostAddress: string, port: number, logLevel: LogLevel = LogLevel.None) {
41 this.port = port;
42 this.hostAddress = hostAddress;
43 this.logger = OutputChannelLogger.getChannel(
44 "React Native Chrome Proxy",
45 process.env.REACT_NATIVE_TOOLS_LAZY_LOGS === "false" ? false : true,
46 false,
47 true,
48 );
49 this.logLevel = logLevel;
50 this.browserInspectUri = "";
51 this.debuggerEndpointHelper = new DebuggerEndpointHelper();
52 }
53
54 public initializeServer(
55 CDPMessageHandler: BaseCDPMessageHandler,
56 logLevel: LogLevel,
57 cancellationToken?: CancellationToken,
58 ): Promise<void> {
59 this.logLevel = logLevel;
60 this.CDPMessageHandler = CDPMessageHandler;
61 this.cancellationToken = cancellationToken;
62
63 return Server.create({ port: this.port, host: this.hostAddress }).then((server: Server) => {
64 this.server = server;
65 this.server.onConnection(this.onConnectionHandler.bind(this));
66 });
67 }
68
69 public async stopServer(): Promise<void> {
70 if (this.server) {
71 this.server.dispose();
72 this.server = null;
73 }
74
75 if (this.applicationTarget) {
76 await this.applicationTarget.close();
77 this.applicationTarget = null;
78 }
79
80 this.browserInspectUri = "";
81 this.cancellationToken = undefined;
82 }
83
84 public setBrowserInspectUri(browserInspectUri: string): void {
85 this.browserInspectUri = browserInspectUri;
86 }
87
88 public setApplicationTargetPort(applicationTargetPort: number): void {
89 this.applicationTargetPort = applicationTargetPort;
90 }
91
92 // eslint-disable-next-line @typescript-eslint/no-unused-vars
93 private async onConnectionHandler([debuggerTarget, request]: [
94 Connection,
95 IncomingMessage,
96 ]): Promise<void> {
97 this.debuggerTarget = debuggerTarget;
98
99 this.debuggerTarget.pause(); // don't listen for events until the target is ready
100
101 if (!this.browserInspectUri) {
102 if (this.cancellationToken) {
103 this.browserInspectUri = await this.debuggerEndpointHelper.retryGetWSEndpoint(
104 `http://localhost:${this.applicationTargetPort}`,
105 90,
106 this.cancellationToken,
107 );
108 } else {
109 this.browserInspectUri = await this.debuggerEndpointHelper.getWSEndpoint(
110 `http://localhost:${this.applicationTargetPort}`,
111 );
112 }
113 }
114
115 this.applicationTarget = new Connection(
116 await WebSocketTransport.create(this.browserInspectUri),
117 );
118
119 this.applicationTarget.onError(this.onApplicationTargetError.bind(this));
120 this.debuggerTarget.onError(this.onDebuggerTargetError.bind(this));
121
122 this.applicationTarget.onCommand(this.handleApplicationTargetCommand.bind(this));
123 this.debuggerTarget.onCommand(this.handleDebuggerTargetCommand.bind(this));
124
125 this.applicationTarget.onReply(this.handleApplicationTargetReply.bind(this));
126 this.debuggerTarget.onReply(this.handleDebuggerTargetReply.bind(this));
127
128 this.applicationTarget.onEnd(this.onApplicationTargetClosed.bind(this));
129 this.debuggerTarget.onEnd(this.onDebuggerTargetClosed.bind(this));
130
131 this.CDPMessageHandler?.setApplicationTarget(this.applicationTarget);
132 this.CDPMessageHandler?.setDebuggerTarget(this.debuggerTarget);
133
134 // dequeue any messages we got in the meantime
135 this.debuggerTarget.unpause();
136 }
137
138 private handleDebuggerTargetCommand(event: IProtocolCommand) {
139 this.logger.logWithCustomTag(
140 this.PROXY_LOG_TAGS.DEBUGGER_COMMAND,
141 JSON.stringify(event, null, 2),
142 this.logLevel,
143 );
144 const processedMessage = this.CDPMessageHandler.processDebuggerCDPMessage(event);
145
146 if (processedMessage.sendBack) {
147 this.debuggerTarget?.send(processedMessage.event);
148 } else {
149 this.applicationTarget?.send(processedMessage.event);
150 }
151 }
152
153 private handleApplicationTargetCommand(event: IProtocolCommand) {
154 this.logger.logWithCustomTag(
155 this.PROXY_LOG_TAGS.APPLICATION_COMMAND,
156 JSON.stringify(event, null, 2),
157 this.logLevel,
158 );
159 const processedMessage = this.CDPMessageHandler.processApplicationCDPMessage(event);
160
161 if (processedMessage.sendBack) {
162 this.applicationTarget?.send(processedMessage.event);
163 } else {
164 this.debuggerTarget?.send(processedMessage.event);
165 }
166 }
167
168 private handleDebuggerTargetReply(event: IProtocolError | IProtocolSuccess) {
169 this.logger.logWithCustomTag(
170 this.PROXY_LOG_TAGS.DEBUGGER_REPLY,
171 JSON.stringify(event, null, 2),
172 this.logLevel,
173 );
174 const processedMessage = this.CDPMessageHandler.processDebuggerCDPMessage(event);
175
176 if (processedMessage.sendBack) {
177 this.debuggerTarget?.send(processedMessage.event);
178 } else {
179 this.applicationTarget?.send(processedMessage.event);
180 }
181 }
182
183 private handleApplicationTargetReply(event: IProtocolError | IProtocolSuccess) {
184 this.logger.logWithCustomTag(
185 this.PROXY_LOG_TAGS.APPLICATION_REPLY,
186 JSON.stringify(event, null, 2),
187 this.logLevel,
188 );
189 const processedMessage = this.CDPMessageHandler.processApplicationCDPMessage(event);
190
191 if (processedMessage.sendBack) {
192 this.applicationTarget?.send(processedMessage.event);
193 } else {
194 this.debuggerTarget?.send(processedMessage.event);
195 }
196 }
197
198 private onDebuggerTargetError(err: Error) {
199 this.logger.error("Error on debugger transport", err);
200 }
201
202 private onApplicationTargetError(err: Error) {
203 this.logger.error("Error on application transport", err);
204 }
205
206 private async onApplicationTargetClosed() {
207 this.applicationTarget = null;
208 }
209
210 private async onDebuggerTargetClosed() {
211 this.browserInspectUri = "";
212 this.CDPMessageHandler.processDebuggerCDPMessage({ method: "close" });
213 this.debuggerTarget = null;
214 }
215}
216