-
Notifications
You must be signed in to change notification settings - Fork 55
/
BspProxy.ts
107 lines (99 loc) · 4.2 KB
/
BspProxy.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { JdtlsImporterConnector } from "./JdtlsImporterConnector";
import { BuildServerConnector } from "./BuildServerConnector";
import * as vscode from "vscode";
import * as rpc from "vscode-jsonrpc/node";
import { Logger } from "../logger/index";
import { sendInfo } from "vscode-extension-telemetry-wrapper";
/**
* Forwards JSON-RPC messages between the build server and the Java JDT LS importer.
*
* This layer is necessary because named pipes are not well supported by Java on Windows,
* but are well supported by Node.js. So Node.js is used to create two named pipe servers.
*
* During the named pipe connecting process, Both the build server and JDT LS importer act as clients connecting to BspProxy.
*/
export class BspProxy {
private buildServerConnector: BuildServerConnector;
private jdtlsImporterConnector: JdtlsImporterConnector;
private buildServerStart: boolean;
constructor(context: vscode.ExtensionContext, private readonly logger: Logger) {
this.buildServerConnector = new BuildServerConnector();
this.jdtlsImporterConnector = new JdtlsImporterConnector(context);
}
/**
* This function needs to be called before we start Java Gradle Server.
*/
public prepareToStart(): boolean {
return this.buildServerConnector.setupBuildServerPipeStream();
}
/**
* The order of the following start steps is important.
*
* We have to start listening after the message forwarding is setup, otherwise the Java importer
* will stop polling and start sending messages before the forwarding is setup and the messages will be lost.
*/
public async start(): Promise<void> {
await this.jdtlsImporterConnector.waitForImporterPipePath();
await this.jdtlsImporterConnector.setupImporterPipeStream();
if (this.buildServerStart) {
this.setupMessageForwarding(
this.jdtlsImporterConnector.getImporterConnection(),
this.buildServerConnector.getServerConnection()
);
}
this.jdtlsImporterConnector.startListening();
}
public getBuildServerPipeName(): string {
return this.buildServerConnector.getServerPipePath();
}
private setupMessageForwarding(
importerConnection: rpc.MessageConnection | null,
buildServerConnection: rpc.MessageConnection | null
): void {
if (!importerConnection || !buildServerConnection) {
return;
}
importerConnection.onRequest((method, params) => {
if (params !== null) {
return buildServerConnection.sendRequest(method, params);
}
return buildServerConnection.sendRequest(method);
});
buildServerConnection.onNotification((method, params) => {
if (params !== null) {
return importerConnection.sendNotification(method, params);
}
importerConnection.sendNotification(method);
});
importerConnection.onError(([error]) => {
this.logger.error(`Error on importerConnection: ${error.message}`);
sendInfo("", {
kind: "bspProxy-importerConnectionError",
message: error.message,
proxyErrorStack: error.stack ? error.stack.toString() : "",
});
// TODO: Implement more specific error handling logic here
});
buildServerConnection.onError(([error]) => {
this.logger.error(`Error on buildServerConnection: ${error.message}`);
sendInfo("", {
kind: "bspProxy-buildServerConnectionError",
message: error.message,
proxyErrorStack: error.stack ? error.stack.toString() : "",
});
// TODO: Implement more specific error handling logic here
});
}
public setBuildServerStarted(started: boolean): void {
this.buildServerStart = started;
}
public closeConnection(): void {
try {
this.buildServerConnector.close();
this.jdtlsImporterConnector.close();
} catch (error) {
// Error when pipe server not started. Ignore it.
}
this.logger.info("Build Server connection closed");
}
}