// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. // TODO(petamoriken): enable prefer-primordials for node polyfills // deno-lint-ignore-file prefer-primordials import { op_cpus, op_node_os_get_priority, op_node_os_set_priority, op_node_os_username, } from "ext:core/ops"; import { validateIntegerRange } from "ext:deno_node/_utils.ts"; import process from "node:process"; import { isWindows, osType } from "ext:deno_node/_util/os.ts"; import { ERR_OS_NO_HOMEDIR } from "ext:deno_node/internal/errors.ts"; import { os } from "ext:deno_node/internal_binding/constants.ts"; import { osUptime } from "ext:runtime/30_os.js"; import { Buffer } from "ext:deno_node/internal/buffer.mjs"; export const constants = os; interface CPUTimes { /** The number of milliseconds the CPU has spent in user mode */ user: number; /** The number of milliseconds the CPU has spent in nice mode */ nice: number; /** The number of milliseconds the CPU has spent in sys mode */ sys: number; /** The number of milliseconds the CPU has spent in idle mode */ idle: number; /** The number of milliseconds the CPU has spent in irq mode */ irq: number; } interface CPUCoreInfo { model: string; /** in MHz */ speed: number; times: CPUTimes; } interface NetworkAddress { /** The assigned IPv4 or IPv6 address */ address: string; /** The IPv4 or IPv6 network mask */ netmask: string; family: "IPv4" | "IPv6"; /** The MAC address of the network interface */ mac: string; /** true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false */ internal: boolean; /** The numeric IPv6 scope ID (only specified when family is IPv6) */ scopeid?: number; /** The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null. */ cidr: string; } interface NetworkInterfaces { [key: string]: NetworkAddress[]; } export interface UserInfoOptions { encoding: string; } interface UserInfo { username: string; uid: number; gid: number; shell: string | null; homedir: string | null; } export function arch(): string { return process.arch; } // deno-lint-ignore no-explicit-any (availableParallelism as any)[Symbol.toPrimitive] = (): number => availableParallelism(); // deno-lint-ignore no-explicit-any (arch as any)[Symbol.toPrimitive] = (): string => process.arch; // deno-lint-ignore no-explicit-any (endianness as any)[Symbol.toPrimitive] = (): string => endianness(); // deno-lint-ignore no-explicit-any (freemem as any)[Symbol.toPrimitive] = (): number => freemem(); // deno-lint-ignore no-explicit-any (homedir as any)[Symbol.toPrimitive] = (): string | null => homedir(); // deno-lint-ignore no-explicit-any (hostname as any)[Symbol.toPrimitive] = (): string | null => hostname(); // deno-lint-ignore no-explicit-any (platform as any)[Symbol.toPrimitive] = (): string => platform(); // deno-lint-ignore no-explicit-any (release as any)[Symbol.toPrimitive] = (): string => release(); // deno-lint-ignore no-explicit-any (version as any)[Symbol.toPrimitive] = (): string => version(); // deno-lint-ignore no-explicit-any (totalmem as any)[Symbol.toPrimitive] = (): number => totalmem(); // deno-lint-ignore no-explicit-any (type as any)[Symbol.toPrimitive] = (): string => type(); // deno-lint-ignore no-explicit-any (uptime as any)[Symbol.toPrimitive] = (): number => uptime(); // deno-lint-ignore no-explicit-any (machine as any)[Symbol.toPrimitive] = (): string => machine(); export function cpus(): CPUCoreInfo[] { return op_cpus(); } /** * Returns a string identifying the endianness of the CPU for which the Deno * binary was compiled. Possible values are 'BE' for big endian and 'LE' for * little endian. */ export function endianness(): "BE" | "LE" { // Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness const buffer = new ArrayBuffer(2); new DataView(buffer).setInt16(0, 256, true /* littleEndian */); // Int16Array uses the platform's endianness. return new Int16Array(buffer)[0] === 256 ? "LE" : "BE"; } /** Return free memory amount */ export function freemem(): number { if (Deno.build.os === "linux" || Deno.build.os == "android") { // On linux, use 'available' memory // https://github.com/libuv/libuv/blob/a5c01d4de3695e9d9da34cfd643b5ff0ba582ea7/src/unix/linux.c#L2064 return Deno.systemMemoryInfo().available; } else { // Use 'free' memory on other platforms return Deno.systemMemoryInfo().free; } } /** Not yet implemented */ export function getPriority(pid = 0): number { validateIntegerRange(pid, "pid"); return op_node_os_get_priority(pid); } /** Returns the string path of the current user's home directory. */ export function homedir(): string | null { // Note: Node/libuv calls getpwuid() / GetUserProfileDirectory() when the // environment variable isn't set but that's the (very uncommon) fallback // path. IMO, it's okay to punt on that for now. switch (osType) { case "windows": return Deno.env.get("USERPROFILE") || null; case "linux": case "android": case "darwin": case "freebsd": case "openbsd": return Deno.env.get("HOME") || null; default: throw Error("unreachable"); } } /** Returns the host name of the operating system as a string. */ export function hostname(): string { return Deno.hostname(); } /** Returns an array containing the 1, 5, and 15 minute load averages */ export function loadavg(): number[] { if (isWindows) { return [0, 0, 0]; } return Deno.loadavg(); } /** Returns an object containing network interfaces that have been assigned a network address. * Each key on the returned object identifies a network interface. The associated value is an array of objects that each describe an assigned network address. */ export function networkInterfaces(): NetworkInterfaces { const interfaces: NetworkInterfaces = {}; for ( const { name, address, netmask, family, mac, scopeid, cidr } of Deno .networkInterfaces() ) { const addresses = interfaces[name] ||= []; const networkAddress: NetworkAddress = { address, netmask, family, mac, internal: (family === "IPv4" && isIPv4LoopbackAddr(address)) || (family === "IPv6" && isIPv6LoopbackAddr(address)), cidr, }; if (family === "IPv6") { networkAddress.scopeid = scopeid!; } addresses.push(networkAddress); } return interfaces; } function isIPv4LoopbackAddr(addr: string) { return addr.startsWith("127"); } function isIPv6LoopbackAddr(addr: string) { return addr === "::1" || addr === "fe80::1"; } /** Returns the a string identifying the operating system platform. The value is set at compile time. Possible values are 'darwin', 'linux', and 'win32'. */ export function platform(): string { return process.platform; } /** Returns the operating system as a string */ export function release(): string { return Deno.osRelease(); } /** Returns a string identifying the kernel version */ export function version(): string { // TODO(kt3k): Temporarily uses Deno.osRelease(). // Revisit this if this implementation is insufficient for any npm module return Deno.osRelease(); } /** Returns the machine type as a string */ export function machine(): string { if (Deno.build.arch == "aarch64") { return "arm64"; } return Deno.build.arch; } /** Not yet implemented */ export function setPriority(pid: number, priority?: number) { /* The node API has the 'pid' as the first parameter and as optional. This makes for a problematic implementation in Typescript. */ if (priority === undefined) { priority = pid; pid = 0; } validateIntegerRange(pid, "pid"); validateIntegerRange(priority, "priority", -20, 19); op_node_os_set_priority(pid, priority); } /** Returns the operating system's default directory for temporary files as a string. */ export function tmpdir(): string | null { /* This follows the node js implementation, but has a few differences: * On windows, if none of the environment variables are defined, we return null. * On unix we use a plain Deno.env.get, instead of safeGetenv, which special cases setuid binaries. * Node removes a single trailing / or \, we remove all. */ if (isWindows) { const temp = Deno.env.get("TEMP") || Deno.env.get("TMP"); if (temp) { return temp.replace(/(?<!:)[/\\]*$/, ""); } const base = Deno.env.get("SYSTEMROOT") || Deno.env.get("WINDIR"); if (base) { return base + "\\temp"; } return null; } else { // !isWindows const temp = Deno.env.get("TMPDIR") || Deno.env.get("TMP") || Deno.env.get("TEMP") || "/tmp"; return temp.replace(/(?<!^)\/*$/, ""); } } /** Return total physical memory amount */ export function totalmem(): number { return Deno.systemMemoryInfo().total; } /** Returns operating system type (i.e. 'Windows_NT', 'Linux', 'Darwin') */ export function type(): string { switch (Deno.build.os as string) { case "windows": return "Windows_NT"; case "linux": case "android": return "Linux"; case "darwin": return "Darwin"; case "freebsd": return "FreeBSD"; case "openbsd": return "OpenBSD"; default: throw Error("unreachable"); } } /** Returns the Operating System uptime in number of seconds. */ export function uptime(): number { return osUptime(); } /** Not yet implemented */ export function userInfo( options: UserInfoOptions = { encoding: "utf-8" }, ): UserInfo { let uid = Deno.uid(); let gid = Deno.gid(); if (isWindows) { uid = -1; gid = -1; } // TODO(@crowlKats): figure out how to do this correctly: // The value of homedir returned by os.userInfo() is provided by the operating system. // This differs from the result of os.homedir(), which queries environment // variables for the home directory before falling back to the operating system response. let _homedir = homedir(); if (!_homedir) { throw new ERR_OS_NO_HOMEDIR(); } let shell = isWindows ? (Deno.env.get("SHELL") || null) : null; let username = op_node_os_username(); if (options?.encoding === "buffer") { _homedir = _homedir ? Buffer.from(_homedir) : _homedir; shell = shell ? Buffer.from(shell) : shell; username = Buffer.from(username); } return { uid, gid, homedir: _homedir, shell, username, }; } /* Returns an estimate of the default amount of parallelism a program should use. */ export function availableParallelism(): number { return navigator.hardwareConcurrency; } export const EOL = isWindows ? "\r\n" : "\n"; export const devNull = isWindows ? "\\\\.\\nul" : "/dev/null"; export default { availableParallelism, arch, cpus, endianness, freemem, getPriority, homedir, hostname, loadavg, networkInterfaces, machine, platform, release, setPriority, tmpdir, totalmem, type, uptime, userInfo, version, constants, EOL, devNull, };