Files
testcontainers/docker/libraries/port.ts
2024-07-19 19:41:59 +02:00

93 lines
2.5 KiB
TypeScript

export const MIN_PORT = 1024;
export const MAX_PORT = 65535;
/**
* Try run listener to check if port is open.
*
* @param options - Deno listen options.
*/
export function checkPort(options: Deno.ListenOptions): CheckedPort {
const { port } = options;
try {
Deno.listen(options).close();
return { valid: true, port: port };
} catch (e) {
if (e.name !== "AddrInUse") {
throw e;
}
return { valid: false, port: port };
}
}
/**
* Create an array of number by min and max.
*
* @param from - Must be between 1024 and 65535
* @param to - Must be between 1024 and 65535 and greater than from
*/
export function makeRange(from: number, to: number): number[] {
if (!(from > MIN_PORT || from < MAX_PORT)) {
throw new RangeError("`from` must be between 1024 and 65535");
}
if (!(to > MIN_PORT || to < MAX_PORT)) {
throw new RangeError("`to` must be between 1024 and 65536");
}
if (!(to > from)) {
throw new RangeError("`to` must be greater than or equal to `from`");
}
const ports = [];
for (let port = from; port <= to; port++) {
ports.push(port);
}
return ports;
}
/**
* Return a random port between 1024 and 65535.
*
* @param hostname - Hostname to check for port availability under. (Optional)
*/
export function randomPort(hostname?: string): number {
const port = Math.ceil(Math.random() * ((MAX_PORT - 1) - MIN_PORT + 1) + MIN_PORT + 1);
const result: CheckedPort = checkPort({ hostname, port });
if (result.valid) {
return result.port;
}
return randomPort(hostname);
}
/**
* Return available port.
*
* @param port - Wanted port, or list of ports. (Optional)
* @param hostname - Hostname to check for availability under. (Optional)
*/
export default function getPort(port?: number | number[], hostname?: string): number {
const listenOptions: Deno.ListenOptions = {
hostname: hostname || "0.0.0.0",
port: (port && !Array.isArray(port)) ? port : 0,
};
if (!port || Array.isArray(port)) {
const ports: number[] = (Array.isArray(port)) ? port : makeRange(MIN_PORT + 1, MAX_PORT - 1);
for (const port of ports) {
const result: CheckedPort = checkPort({ ...listenOptions, port });
if (result.valid) return result.port;
}
return getPort(ports[ports.length - 1]);
}
const result: CheckedPort = checkPort(listenOptions);
if (!result.valid) {
const range = makeRange(result.port + 1, MAX_PORT - 1);
return getPort(range);
}
return result.port;
}
export type CheckedPort = {
valid: boolean;
port: number;
};