microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.8.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/networkInspector/clientDevice.ts

269lines · modeblame

4bb0956eRedMickey5 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 { ReactiveSocket } from "rsocket-types";
5import { ClientOS } from "./clientUtils";
6import { InspectorView, InspectorViewType } from "./views/inspectorView";
7import { OutputChannelLogger } from "../log/OutputChannelLogger";
8import { InspectorViewFactory } from "./views/inspectorViewFactory";
9
10/**
11* @preserve
12* Start region: the code is borrowed from https://github.com/facebook/flipper/blob/v0.79.1/desktop/app/src/Client.tsx
13*
14* Copyright (c) Facebook, Inc. and its affiliates.
15*
16* This source code is licensed under the MIT license found in the
17* LICENSE file in the root directory of this source tree.
18*
19* @format
20*/
21
22export interface ClientIdConstituents {
23app: string;
24os: ClientOS;
25device: string;
26device_id: string;
27}
28
29export interface UninitializedClient {
30os: ClientOS;
31deviceName: string;
32appName: string;
33}
34
35export interface ClientCsrQuery {
36csr?: string;
37csr_path?: string;
38}
39
40export interface ClientQuery extends ClientIdConstituents {
41sdk_version?: number;
42}
43
44export interface SecureClientQuery extends ClientQuery, ClientCsrQuery {
45medium?: number;
46}
47
48export interface RequestParams {
49api: string;
50method: string;
51params?: Record<string, any>;
52}
53
54type RequestMetadata = { method: string; id: number; params: RequestParams | undefined };
55
56type ErrorType = { message: string; stacktrace: string; name: string };
57
58export class ClientDevice {
59private readonly networkInspectorPluginName: string;
60
61private _id: string;
62private _query: ClientQuery;
63private _connection: ReactiveSocket<any, any> | null | undefined;
64private logger: OutputChannelLogger;
65private messageIdCounter: number;
66private sdkVersion: number;
67private activePlugins: Set<string>;
68private inspectorView: InspectorView;
69
70private requestCallbacks: Map<
71number,
72{
73resolve: (data: any) => void;
74reject: (err: Error) => void;
75metadata: RequestMetadata;
76}
77>;
78
79constructor(
80id: string,
81query: ClientQuery,
82connection: ReactiveSocket<any, any> | null | undefined,
83inspectorViewType: InspectorViewType,
84logger: OutputChannelLogger,
85) {
86this.networkInspectorPluginName = "Network";
87
88this._id = id;
89this._query = query;
90this._connection = connection;
91this.logger = logger;
92this.messageIdCounter = 0;
93this.sdkVersion = query.sdk_version || 0;
94this.activePlugins = new Set();
95this.requestCallbacks = new Map();
96this.inspectorView = InspectorViewFactory.getInspectorView(inspectorViewType);
97}
98
99get id(): string {
100return this._id;
101}
102
103get query(): ClientQuery {
104return this._query;
105}
106
107get connection(): ReactiveSocket<any, any> | null | undefined {
108return this._connection;
109}
110
111public async init(): Promise<void> {
112const plugins = await this.loadPlugins();
113if (plugins.includes(this.networkInspectorPluginName)) {
114this.initNetworkInspectorPlugin();
115}
116await this.inspectorView.init();
117}
118
119public onMessage(msg: string): void {
120if (typeof msg !== "string") {
121return;
122}
123
124let rawData;
125try {
126rawData = JSON.parse(msg);
127} catch (err) {
128this.logger.error(`Invalid JSON: ${msg}`);
129return;
130}
131
132const data: {
133id?: number;
134method?: string;
135params?: RequestParams;
136success?: Record<string, any>;
137error?: ErrorType;
138} = rawData;
139
140if (!data.id) {
141const { error } = data;
142if (error) {
143this.logger.error(
144`Error received from device ${
145data.method ? `when calling ${data.method}` : ""
146}: ${error.message} + \nDevice Stack Trace: ${error.stacktrace}`,
147);
148} else if (data.method === "execute" && data.params) {
149this.inspectorView.handleMessage(data.params);
150}
151return; // method === "execute";
152}
153
154if (this.sdkVersion < 1) {
155const callbacks = this.requestCallbacks.get(data.id);
156if (!callbacks) {
157return;
158}
159this.requestCallbacks.delete(data.id);
160this.onResponse(data, callbacks.resolve, callbacks.reject);
161}
162}
163
164private initNetworkInspectorPlugin(): void {
165this.activePlugins.add(this.networkInspectorPluginName);
166this.rawSend("init", { plugin: this.networkInspectorPluginName });
167}
168
169private async loadPlugins(): Promise<string[]> {
170const plugins = await this.rawCall<{ plugins: string[] }>("getPlugins", false).then(
171data => data.plugins,
172);
173return plugins;
174}
175
176private rawSend(method: string, params?: Record<string, any>): void {
177const data = {
178method,
179params,
180};
181if (this._connection) {
182this._connection.fireAndForget({ data: JSON.stringify(data) });
183}
184}
185
186private rawCall<T>(method: string, fromPlugin: boolean, params?: RequestParams): Promise<T> {
187return new Promise((resolve, reject) => {
188const id = this.messageIdCounter++;
189const metadata: RequestMetadata = {
190method,
191id,
192params,
193};
194
195if (this.sdkVersion < 1) {
196this.requestCallbacks.set(id, { reject, resolve, metadata });
197}
198
199const data = {
200id,
201method,
202params,
203};
204
205const plugin = params ? params.api : undefined;
206
207if (this.sdkVersion < 1) {
208if (this._connection) {
209this._connection.fireAndForget({ data: JSON.stringify(data) });
210}
211return;
212}
213
214if (!fromPlugin || this.isAcceptingMessagesFromPlugin(plugin)) {
215this._connection!.requestResponse({
216data: JSON.stringify(data),
217}).subscribe({
218onComplete: payload => {
219if (!fromPlugin || this.isAcceptingMessagesFromPlugin(plugin)) {
220const response: {
221success?: Record<string, any>;
222error?: ErrorType;
223} = JSON.parse(payload.data);
224
225this.onResponse(response, resolve, reject);
226}
227},
228onError: e => {
229reject(e);
230},
231});
232} else {
233reject(
234new Error(
235`Cannot send ${method}, client is not accepting messages for plugin ${plugin}`,
236),
237);
238}
239});
240}
241
242private onResponse(
243data: {
244success?: Record<string, any>;
245error?: ErrorType;
246},
247resolve: ((a: any) => any) | undefined,
248reject: (error: ErrorType) => any,
249): void {
250if (data.success) {
251resolve && resolve(data.success);
252} else if (data.error) {
253reject(data.error);
254const { error } = data;
255if (error) {
256this.logger.debug(error.message);
257}
258}
259}
260
261private isAcceptingMessagesFromPlugin(plugin: string | null | undefined): boolean {
262return !!(this._connection && (!plugin || this.activePlugins.has(plugin)));
263}
264}
265
266/**
267* @preserve
268* End region: https://github.com/facebook/flipper/blob/v0.79.1/desktop/app/src/Client.tsx
269*/