From dfbfa900e1cfde0a55db767a74337d01c7d94421 Mon Sep 17 00:00:00 2001 From: kodemon Date: Fri, 19 Jul 2024 19:39:26 +0200 Subject: [PATCH] feat: add ports to code --- containers/postgres.ts | 4 +- deno.json | 2 - deno.lock | 10 +---- docker/libraries/exec.ts | 2 +- docker/libraries/port.ts | 92 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 docker/libraries/port.ts diff --git a/containers/postgres.ts b/containers/postgres.ts index 4742cfa..abbabe6 100644 --- a/containers/postgres.ts +++ b/containers/postgres.ts @@ -18,11 +18,11 @@ * ``` */ -import delay from "delay"; -import getPort from "port"; import psql, { type Sql } from "postgres"; +import { delay } from "std/async/delay.ts"; import type { Container } from "../docker/libraries/container.ts"; +import getPort from "../docker/libraries/port.ts"; import { docker } from "../mod.ts"; export class PostgresTestContainer { diff --git a/deno.json b/deno.json index b1742a5..2b982fe 100644 --- a/deno.json +++ b/deno.json @@ -7,8 +7,6 @@ }, "imports": { "std/": "https://deno.land/std@0.224.0/", - "delay": "npm:delay@6.0.0", - "port": "https://deno.land/x/getport@v2.1.2/mod.ts", "postgres": "npm:postgres@3.4.4" }, "exclude": [ diff --git a/deno.lock b/deno.lock index bfcc672..adfe81b 100644 --- a/deno.lock +++ b/deno.lock @@ -2,14 +2,9 @@ "version": "3", "packages": { "specifiers": { - "npm:delay@6.0.0": "npm:delay@6.0.0", "npm:postgres@3.4.4": "npm:postgres@3.4.4" }, "npm": { - "delay@6.0.0": { - "integrity": "sha512-2NJozoOHQ4NuZuVIr5CWd0iiLVIRSDepakaovIN+9eIDHEhdCAEvSy2cuf1DCrPPQLvHmbqTHODlhHg8UCy4zw==", - "dependencies": {} - }, "postgres@3.4.4": { "integrity": "sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==", "dependencies": {} @@ -46,17 +41,16 @@ "https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3", "https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73", "https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19", + "https://deno.land/std@0.224.0/async/delay.ts": "f90dd685b97c2f142b8069082993e437b1602b8e2561134827eeb7c12b95c499", "https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5", "https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6", "https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2", "https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e", "https://deno.land/std@0.224.0/testing/_test_suite.ts": "f10a8a6338b60c403f07a76f3f46bdc9f1e1a820c0a1decddeb2949f7a8a0546", - "https://deno.land/std@0.224.0/testing/bdd.ts": "3e4de4ff6d8f348b5574661cef9501b442046a59079e201b849d0e74120d476b", - "https://deno.land/x/getport@v2.1.2/mod.ts": "e1d629c14008fc1da85278615c55e9356c206d35054577c49639248e3c036f17" + "https://deno.land/std@0.224.0/testing/bdd.ts": "3e4de4ff6d8f348b5574661cef9501b442046a59079e201b849d0e74120d476b" }, "workspace": { "dependencies": [ - "npm:delay@6.0.0", "npm:postgres@3.4.4" ] } diff --git a/docker/libraries/exec.ts b/docker/libraries/exec.ts index e92f36e..d698da0 100644 --- a/docker/libraries/exec.ts +++ b/docker/libraries/exec.ts @@ -1,4 +1,4 @@ -import delay from "delay"; +import { delay } from "std/async/delay.ts"; import { modem } from "./modem.ts"; diff --git a/docker/libraries/port.ts b/docker/libraries/port.ts new file mode 100644 index 0000000..7aa8212 --- /dev/null +++ b/docker/libraries/port.ts @@ -0,0 +1,92 @@ +export const MIN_PORT = 1024; +export const MAX_PORT = 65535; + +/** + * Try run listener to check if port is open. + * + * @param 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 + */ +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 + * @param hostname + */ +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; +};