@dynatrace/devkit
Version:
The Dynatrace App Toolkit utilities for writing and testing migrations.
106 lines (105 loc) • 3.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.findPortInRange = findPortInRange;
exports.isUsed = isUsed;
exports.runOnUnusedPort = runOnUnusedPort;
const net_1 = require("net");
/**
* @internal Only for the use of DevXp
* Util to get a free port to run tests on.
*/
async function findPortInRange(host, startPort, endPort) {
let port = startPort;
while (endPort ? port <= endPort : true) {
if (!(await isUsed(host, port))) {
return port;
}
else {
port++;
if (endPort && port > endPort) {
throw new Error('All ports are taken!');
}
}
}
}
/**
* @internal Only for the use of DevXp
* Util to check if a port is used or not
*/
async function isUsed(host, port) {
return new Promise((resolve) => {
const server = (0, net_1.createServer)();
server.once('error', () => resolve(true));
server.once('listening', function () {
server.close(() => {
resolve(false);
});
});
server.listen(port, host);
});
}
/**
* @internal Only for the use of DevXp
* Util to write code that depends on a port being unused. Tries to run
* the specified code on a specified port and retries with next port (<= options.endPort)
* if it fails due to the port being bound already.
* @param run code to run that depends on a port being unused.
* @param startPort port that should be used for the first try.
* @param options further options.
* @returns
*/
async function runOnUnusedPort(run, startPort, options) {
// If specified range is an array, make a copy in order to not
// modify original array.
let range;
if (options && Array.isArray(options.range)) {
range = [...options.range];
}
else {
range = options?.range;
}
// Start with specified port
let port = startPort;
while (port) {
try {
const t = await run(port);
return t;
}
catch (error) {
if ((options?.errorMessage &&
error.message.includes(options?.errorMessage)) ||
error.message.includes('EADDRINUSE') ||
error.message.includes('EACCES')) {
if (options?.onUsedCallback) {
options.onUsedCallback(port);
}
}
else {
throw error;
}
}
port = getNextPort(port, range);
}
throw Error(options?.displayMessage ?? 'Could not find a free port!');
}
/**
* Helper function that tries to find the next port to try.
* Attention: Has a side effect on range as shift changes the range if it is a number[]
*/
function getNextPort(port, range) {
if (!range) {
// If nothing specified, try the next port
return port + 1;
}
else {
if (typeof range === 'number') {
// If range is specified by a single number check if the current port is still
// smaller than upper limit.
return port < range ? port + 1 : undefined;
}
else {
// Returns and removes the first element of range
return range.shift();
}
}
}