microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
df4bce4041caa61af1460ef87f2380820508a455

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/extensionServer.ts

199lines · 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 * as net from "net";
5import * as Q from "q";
6import * as vscode from "vscode";
7
8import * as em from "../common/extensionMessaging";
9import {HostPlatform} from "../common/hostPlatform";
10import {Log} from "../common/log/log";
11import {LogLevel} from "../common/log/logHelper";
12import {Packager} from "../common/packager";
13import {PackagerStatus, PackagerStatusIndicator} from "./packagerStatusIndicator";
14import {LogCatMonitor} from "./android/logCatMonitor";
15import {FileSystem} from "../common/node/fileSystem";
16import {ConfigurationReader} from "../common/configurationReader";
17
18import {SettingsHelper} from "./settingsHelper";
19
20export class ExtensionServer implements vscode.Disposable {
21 private serverInstance: net.Server = null;
22 private messageHandlerDictionary: { [id: number]: ((...argArray: any[]) => Q.Promise<any>) } = {};
23 private reactNativePackager: Packager;
24 private reactNativePackageStatusIndicator: PackagerStatusIndicator;
25 private pipePath: string;
26 private logCatMonitor: LogCatMonitor = null;
27
28 public constructor(reactNativePackager: Packager, packagerStatusIndicator: PackagerStatusIndicator) {
29
30 this.pipePath = HostPlatform.getExtensionPipePath();
31 this.reactNativePackager = reactNativePackager;
32 this.reactNativePackageStatusIndicator = packagerStatusIndicator;
33
34 /* register handlers for all messages */
35 this.messageHandlerDictionary[em.ExtensionMessage.START_PACKAGER] = this.startPackager;
36 this.messageHandlerDictionary[em.ExtensionMessage.STOP_PACKAGER] = this.stopPackager;
37 this.messageHandlerDictionary[em.ExtensionMessage.PREWARM_BUNDLE_CACHE] = this.prewarmBundleCache;
38 this.messageHandlerDictionary[em.ExtensionMessage.START_MONITORING_LOGCAT] = this.startMonitoringLogCat;
39 this.messageHandlerDictionary[em.ExtensionMessage.STOP_MONITORING_LOGCAT] = this.stopMonitoringLogCat;
40 this.messageHandlerDictionary[em.ExtensionMessage.GET_PACKAGER_PORT] = this.getPackagerPort;
41 }
42
43 /**
44 * Starts the server.
45 */
46 public setup(): Q.Promise<void> {
47
48 let deferred = Q.defer<void>();
49
50 let launchCallback = (error: any) => {
51 Log.logInternalMessage(LogLevel.Info, "Extension messaging server started.");
52 if (error) {
53 deferred.reject(error);
54 } else {
55 deferred.resolve(null);
56 }
57 };
58
59 this.serverInstance = net.createServer(this.handleSocket.bind(this));
60 this.serverInstance.on("error", this.recoverServer.bind(this));
61 this.serverInstance.listen(this.pipePath, launchCallback);
62
63 return deferred.promise;
64 }
65
66 /**
67 * Stops the server.
68 */
69 public dispose(): void {
70 if (this.serverInstance) {
71 this.serverInstance.close();
72 this.serverInstance = null;
73 }
74
75 this.stopMonitoringLogCat();
76 }
77
78 /**
79 * Message handler for GET_PACKAGER_PORT.
80 */
81 private getPackagerPort(): Q.Promise<number> {
82 return Q(SettingsHelper.getPackagerPort());
83 }
84
85 /**
86 * Message handler for START_PACKAGER.
87 */
88 private startPackager(port?: any): Q.Promise<any> {
89 const portToUse = ConfigurationReader.readIntWithDefaultSync(port, SettingsHelper.getPackagerPort());
90 return this.reactNativePackager.start(portToUse)
91 .then(() =>
92 this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STARTED));
93 }
94
95 /**
96 * Message handler for STOP_PACKAGER.
97 */
98 private stopPackager(): Q.Promise<any> {
99 return this.reactNativePackager.stop()
100 .then(() => this.reactNativePackageStatusIndicator.updatePackagerStatus(PackagerStatus.PACKAGER_STOPPED));
101 }
102
103 /**
104 * Message handler for PREWARM_BUNDLE_CACHE.
105 */
106 private prewarmBundleCache(platform: string): Q.Promise<any> {
107 return this.reactNativePackager.prewarmBundleCache(platform);
108 }
109
110 /**
111 * Message handler for START_MONITORING_LOGCAT.
112 */
113 private startMonitoringLogCat(deviceId: string, logCatArguments: string): Q.Promise<any> {
114 this.stopMonitoringLogCat(); // Stop previous logcat monitor if it's running
115
116 // this.logCatMonitor can be mutated, so we store it locally too
117 const logCatMonitor = this.logCatMonitor = new LogCatMonitor(deviceId, logCatArguments);
118 logCatMonitor.start() // The LogCat will continue running forever, so we don't wait for it
119 .catch(error =>
120 Log.logWarning("Error while monitoring LogCat", error))
121 .done();
122
123 return Q.resolve<void>(void 0);
124 }
125
126 private stopMonitoringLogCat(): Q.Promise<void> {
127 if (this.logCatMonitor) {
128 this.logCatMonitor.dispose();
129 this.logCatMonitor = null;
130 }
131
132 return Q.resolve<void>(void 0);
133 }
134
135 /**
136 * Extension message handler.
137 */
138 private handleExtensionMessage(messageWithArgs: em.MessageWithArguments): Q.Promise<any> {
139 let handler = this.messageHandlerDictionary[messageWithArgs.message];
140 if (handler) {
141 Log.logInternalMessage(LogLevel.Info, "Handling message: " + em.ExtensionMessage[messageWithArgs.message]);
142 return handler.apply(this, messageWithArgs.args);
143 } else {
144 return Q.reject("Invalid message: " + messageWithArgs.message);
145 }
146 }
147
148 /**
149 * Handles connections to the server.
150 */
151 private handleSocket(socket: net.Socket): void {
152 let handleError = (e: any) => {
153 Log.logError(e);
154 socket.end(em.ErrorMarker);
155 };
156
157 let dataCallback = (data: any) => {
158 try {
159 let messageWithArgs: em.MessageWithArguments = JSON.parse(data);
160 em.validateMessageWithArguments(messageWithArgs);
161 this.handleExtensionMessage(messageWithArgs)
162 .then(result => {
163 socket.end(JSON.stringify(result));
164 })
165 .catch((e) => { handleError(e); })
166 .done();
167 } catch (e) {
168 handleError(e);
169 }
170 };
171
172 socket.on("data", dataCallback);
173 };
174
175 /**
176 * Recovers the server in case the named socket we use already exists, but no other instance of VSCode is active.
177 */
178 private recoverServer(error: any): void {
179 let errorHandler = (e: any) => {
180 /* The named socket is not used. */
181 if (e.code === "ECONNREFUSED") {
182 new FileSystem().removePathRecursivelyAsync(this.pipePath)
183 .then(() => {
184 this.serverInstance.listen(this.pipePath);
185 })
186 .done();
187 }
188 };
189
190 /* The named socket already exists. */
191 if (error.code === "EADDRINUSE") {
192 let clientSocket = new net.Socket();
193 clientSocket.on("error", errorHandler);
194 clientSocket.connect(this.pipePath, function() {
195 clientSocket.end();
196 });
197 }
198 }
199}
200