microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
a9d77c8b0667ef4b6618231d585f8465dae8b0df

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/extensionServer.ts

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