microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
9fe4ca937c831dc8a5dc47004292f6ed11544e43

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/extensionServer.ts

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