Skip to content

Commit 90ff83b

Browse files
authored
Merge pull request #112 from austb/random_local_port
(GH-109) Randomize language server port when local
2 parents af61569 + 45bd020 commit 90ff83b

File tree

1 file changed

+75
-45
lines changed

1 file changed

+75
-45
lines changed

client/src/connection.ts

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -88,35 +88,13 @@ export class ConnectionManager implements IConnectionManager {
8888
this.setConnectionStatus("Starting Puppet...", ConnectionStatus.Starting);
8989

9090
if (this.connectionConfiguration.type == ConnectionType.Local) {
91-
this.languageServerProcess = this.createLanguageServerProcess(contextPath);
92-
if (this.languageServerProcess == undefined) {
93-
if (this.connectionStatus == ConnectionStatus.Failed) {
94-
// We've already handled this state. Just return
95-
return
96-
}
97-
throw new Error('Unable to start the Language Server Process');
98-
}
99-
100-
this.languageServerProcess.stdout.on('data', (data) => {
101-
this.logger.debug("OUTPUT: " + data.toString());
102-
103-
// If the language client isn't already running and it's sent the trigger text, start up a client
104-
if ( (this.languageServerClient == undefined) && (data.toString().match("LANGUAGE SERVER RUNNING") != null) ) {
105-
this.languageServerClient = this.startLangClientTCP();
106-
this.extensionContext.subscriptions.push(this.languageServerClient.start());
107-
}
108-
});
109-
110-
this.languageServerProcess.on('close', (exitCode) => {
111-
this.logger.debug("SERVER terminated with exit code: " + exitCode);
112-
});
91+
this.createLanguageServerProcess(contextPath, this.onLanguageServerStart.bind(this));
11392
}
11493
else {
11594
this.languageServerClient = this.startLangClientTCP();
11695
this.extensionContext.subscriptions.push(this.languageServerClient.start());
96+
this.logStart();
11797
}
118-
119-
this.logger.debug('Congratulations, your extension "vscode-puppet" is now active!');
12098
}
12199

