microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
4f4e082dd1d2adc773da8fdd1c2a71ffaa5837dd

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/extensionServer.ts

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