Skip to content

Commit b8f286f

Browse files
committed
(GH-412) Add ConnectionHandler
This commit adds a new ConnectionHandler abstract class that implements all logic needed to create, configure, and start a `LanguageClient` to connect with a `LanguageServer`. It does not handle setting up the logic needed to create, configure, or start the protocol specific code needed to communicate. That logic will be handled by classes that extend `ConnectionHandler`. This is largely a distilled re-implementation of parts of `ConnectionManager` and 'PuppetLanguageClient` and requires the stdio and tcp implementations to work.
1 parent 416f071 commit b8f286f

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

src/handler.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import * as vscode from 'vscode';
2+
import { LanguageClient, ServerOptions, LanguageClientOptions, RevealOutputChannelOn } from 'vscode-languageclient';
3+
4+
import { ConnectionStatus, IConnectionConfiguration, ConnectionType, ProtocolType } from './interfaces';
5+
import { PuppetStatusBar } from './PuppetStatusBar';
6+
import { OutputChannelLogger } from './logging/outputchannel';
7+
import { ISettings } from './settings';
8+
import { PuppetVersionDetails, PuppetVersionRequest, PuppetCommandStrings } from './messages';
9+
import { reporter } from './telemetry/telemetry';
10+
11+
export abstract class ConnectionHandler {
12+
private timeSpent:number;
13+
14+
private _status: ConnectionStatus;
15+
public get status(): ConnectionStatus {
16+
return this._status;
17+
}
18+
19+
private _languageClient: LanguageClient;
20+
public get languageClient(): LanguageClient {
21+
return this._languageClient;
22+
}
23+
24+
abstract get connectionType(): ConnectionType;
25+
26+
public get protocolType(): ProtocolType {
27+
return this.settings.editorService.protocol;
28+
}
29+
30+
protected constructor(
31+
protected context: vscode.ExtensionContext,
32+
protected settings: ISettings,
33+
protected statusBar: PuppetStatusBar,
34+
protected logger: OutputChannelLogger,
35+
protected config: IConnectionConfiguration,
36+
) {
37+
this.timeSpent = Date.now();
38+
this.setConnectionStatus('Initializing', ConnectionStatus.Initializing);
39+
40+
let documents = [{ scheme: 'file', language: 'puppet' }];
41+
42+
this.logger.debug('Configuring language client options');
43+
let clientOptions: LanguageClientOptions = {
44+
documentSelector: documents,
45+
outputChannel: this.logger.logChannel,
46+
revealOutputChannelOn: RevealOutputChannelOn.Info,
47+
};
48+
49+
this.logger.debug('Creating server options');
50+
let serverOptions = this.createServerOptions();
51+
52+
this.logger.debug('Creating language client');
53+
this._languageClient = new LanguageClient('PuppetVSCode', serverOptions, clientOptions);
54+
this._languageClient
55+
.onReady()
56+
.then(
57+
() => {
58+
this.setConnectionStatus('Loading Puppet', ConnectionStatus.Starting);
59+
this.queryLanguageServerStatusWithProgress();
60+
},
61+
reason => {
62+
this.setConnectionStatus('Starting error', ConnectionStatus.Starting);
63+
this.languageClient.error(reason);
64+
},
65+
)
66+
.catch(() => {
67+
this.setConnectionStatus('Failure', ConnectionStatus.Failed);
68+
});
69+
this.setConnectionStatus('Initialization Complete', ConnectionStatus.InitializationComplete);
70+
71+
this.context.subscriptions.push(vscode.commands.registerCommand(PuppetCommandStrings.PuppetShowConnectionLogsCommandId,
72+
() => { this.logger.show(); }
73+
));
74+
}
75+
76+
abstract createServerOptions(): ServerOptions;
77+
abstract cleanup(): void;
78+
79+
start(): void {
80+
this.setConnectionStatus('Starting languageserver', ConnectionStatus.Starting, '');
81+
this.context.subscriptions.push(this.languageClient.start());
82+
}
83+
84+
stop(): void {
85+
this.setConnectionStatus('Stopping languageserver', ConnectionStatus.Stopping, '');
86+
if (this.languageClient !== undefined) {
87+
this.timeSpent = Date.now() - this.timeSpent;
88+
this._languageClient.sendRequest(PuppetVersionRequest.type).then(versionDetails => {
89+
reporter.sendTelemetryEvent('data', {
90+
'timeSpent' : this.timeSpent.toString(),
91+
'puppetVersion' : versionDetails.puppetVersion,
92+
'facterVersion' : versionDetails.facterVersion,
93+
'languageServerVersion': versionDetails.languageServerVersion,
94+
});
95+
});
96+
this.languageClient.stop();
97+
}
98+
99+
this.logger.debug('Running cleanup');
100+
this.cleanup();
101+
this.setConnectionStatus('Stopped languageserver', ConnectionStatus.Stopped, '');
102+
}
103+
104+
private setConnectionStatus(message: string, status: ConnectionStatus, toolTip?: string) {
105+
this._status = status;
106+
this.statusBar.setConnectionStatus(message, status, toolTip);
107+
}
108+
109+
private queryLanguageServerStatusWithProgress() {
110+
return new Promise((resolve, reject) => {
111+
let count = 0;
112+
let lastVersionResponse: PuppetVersionDetails;
113+
let handle = setInterval(() => {
114+
count++;
115+
116+
// After 30 seonds timeout the progress
117+
if (count >= 30 || this._languageClient === undefined) {
118+
clearInterval(handle);
119+
this.setConnectionStatus(lastVersionResponse.puppetVersion, ConnectionStatus.RunningLoaded, '');
120+
resolve();
121+
return;
122+
}
123+
124+
this._languageClient.sendRequest(PuppetVersionRequest.type).then(versionDetails => {
125+
lastVersionResponse = versionDetails;
126+
if (
127+
versionDetails.factsLoaded &&
128+
versionDetails.functionsLoaded &&
129+
versionDetails.typesLoaded &&
130+
versionDetails.classesLoaded
131+
) {
132+
clearInterval(handle);
133+
this.setConnectionStatus(lastVersionResponse.puppetVersion, ConnectionStatus.RunningLoaded, '');
134+
resolve();
135+
} else {
136+
let toolTip: string = '';
137+
138+
toolTip += versionDetails.classesLoaded ? '✔ Classes: Loaded\n' : '⏳ Classes: Loading...\n';
139+
toolTip += versionDetails.factsLoaded ? '✔ Facts: Loaded\n' : '⏳ Facts: Loading...\n';
140+
toolTip += versionDetails.functionsLoaded ? '✔ Functions: Loaded\n' : '⏳ Functions: Loading...\n';
141+
toolTip += versionDetails.typesLoaded ? '✔ Types: Loaded' : '⏳ Types: Loading...';
142+
143+
this.setConnectionStatus(lastVersionResponse.puppetVersion, ConnectionStatus.RunningLoading, toolTip);
144+
}
145+
});
146+
}, 1000);
147+
});
148+
}
149+
}

0 commit comments

Comments
 (0)