Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 23da1cf

Browse filesBrowse files
committed
send all events through common stream
1 parent 594ac01 commit 23da1cf
Copy full SHA for 23da1cf

4 files changed

+99-73Lines changed: 99 additions & 73 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/server/editorServices.ts‎

Copy file name to clipboardExpand all lines: src/server/editorServices.ts
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace ts.server {
1616
export const ProjectInfoTelemetryEvent = "projectInfo";
1717
// tslint:enable variable-name
1818

19+
// TODO: make these inherit from protocol.Event?
1920
export interface ProjectsUpdatedInBackgroundEvent {
2021
eventName: typeof ProjectsUpdatedInBackgroundEvent;
2122
data: { openFiles: string[]; };
@@ -320,6 +321,7 @@ namespace ts.server {
320321
pluginProbeLocations?: ReadonlyArray<string>;
321322
allowLocalPluginLoads?: boolean;
322323
typesMapLocation?: string;
324+
eventSender?: EventSender;
323325
}
324326

325327
type WatchFile = (host: ServerHost, file: string, cb: FileWatcherCallback, watchType: WatchType, project?: Project) => FileWatcher;
@@ -436,7 +438,7 @@ namespace ts.server {
436438
this.loadTypesMap();
437439
}
438440

439-
this.typingsInstaller.attach(this);
441+
this.typingsInstaller.attach(this, opts.eventSender);
440442

441443
this.typingsCache = new TypingsCache(this.typingsInstaller);
442444

Collapse file

‎src/server/server.ts‎

Copy file name to clipboardExpand all lines: src/server/server.ts
+21-45Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/// <reference types="node" />
21
/// <reference path="shared.ts" />
32
/// <reference path="session.ts" />
43

@@ -7,7 +6,7 @@ namespace ts.server {
76
host: ServerHost;
87
cancellationToken: ServerCancellationToken;
98
canUseEvents: boolean;
10-
installerEventPort: number;
9+
eventPort: number;
1110
useSingleInferredProject: boolean;
1211
useInferredProjectPerProjectRoot: boolean;
1312
disableAutomaticTypingAcquisition: boolean;
@@ -22,10 +21,6 @@ namespace ts.server {
2221
allowLocalPluginLoads: boolean;
2322
}
2423

25-
const net: {
26-
connect(options: { port: number }, onConnect?: () => void): NodeSocket
27-
} = require("net");
28-
2924
const childProcess: {
3025
fork(modulePath: string, args: string[], options?: { execArgv: string[], env?: MapLike<string> }): NodeChildProcess;
3126
execFileSync(file: string, args: string[], options: { stdio: "ignore", env: MapLike<string> }): string | Buffer;
@@ -83,10 +78,6 @@ namespace ts.server {
8378
pid: number;
8479
}
8580

86-
interface NodeSocket {
87-
write(data: string, encoding: string): boolean;
88-
}
89-
9081
interface ReadLineOptions {
9182
input: NodeJS.ReadableStream;
9283
output?: NodeJS.WritableStream;
@@ -244,9 +235,8 @@ namespace ts.server {
244235
class NodeTypingsInstaller implements ITypingsInstaller {
245236
private installer: NodeChildProcess;
246237
private installerPidReported = false;
247-
private socket: NodeSocket;
248238
private projectService: ProjectService;
249-
private eventSender: EventSender;
239+
private eventSender: EventSender | undefined;
250240
private activeRequestCount = 0;
251241
private requestQueue: QueuedOperation[] = [];
252242
private requestMap = createMap<QueuedOperation>(); // Maps operation ID to newest requestQueue entry with that ID
@@ -267,18 +257,10 @@ namespace ts.server {
267257
private readonly telemetryEnabled: boolean,
268258
private readonly logger: server.Logger,
269259
private readonly host: ServerHost,
270-
eventPort: number,
271260
readonly globalTypingsCacheLocation: string,
272261
readonly typingSafeListLocation: string,
273262
readonly typesMapLocation: string,
274-
private readonly npmLocation: string | undefined,
275-
private newLine: string) {
276-
if (eventPort) {
277-
const s = net.connect({ port: eventPort }, () => {
278-
this.socket = s;
279-
this.reportInstallerProcessId();
280-
});
281-
}
263+
private readonly npmLocation: string | undefined) {
282264
}
283265

284266
isKnownTypesPackageName(name: string): boolean {
@@ -310,26 +292,23 @@ namespace ts.server {
310292
if (this.installerPidReported) {
311293
return;
312294
}
313-
if (this.socket && this.installer) {
314-
this.sendEvent(0, "typingsInstallerPid", { pid: this.installer.pid });
295+
if (this.installer && this.eventSender) {
296+
this.eventSender.event({ pid: this.installer.pid }, "typingsInstallerPid");
315297
this.installerPidReported = true;
316298
}
317299
}
318300

319-
private sendEvent(seq: number, event: string, body: any): void {
320-
this.socket.write(formatMessage({ seq, type: "event", event, body }, this.logger, Buffer.byteLength, this.newLine), "utf8");
321-
}
322301

323-
setTelemetrySender(telemetrySender: EventSender) {
324-
this.eventSender = telemetrySender;
325-
}
326-
327-
attach(projectService: ProjectService) {
302+
attach(projectService: ProjectService, eventSender?: EventSender) {
328303
this.projectService = projectService;
329304
if (this.logger.hasLevel(LogLevel.requestTime)) {
330305
this.logger.info("Binding...");
331306
}
332307

308+
if (eventSender) {
309+
this.eventSender = eventSender;
310+
}
311+
333312
const args: string[] = [Arguments.GlobalCacheLocation, this.globalTypingsCacheLocation];
334313
if (this.telemetryEnabled) {
335314
args.push(Arguments.EnableTelemetry);
@@ -353,10 +332,10 @@ namespace ts.server {
353332
if (match) {
354333
// if port is specified - use port + 1
355334
// otherwise pick a default port depending on if 'debug' or 'inspect' and use its value + 1
356-
const currentPort = match[2] !== undefined
357-
? +match[2]
358-
: match[1].charAt(0) === "d" ? 5858 : 9229;
359-
execArgv.push(`--${match[1]}=${currentPort + 1}`);
335+
// const currentPort = match[2] !== undefined
336+
// ? +match[2]
337+
// : match[1].charAt(0) === "d" ? 5858 : 9229;
338+
// execArgv.push(`--${match[1]}=${currentPort + 1}`);
360339
break;
361340
}
362341
}
@@ -508,8 +487,8 @@ namespace ts.server {
508487

509488
this.projectService.updateTypingsForProject(response);
510489

511-
if (this.socket) {
512-
this.sendEvent(0, "setTypings", response);
490+
if (this.eventSender) {
491+
this.eventSender.event(response, "setTypings");
513492
}
514493

515494
break;
@@ -530,10 +509,10 @@ namespace ts.server {
530509

531510
class IOSession extends Session {
532511
constructor(options: IoSessionOptions) {
533-
const { host, installerEventPort, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, canUseEvents } = options;
512+
const { host, eventPort, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, canUseEvents } = options;
534513
const typingsInstaller = disableAutomaticTypingAcquisition
535514
? undefined
536-
: new NodeTypingsInstaller(telemetryEnabled, logger, host, installerEventPort, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation, host.newLine);
515+
: new NodeTypingsInstaller(telemetryEnabled, logger, host, globalTypingsCacheLocation, typingSafeListLocation, typesMapLocation, npmLocation);
537516

538517
super({
539518
host,
@@ -545,13 +524,10 @@ namespace ts.server {
545524
hrtime: process.hrtime,
546525
logger,
547526
canUseEvents,
527+
eventPort,
548528
globalPlugins: options.globalPlugins,
549529
pluginProbeLocations: options.pluginProbeLocations,
550530
allowLocalPluginLoads: options.allowLocalPluginLoads });
551-
552-
if (telemetryEnabled && typingsInstaller) {
553-
typingsInstaller.setTelemetrySender(this);
554-
}
555531
}
556532

557533
exit() {
@@ -936,8 +912,8 @@ namespace ts.server {
936912
const options: IoSessionOptions = {
937913
host: sys,
938914
cancellationToken,
939-
installerEventPort: eventPort,
940-
canUseEvents: eventPort === undefined,
915+
eventPort,
916+
canUseEvents: true,
941917
useSingleInferredProject,
942918
useInferredProjectPerProjectRoot,
943919
disableAutomaticTypingAcquisition,
Collapse file

‎src/server/session.ts‎

Copy file name to clipboardExpand all lines: src/server/session.ts
+74-26Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1+
/// <reference types="node" />
12
/// <reference path="..\compiler\commandLineParser.ts" />
23
/// <reference path="..\services\services.ts" />
34
/// <reference path="protocol.ts" />
45
/// <reference path="editorServices.ts" />
56

67
namespace ts.server {
8+
9+
interface NodeSocket {
10+
write(data: string, encoding: string): boolean;
11+
}
12+
13+
const net: {
14+
connect(options: { port: number }, onConnect?: () => void): NodeSocket
15+
} = require("net");
16+
717
interface StackTraceError extends Error {
818
stack?: string;
919
}
@@ -253,6 +263,10 @@ namespace ts.server {
253263
hrtime: (start?: number[]) => number[];
254264
logger: Logger;
255265
canUseEvents: boolean;
266+
/**
267+
* If defined, the Session will send events through `eventPort` instead of stdout.
268+
*/
269+
eventPort?: number;
256270
eventHandler?: ProjectServiceEventHandler;
257271
throttleWaitMilliseconds?: number;
258272

@@ -269,15 +283,19 @@ namespace ts.server {
269283
private currentRequestId: number;
270284
private errorCheck: MultistepOperation;
271285

272-
private eventHandler: ProjectServiceEventHandler;
273-
274286
private host: ServerHost;
275287
private readonly cancellationToken: ServerCancellationToken;
276288
protected readonly typingsInstaller: ITypingsInstaller;
277289
private byteLength: (buf: string, encoding?: string) => number;
278290
private hrtime: (start?: number[]) => number[];
279291
protected logger: Logger;
292+
280293
private canUseEvents: boolean;
294+
private eventPort: number | undefined;
295+
private eventSocket: NodeSocket;
296+
private eventHandler: ProjectServiceEventHandler;
297+
public readonly event: EventSender["event"];
298+
private socketEventQueue: { info: any, eventName: string}[] | undefined;
281299

282300
constructor(opts: SessionOptions) {
283301
this.host = opts.host;
@@ -286,14 +304,49 @@ namespace ts.server {
286304
this.byteLength = opts.byteLength;
287305
this.hrtime = opts.hrtime;
288306
this.logger = opts.logger;
307+
this.eventPort = opts.eventPort;
289308
this.canUseEvents = opts.canUseEvents;
290309

291310
const { throttleWaitMilliseconds } = opts;
292311

312+
if (!this.canUseEvents) {
313+
this.event = noop;
314+
}
315+
else if (this.eventPort) {
316+
const s = net.connect({ port: this.eventPort }, () => {
317+
this.eventSocket = s;
318+
this.clearSocketEventQueue();
319+
});
320+
321+
this.event = function <T>(info: T, eventName: string) {
322+
if (!this.eventSocket) {
323+
if (this.logger.hasLevel(LogLevel.verbose)) {
324+
this.logger.info(`eventPort: event queued, but socket not yet initialized`);
325+
}
326+
(this.socketEventQueue || (this.socketEventQueue = [])).push({ info, eventName });
327+
return;
328+
}
329+
else {
330+
Debug.assert(this.socketEventQueue === undefined);
331+
this.writeToEventSocket(info, eventName);
332+
}
333+
};
334+
}
335+
else {
336+
this.event = function <T>(info: T, eventName: string) {
337+
const ev: protocol.Event = {
338+
seq: 0,
339+
type: "event",
340+
event: eventName,
341+
body: info
342+
};
343+
this.send(ev);
344+
};
345+
}
346+
293347
this.eventHandler = this.canUseEvents
294348
? opts.eventHandler || (event => this.defaultEventHandler(event))
295349
: undefined;
296-
297350
const multistepOperationHost: MultistepOperationHost = {
298351
executeWithRequestId: (requestId, action) => this.executeWithRequestId(requestId, action),
299352
getCurrentRequestId: () => this.currentRequestId,
@@ -314,20 +367,26 @@ namespace ts.server {
314367
eventHandler: this.eventHandler,
315368
globalPlugins: opts.globalPlugins,
316369
pluginProbeLocations: opts.pluginProbeLocations,
317-
allowLocalPluginLoads: opts.allowLocalPluginLoads
370+
allowLocalPluginLoads: opts.allowLocalPluginLoads,
371+
eventSender: this
318372
};
319373
this.projectService = new ProjectService(settings);
320374
this.gcTimer = new GcTimer(this.host, /*delay*/ 7000, this.logger);
321375
}
322376

377+
private clearSocketEventQueue() {
378+
for (const event of this.socketEventQueue) {
379+
this.writeToEventSocket(event.info, event.eventName);
380+
}
381+
this.socketEventQueue = undefined;
382+
}
383+
384+
private writeToEventSocket(info: any, eventName: string): void {
385+
this.eventSocket.write(formatMessage({ seq: 0, type: "event", event: eventName, body: info }, this.logger, Buffer.byteLength, this.host.newLine), "utf8");
386+
}
387+
323388
private sendRequestCompletedEvent(requestId: number): void {
324-
const event: protocol.RequestCompletedEvent = {
325-
seq: 0,
326-
type: "event",
327-
event: "requestCompleted",
328-
body: { request_seq: requestId }
329-
};
330-
this.send(event);
389+
this.event<protocol.RequestCompletedEventBody>({ request_seq: requestId }, "requestCompleted");
331390
}
332391

333392
private defaultEventHandler(event: ProjectServiceEvent) {
@@ -392,26 +451,15 @@ namespace ts.server {
392451
}
393452

394453
public send(msg: protocol.Message) {
395-
if (msg.type === "event" && !this.canUseEvents) {
396-
if (this.logger.hasLevel(LogLevel.verbose)) {
397-
this.logger.info(`Session does not support events: ignored event: ${JSON.stringify(msg)}`);
398-
}
399-
return;
454+
if (msg.type === "event") {
455+
Debug.assert(this.canUseEvents);
456+
Debug.assert(!this.eventPort);
400457
}
401458
this.host.write(formatMessage(msg, this.logger, this.byteLength, this.host.newLine));
402459
}
403460

404-
public event<T>(info: T, eventName: string) {
405-
const ev: protocol.Event = {
406-
seq: 0,
407-
type: "event",
408-
event: eventName,
409-
body: info
410-
};
411-
this.send(ev);
412-
}
413-
414461
// For backwards-compatibility only.
462+
/** @deprecated */
415463
public output(info: any, cmdName: string, reqSeq?: number, errorMsg?: string): void {
416464
this.doOutput(info, cmdName, reqSeq, /*success*/ !errorMsg, errorMsg);
417465
}
Collapse file

‎src/server/typingsCache.ts‎

Copy file name to clipboardExpand all lines: src/server/typingsCache.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace ts.server {
1010
isKnownTypesPackageName(name: string): boolean;
1111
installPackage(options: InstallPackageOptionsWithProjectRootPath): Promise<ApplyCodeActionCommandResult>;
1212
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>): void;
13-
attach(projectService: ProjectService): void;
13+
attach(projectService: ProjectService, eventSender?: EventSender): void;
1414
onProjectClosed(p: Project): void;
1515
readonly globalTypingsCacheLocation: string;
1616
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.