122100
public stop() {
@@ -159,12 +137,64 @@ export class ConnectionManager implements IConnectionManager {
159137
this.extensionContext.subscriptions.clear();
160138
}
161139

162-
private createLanguageServerProcess(serverExe: string) {
140+
private logStart() {
141+
this.logger.debug('Congratulations, your extension "vscode-puppet" is now active!');
142+
}
143+
144+
private onLanguageServerStart(proc : cp.ChildProcess) {
145+
this.logger.debug('LanguageServer Process Started: ' + proc)
146+
this.languageServerProcess = proc
147+
if (this.languageServerProcess == undefined) {
148+
if (this.connectionStatus == ConnectionStatus.Failed) {
149+
// We've already handled this state. Just return
150+
return
151+
}
152+
throw new Error('Unable to start the Language Server Process');
153+
}
154+
155+
this.languageServerProcess.stdout.on('data', (data) => {
156+
this.logger.debug("OUTPUT: " + data.toString());
157+
158+
// If the language client isn't already running and it's sent the trigger text, start up a client
159+
if ( (this.languageServerClient == undefined) && (data.toString().match("LANGUAGE SERVER RUNNING") != null) ) {
160+
this.languageServerClient = this.startLangClientTCP();
161+
this.extensionContext.subscriptions.push(this.languageServerClient.start());
162+
}
163+
});
164+
165+
this.languageServerProcess.on('close', (exitCode) => {
166+
this.logger.debug("SERVER terminated with exit code: " + exitCode);
167+
});
168+
169+
this.logStart();
170+
}
171+
172+
public startLanguageServerProcess(cmd : string, args : Array<string>, options : cp.SpawnOptions, callback : Function) {
173+
if ((this.connectionConfiguration.host == undefined) || (this.connectionConfiguration.host == '')) {
174+
args.push('--ip=127.0.0.1');
175+
} else {
176+
args.push('--ip=' + this.connectionConfiguration.host);
177+
}
178+
args.push('--port=' + this.connectionConfiguration.port);
179+
args.push('--timeout=' + this.connectionConfiguration.timeout);
180+
if (this.connectionConfiguration.preLoadPuppet == false) { args.push('--no-preload'); }
181+
if ((this.connectionConfiguration.debugFilePath != undefined) && (this.connectionConfiguration.debugFilePath != '')) {
182+
args.push('--debug=' + this.connectionConfiguration.debugFilePath);
183+
}
184+
185+
this.logger.debug("Starting the language server with " + cmd + " " + args.join(" "));
186+
var proc = cp.spawn(cmd, args, options)
187+
this.logger.debug('Language server PID:' + proc.pid)
188+
189+
callback(proc);
190+
}
191+
192+
private createLanguageServerProcess(serverExe: string, callback : Function) {
163193
this.logger.debug('Language server found at: ' + serverExe)
164194

165195
let cmd: string = undefined;
166196
let args = [serverExe];
167-
let options = {};
197+
let options : cp.SpawnOptions = {};
168198

169199
// type Platform = 'aix'
170200
// | 'android'
@@ -204,7 +234,7 @@ export class ConnectionManager implements IConnectionManager {
204234
this.logger.debug('Starting language server')
205235

206236
// Try and find the puppet-agent ruby
207-
let rubyPath: string = '/opt/puppetlabs/puppet/bin/ruby';
237+
let rubyPath : string = '/opt/puppetlabs/puppet/bin/ruby';
208238
if (fs.existsSync(rubyPath)) { cmd = rubyPath }
209239

210240
// Default to ruby on the path
@@ -222,30 +252,30 @@ export class ConnectionManager implements IConnectionManager {
222252
return;
223253
}
224254

225-
if ((this.connectionConfiguration.host == undefined) || (this.connectionConfiguration.host == '')) {
226-
args.push('--ip=127.0.0.1');
227-
args.push('--local-workspace=' + vscode.workspace.textDocuments[0]);
228-
} else {
229-
args.push('--ip=' + this.connectionConfiguration.host);
230-
}
231-
args.push('--port=' + this.connectionConfiguration.port);
232-
args.push('--timeout=' + this.connectionConfiguration.timeout);
233-
if (this.connectionConfiguration.preLoadPuppet == false) { args.push('--no-preload'); }
234-
if ((this.connectionConfiguration.debugFilePath != undefined) && (this.connectionConfiguration.debugFilePath != '')) {
235-
args.push('--debug=' + this.connectionConfiguration.debugFilePath);
236-
}
237-
238-
this.logger.debug("Starting the language server with " + cmd + " " + args.join(" "));
239-
var proc = cp.spawn(cmd, args, options)
240-
this.logger.debug('Language server PID:' + proc.pid)
255+
let connMgr : ConnectionManager = this;
256+
let logger = this.logger;
257+
// Start a server to get a random port
258+
this.logger.debug('Creating server process to identify random port')
259+
const server = net.createServer()
260+
.on('close', () => {
261+
logger.debug('Server process to identify random port disconnected');
262+
connMgr.startLanguageServerProcess(cmd, args, options, callback);
263+
})
264+
.on('error', (err) => {
265+
throw err;
266+
});
241267

242-
return proc;
268+
// Listen on random port
269+
server.listen(0);
270+
this.logger.debug('Selected port for local language server: ' + server.address().port);
271+
connMgr.connectionConfiguration.port = server.address().port;
272+
server.close();
243273
}
244274

245275
private startLangClientTCP(): LanguageClient {
246276
this.logger.debug('Configuring language server options')
247277

248-
var connMgr:ConnectionManager = this;
278+
let connMgr:ConnectionManager = this;
249279
let serverOptions: ServerOptions = function () {
250280
return new Promise((resolve, reject) => {
251281
var client = new net.Socket();

0 commit comments

Comments
 (0)