mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-30 17:23:29 -05:00
* Do not rely on same starting port every time, misc * put back to 5 seconds for process kill timeout * extHostNotebook shutdown manager handle
114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
// This code is originally from https://github.com/Microsoft/vscode/blob/master/src/vs/base/node/ports.ts
|
|
|
|
import * as net from 'net';
|
|
|
|
export class StrictPortFindOptions {
|
|
constructor(public minPort: number, public maxport: number) {
|
|
}
|
|
public maxRetriesPerStartPort: number = 5;
|
|
public totalRetryLoops: number = 10;
|
|
public timeout: number = 5000;
|
|
}
|
|
|
|
/**
|
|
* Searches for a free port with additional retries and a function to search in a much larger range if initial
|
|
* attempt to find a port fails. By skipping to a random port after the first time failing, this should help
|
|
* reduce the likelihood that no free port can be found.
|
|
*/
|
|
export async function strictFindFreePort(options: StrictPortFindOptions): Promise<number> {
|
|
let totalRetries = options.totalRetryLoops;
|
|
let startPort = getRandomInt(options.minPort, options.maxport);
|
|
let port = await findFreePort(startPort, options.maxRetriesPerStartPort, options.timeout);
|
|
while (port === 0 && totalRetries > 0) {
|
|
startPort = getRandomInt(options.minPort, options.maxport);
|
|
port = await findFreePort(startPort, options.maxRetriesPerStartPort, options.timeout);
|
|
totalRetries--;
|
|
}
|
|
return port;
|
|
}
|
|
|
|
/**
|
|
* Get a random integer between `min` and `max`.
|
|
*
|
|
* @param min - min number
|
|
* @param max - max number
|
|
* @return a random integer
|
|
*/
|
|
function getRandomInt(min: number, max: number): number {
|
|
return Math.floor(Math.random() * (max - min + 1) + min);
|
|
}
|
|
|
|
/**
|
|
* Given a start point and a max number of retries, will find a port that
|
|
* is openable. Will return 0 in case no free port can be found.
|
|
*/
|
|
export function findFreePort(startPort: number, giveUpAfter: number, timeout: number): Thenable<number> {
|
|
let done = false;
|
|
|
|
return new Promise(resolve => {
|
|
const timeoutHandle = setTimeout(() => {
|
|
if (!done) {
|
|
done = true;
|
|
return resolve(0);
|
|
}
|
|
}, timeout);
|
|
|
|
doFindFreePort(startPort, giveUpAfter, (port) => {
|
|
if (!done) {
|
|
done = true;
|
|
clearTimeout(timeoutHandle);
|
|
return resolve(port);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function doFindFreePort(startPort: number, giveUpAfter: number, clb: (port: number) => void): void {
|
|
if (giveUpAfter === 0) {
|
|
return clb(0);
|
|
}
|
|
|
|
const client = new net.Socket();
|
|
|
|
// If we can connect to the port it means the port is already taken so we continue searching
|
|
client.once('connect', () => {
|
|
dispose(client);
|
|
|
|
return doFindFreePort(startPort + 1, giveUpAfter - 1, clb);
|
|
});
|
|
|
|
client.once('data', () => {
|
|
// this listener is required since node.js 8.x
|
|
});
|
|
|
|
client.once('error', (err: Error & { code?: string }) => {
|
|
dispose(client);
|
|
|
|
// If we receive any non ECONNREFUSED error, it means the port is used but we cannot connect
|
|
if (err.code !== 'ECONNREFUSED') {
|
|
return doFindFreePort(startPort + 1, giveUpAfter - 1, clb);
|
|
}
|
|
|
|
// Otherwise it means the port is free to use!
|
|
return clb(startPort);
|
|
});
|
|
|
|
client.connect(startPort, '127.0.0.1');
|
|
}
|
|
|
|
function dispose(socket: net.Socket): void {
|
|
try {
|
|
socket.removeAllListeners('connect');
|
|
socket.removeAllListeners('error');
|
|
socket.end();
|
|
socket.destroy();
|
|
socket.unref();
|
|
} catch (error) {
|
|
console.error(error); // otherwise this error would get lost in the callback chain
|
|
}
|
|
}
|