feat(net): getNetworkAddress() (#4677)

* feat(net): `getNetworkAddress()`

* tweaks

* tweaks

* work

* work

* tweak

* tweaks
This commit is contained in:
Asher Gomez 2024-05-30 12:17:40 +10:00 committed by GitHub
parent fc8b738487
commit 622012b375
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 151 additions and 14 deletions

View File

@ -51,6 +51,7 @@ import { parseArgs } from "@std/cli/parse-args";
import { red } from "@std/fmt/colors";
import denoConfig from "./deno.json" with { type: "json" };
import { format as formatBytes } from "@std/fmt/bytes";
import { getNetworkAddress } from "@std/net/get-network-address";
interface EntryInfo {
mode: string;
@ -847,19 +848,6 @@ function main() {
}
}
/**
* Gets the network address of the machine,
* inspired by the util of the same name in `npm:serve`
* https://github.com/vercel/serve/blob/1ea55b1b5004f468159b54775e4fb3090fedbb2b/source/utilities/http.ts#L33
*/
function getNetworkAddress() {
for (const { family, address } of Deno.networkInterfaces()) {
if (family === "IPv4" && !address.startsWith("127.")) {
return address;
}
}
}
function printUsage() {
console.log(`Deno File Server ${denoConfig.version}
Serves a local directory in HTTP.

View File

@ -3,6 +3,7 @@
"version": "0.224.1",
"exports": {
".": "./mod.ts",
"./get-available-port": "./get_available_port.ts"
"./get-available-port": "./get_available_port.ts",
"./get-network-address": "./get_network_address.ts"
}
}

View File

@ -0,0 +1,48 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
/**
* Gets the IPv4 or IPv6 network address of the machine.
*
* This is inspired by the util of the same name in
* {@linkcode https://www.npmjs.com/package/serve | npm:serve}.
*
* For more advanced use, use {@linkcode Deno.networkInterfaces} directly.
*
* @see {@link https://github.com/vercel/serve/blob/1ea55b1b5004f468159b54775e4fb3090fedbb2b/source/utilities/http.ts#L33}
*
* @param family The IP protocol version of the interface to get the address of.
* @returns The IPv4 network address of the machine.
*
* @example Get the IPv4 network address (default)
* ```ts
* import { getNetworkAddress } from "@std/net/get-network-address";
* import { assert } from "@std/assert/assert";
*
* const address = getNetworkAddress();
*
* assert(address !== undefined);
* ```
*
* @example Get the IPv6 network address
* ```ts
* import { getNetworkAddress } from "@std/net/get-network-address";
* import { assert } from "@std/assert/assert";
*
* const address = getNetworkAddress("IPv6");
*
* assert(address !== undefined);
* ```
*/
export function getNetworkAddress(
family: Deno.NetworkInterfaceInfo["family"] = "IPv4",
): string | undefined {
return Deno.networkInterfaces()
.find((i) =>
i.family === family &&
(family === "IPv4"
// Cannot lie within 127.0.0.0/8
? !i.address.startsWith("127")
// Cannot be loopback or link-local addresses
: !(i.address === "::1" || i.address === "fe80::1") && i.scopeid === 0)
)
?.address;
}

View File

@ -0,0 +1,99 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { getNetworkAddress } from "./get_network_address.ts";
import { stub } from "@std/testing/mock";
import { assertEquals } from "@std/assert/assert-equals";
const INTERFACES: Deno.NetworkInterfaceInfo[] = [
// Network inaccessible
{
family: "IPv4",
name: "lo0",
address: "127.0.0.1",
netmask: "255.0.0.0",
scopeid: null,
cidr: "127.0.0.1/8",
mac: "00:00:00:00:00:00",
},
{
family: "IPv6",
name: "lo0",
address: "::1",
netmask: "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
scopeid: 0,
cidr: "::1/128",
mac: "00:00:00:00:00:00",
},
{
family: "IPv6",
name: "lo0",
address: "fe80::1",
netmask: "ffff:ffff:ffff:ffff::",
scopeid: 1,
cidr: "fe80::1/64",
mac: "00:00:00:00:00:00",
},
{
family: "IPv6",
name: "utun2",
address: "fe80::7c00:d02e:f1ae:3980",
netmask: "ffff:ffff:ffff:ffff::",
scopeid: 17,
cidr: "fe80::7c00:d02e:f1ae:3980/64",
mac: "00:00:00:00:00:00",
},
// Network accessible
{
family: "IPv4",
name: "en0",
address: "192.168.0.123",
netmask: "255.255.255.0",
scopeid: null,
cidr: "192.168.0.123/24",
mac: "11:11:11:11:11:11",
},
{
family: "IPv6",
name: "en0",
address: "2001:0000:0000:0000:0000:0000:0000:1234",
netmask: "ffff:ffff:ffff:ffff::",
scopeid: 0,
cidr: "2001:0000:0000:0000:0000:0000:0000:1234/64",
mac: "11:11:11:11:11:11",
},
] as const;
Deno.test("getNetworkAddress() works with IPv4", () => {
using _networkInterfaces = stub(
Deno,
"networkInterfaces",
() => INTERFACES,
);
const hostname = getNetworkAddress();
assertEquals(hostname, INTERFACES[4]!.address);
});
Deno.test("getNetworkAddress() returns listenable IPv4 address", () => {
const hostname = getNetworkAddress();
// Only do this test if listenable network interfaces exist
if (hostname !== undefined) {
using _listener = Deno.listen({ hostname, port: 0 });
}
});
Deno.test("getNetworkAddress() works with IPv6", () => {
using _networkInterfaces = stub(
Deno,
"networkInterfaces",
() => INTERFACES,
);
const hostname = getNetworkAddress("IPv6");
assertEquals(hostname, INTERFACES[5]!.address);
});
Deno.test("getNetworkAddress() returns listenable IPv6 address", () => {
const hostname = getNetworkAddress("IPv6");
// Only do this test if listenable network interfaces exist
if (hostname !== undefined) {
using _listener = Deno.listen({ hostname, port: 0 });
}
});

View File

@ -7,3 +7,4 @@
*/
export * from "./get_available_port.ts";
export * from "./get_network_address.ts";