microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
c78564627d05eb04bd03fb8d3978871935d0c077

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/cdp-proxy/reactNativeCDPProxy.ts

213lines · 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 async 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 this.server = await Server.create({ port: this.port, host: this.hostAddress });
64 this.server.onConnection(this.onConnectionHandler.bind(this));
65 }
66
67 public async stopServer(): Promise<void> {
68 if (this.server) {
69 this.server.dispose();
70 this.server = null;
71 }
72
73 if (this.applicationTarget) {
74 await this.applicationTarget.close();
75 this.applicationTarget = null;
76 }
77
78 this.browserInspectUri = "";
79 this.cancellationToken = undefined;
80 }
81
82 public setBrowserInspectUri(browserInspectUri: string): void {
83 this.browserInspectUri = browserInspectUri;
84 }
85
86 public setApplicationTargetPort(applicationTargetPort: number): void {
87 this.applicationTargetPort = applicationTargetPort;
88 }
89
90 // eslint-disable-next-line @typescript-eslint/no-unused-vars
91 private async onConnectionHandler([debuggerTarget, request]: [
92 Connection,
93 IncomingMessage,
94 ]): Promise<void> {
95 this.debuggerTarget = debuggerTarget;
96
97 this.debuggerTarget.pause(); // don't listen for events until the target is ready
98
99 if (!this.browserInspectUri) {
100 if (this.cancellationToken) {
101 this.browserInspectUri = await this.debuggerEndpointHelper.retryGetWSEndpoint(
102 `http://localhost:${this.applicationTargetPort}`,
103 90,
104 this.cancellationToken,
105 );
106 } else {
107 this.browserInspectUri = await this.debuggerEndpointHelper.getWSEndpoint(
108 `http://localhost:${this.applicationTargetPort}`,
109 );
110 }
111 }
112
113 this.applicationTarget = new Connection(
114 await WebSocketTransport.create(this.browserInspectUri),
115 );
116
117 this.applicationTarget.onError(this.onApplicationTargetError.bind(this));
118 this.debuggerTarget.onError(this.onDebuggerTargetError.bind(this));
119
120 this.applicationTarget.onCommand(this.handleApplicationTargetCommand.bind(this));
121 this.debuggerTarget.onCommand(this.handleDebuggerTargetCommand.bind(this));
122
123 this.applicationTarget.onReply(this.handleApplicationTargetReply.bind(this));
124 this.debuggerTarget.onReply(this.handleDebuggerTargetReply.bind(this));
125
126 this.applicationTarget.onEnd(this.onApplicationTargetClosed.bind(this));
127 this.debuggerTarget.onEnd(this.onDebuggerTargetClosed.bind(this));
128
129 this.CDPMessageHandler?.setApplicationTarget(this.applicationTarget);
130 this.CDPMessageHandler?.setDebuggerTarget(this.debuggerTarget);
131
132 // dequeue any messages we got in the meantime
133 this.debuggerTarget.unpause();
134 }
135
136 private handleDebuggerTargetCommand(event: IProtocolCommand) {
137 this.logger.logWithCustomTag(
138 this.PROXY_LOG_TAGS.DEBUGGER_COMMAND,
139 JSON.stringify(event, null, 2),
140 this.logLevel,
141 );
142 const processedMessage = this.CDPMessageHandler.processDebuggerCDPMessage(event);
143
144 if (processedMessage.sendBack) {
145 this.debuggerTarget?.send(processedMessage.event);
146 } else {
147 this.applicationTarget?.send(processedMessage.event);
148 }
149 }
150
151 private handleApplicationTargetCommand(event: IProtocolCommand) {
152 this.logger.logWithCustomTag(
153 this.PROXY_LOG_TAGS.APPLICATION_COMMAND,
154 JSON.stringify(event, null, 2),
155 this.logLevel,
156 );
157 const processedMessage = this.CDPMessageHandler.processApplicationCDPMessage(event);
158
159 if (processedMessage.sendBack) {
160 this.applicationTarget?.send(processedMessage.event);
161 } else {
162 this.debuggerTarget?.send(processedMessage.event);
163 }
164 }
165
166 private handleDebuggerTargetReply(event: IProtocolError | IProtocolSuccess) {
167 this.logger.logWithCustomTag(
168 this.PROXY_LOG_TAGS.DEBUGGER_REPLY,
169 JSON.stringify(event, null, 2),
170 this.logLevel,
171 );
172 const processedMessage = this.CDPMessageHandler.processDebuggerCDPMessage(event);
173
174 if (processedMessage.sendBack) {
175 this.debuggerTarget?.send(processedMessage.event);
176 } else {
177 this.applicationTarget?.send(processedMessage.event);
178 }
179 }
180
181 private handleApplicationTargetReply(event: IProtocolError | IProtocolSuccess) {
182 this.logger.logWithCustomTag(
183 this.PROXY_LOG_TAGS.APPLICATION_REPLY,
184 JSON.stringify(event, null, 2),
185 this.logLevel,
186 );
187 const processedMessage = this.CDPMessageHandler.processApplicationCDPMessage(event);
188
189 if (processedMessage.sendBack) {
190 this.applicationTarget?.send(processedMessage.event);
191 } else {
192 this.debuggerTarget?.send(processedMessage.event);
193 }
194 }
195
196 private onDebuggerTargetError(err: Error) {
197 this.logger.error("Error on debugger transport", err);
198 }
199
200 private onApplicationTargetError(err: Error) {
201 this.logger.error("Error on application transport", err);
202 }
203
204 private async onApplicationTargetClosed() {
205 this.applicationTarget = null;
206 }
207
208 private async onDebuggerTargetClosed() {
209 this.browserInspectUri = "";
210 this.CDPMessageHandler.processDebuggerCDPMessage({ method: "close" });
211 this.debuggerTarget = null;
212 }
213}
214