@socketsupply/socket
Version:
A Cross-Platform, Native Runtime for Desktop and Mobile Apps — Create apps using HTML, CSS, and JavaScript. Written from the ground up to be small and maintainable.
396 lines (336 loc) • 9.73 kB
JavaScript
/**
* @module os
*
* This module provides normalized system information from all the major
* operating systems.
*
* Example usage:
* ```js
* import { arch, platform } from 'socket:os'
* ```
*/
import ipc, { primordials } from './ipc.js'
import { toProperCase } from './util.js'
import constants from './os/constants.js'
import { HOME } from './path/well-known.js'
export { constants }
const UNKNOWN = 'unknown'
// eslint-disable-next-line new-parens
const cache = new class {
type = UNKNOWN
/**
* @type {boolean}
* @ignore
*/
isWindows = false
/**
* @type {object?}
* @ignore
*/
networkInterfaces
/**
* @type {number}
* @ignore
*/
networkInterfacesTTL = 0
/**
* @type {object?}
* @ignore
*/
cpus
/**
* @type {string?}
* @ignore
*/
uname
}
/**
* Returns the operating system CPU architecture for which Socket was compiled.
* @returns {string} - 'arm64', 'ia32', 'x64', or 'unknown'
*/
export function arch () {
return primordials.arch
}
/**
* Returns an array of objects containing information about each CPU/core.
* @returns {Array<object>} cpus - An array of objects containing information about each CPU/core.
* The properties of the objects are:
* - model `<string>` - CPU model name.
* - speed `<number>` - CPU clock speed (in MHz).
* - times `<object>` - An object containing the fields user, nice, sys, idle, irq representing the number of milliseconds the CPU has spent in each mode.
* - user `<number>` - Time spent by this CPU or core in user mode.
* - nice `<number>` - Time spent by this CPU or core in user mode with low priority (nice).
* - sys `<number>` - Time spent by this CPU or core in system mode.
* - idle `<number>` - Time spent by this CPU or core in idle mode.
* - irq `<number>` - Time spent by this CPU or core in IRQ mode.
* @see {@link https://nodejs.org/api/os.html#os_os_cpus}
*/
export function cpus () {
if (!cache.cpus) {
const { err, data } = ipc.sendSync('os.cpus')
if (err) throw err
cache.cpus = data
}
return cache.cpus
}
/**
* Returns an object containing network interfaces that have been assigned a network address.
* @returns {object} - 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.
* The properties available on the assigned network address object include:
* - address `<string>` - The assigned IPv4 or IPv6 address.
* - netmask `<string>` - The IPv4 or IPv6 network mask.
* - family `<string>` - The address family ('IPv4' or 'IPv6').
* - mac `<string>` - The MAC address of the network interface.
* - internal `<boolean>` - Indicates whether the network interface is a loopback interface.
* - scopeid `<number>` - The numeric scope ID (only specified when family is 'IPv6').
* - cidr `<string>` - The CIDR notation of the interface.
* @see {@link https://nodejs.org/api/os.html#os_os_networkinterfaces}
*/
export function networkInterfaces () {
const now = Date.now()
if (cache.networkInterfaces && cache.networkInterfacesTTL > now) {
return cache.networkInterfaces
}
const interfaces = {}
const result = ipc.sendSync('os.networkInterfaces')
if (!result.data) return interfaces
const { ipv4, ipv6 } = result.data
for (const type in ipv4) {
const info = typeof ipv4[type] === 'string'
? { address: ipv4[type] }
: ipv4[type]
const { address } = info
const family = 'IPv4'
let internal = info.internal || false
let netmask = info.netmask || '255.255.255.0'
let cidr = `${address}/24`
let mac = info.mac || null
if (address === '127.0.0.1') {
internal = true
mac = '00:00:00:00:00:00'
cidr = '127.0.0.1/8'
netmask = '255.0.0.0'
}
interfaces[type] = interfaces[type] || []
interfaces[type].push({
address,
netmask,
internal,
family,
cidr,
mac
})
}
for (const type in ipv6) {
const info = typeof ipv6[type] === 'string'
? { address: ipv6[type] }
: ipv6[type]
const { address } = info
const family = 'IPv6'
let internal = info.internal || false
let netmask = internal.netmask || 'ffff:ffff:ffff:ffff::'
let cidr = `${address}/64`
let mac = info.mac || null
if (address === '::1') {
internal = true
netmask = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
cidr = '::1/128'
mac = '00:00:00:00:00:00'
}
interfaces[type] = interfaces[type] || []
interfaces[type].push({
address,
netmask,
internal,
family,
cidr,
mac
})
}
cache.networkInterfaces = interfaces
cache.networkInterfacesTTL = Date.now() + 512
return interfaces
}
/**
* Returns the operating system platform.
* @returns {string} - 'android', 'cygwin', 'freebsd', 'linux', 'darwin', 'ios', 'openbsd', 'win32', or 'unknown'
* @see {@link https://nodejs.org/api/os.html#os_os_platform}
* The returned value is equivalent to `process.platform`.
*/
export function platform () {
return primordials.platform
}
/**
* Returns the operating system name.
* @returns {string} - 'CYGWIN_NT', 'Mac', 'Darwin', 'FreeBSD', 'Linux', 'OpenBSD', 'Windows_NT', 'Win32', or 'Unknown'
* @see {@link https://nodejs.org/api/os.html#os_os_type}
*/
export function type () {
let value = 'unknown'
if (cache.type !== UNKNOWN) {
return cache.type
}
if (globalThis !== globalThis.window) {
switch (platform()) {
case 'android': return 'Linux'
case 'cygwin': return 'CYGWIN_NT'
case 'freebsd': return 'FreeBSD'
case 'linux': return 'Linux'
case 'openbsd': return 'OpenBSD'
case 'win32': return 'Windows_NT'
case 'ios': case 'mac': case 'Mac': case 'darwin': return 'Darwin'
}
}
if (globalThis === globalThis.window) {
value = primordials.platform
}
value = value.replace(/android/i, 'Linux')
value = value.replace(/ios/i, 'Darwin')
if (value !== UNKNOWN) {
value = toProperCase(value)
}
cache.type = value
return cache.type
}
/**
* @returns {boolean} - `true` if the operating system is Windows.
*/
export function isWindows () {
if (cache.isWindows) {
return cache.isWindows
}
cache.isWindows = /^win.*/i.test(type())
return cache.isWindows
}
/**
* @returns {string} - The operating system's default directory for temporary files.
*/
export function tmpdir () {
let path = ''
if (isWindows()) {
path = (
globalThis.__args.env.TEMPDIR ||
globalThis.__args.env.TMPDIR ||
globalThis.__args.env.TEMP ||
globalThis.__args.env.TMP ||
(globalThis.__args.env.SystemRoot ?? globalThis.__args.env.windir ?? '') + '\\temp'
)
if (path.length > 1 && path.endsWith('\\') && !path.endsWith(':\\')) {
path = path.slice(0, -1)
}
} else {
path = (
globalThis.__args.env.TEMPDIR ||
globalThis.__args.env.TMPDIR ||
globalThis.__args.env.TEMP ||
globalThis.__args.env.TMP ||
''
)
// derive default
if (!path) {
if (platform() === 'ios') {
// @TODO(jwerle): use a path module
path = [primordials.cwd, 'tmp'].join('/')
} else if (platform() === 'android') {
path = '/data/local/tmp'
} else {
path = '/tmp'
}
}
if (path.length > 1 && path.endsWith('/')) {
path = path.slice(0, -1)
}
}
return path
}
/**
* @type {string}
* The operating system's end-of-line marker. `'\r\n'` on Windows and `'\n'` on POSIX.
*/
export const EOL = (() => {
if (isWindows()) {
return '\r\n'
}
return '\n'
})()
// FIXME: should be process.resourceUsage()
/**
* Get resource usage.
*/
export function rusage () {
const { err, data } = ipc.sendSync('os.rusage')
if (err) throw err
return data
}
/**
* Returns the system uptime in seconds.
* @returns {number} - The system uptime in seconds.
*/
export function uptime () {
const { err, data } = ipc.sendSync('os.uptime')
if (err) throw err
return data
}
// FIXME: should be os.machine() + os.release() + os.type() + os.version()
/**
* Returns the operating system name.
* @returns {string} - The operating system name.
*/
export function uname () {
if (!cache.uname) {
const { err, data } = ipc.sendSync('os.uname')
if (err) throw err
cache.uname = data
}
return cache.uname
}
/**
* It's implemented in process.hrtime.bigint()
* @ignore
*/
export function hrtime () {
const result = ipc.sendSync('os.hrtime', {}, {
desiredResponseType: 'arraybuffer'
})
if (result.err) throw result.err
return result.data.readBigUInt64BE(0)
}
/**
* Node.js doesn't have this method.
* @ignore
*/
export function availableMemory () {
const result = ipc.sendSync('os.availableMemory', {}, {
desiredResponseType: 'arraybuffer'
})
if (result.err) throw result.err
return result.data.readBigUInt64BE(0)
}
/**
* The host operating system. This value can be one of:
* - android
* - android-emulator
* - iphoneos
* - iphone-simulator
* - linux
* - macosx
* - unix
* - unknown
* - win32
* @ignore
* @return {'android'|'android-emulator'|'iphoneos'|iphone-simulator'|'linux'|'macosx'|unix'|unknown'|win32'}
*/
export function host () {
return primordials['host-operating-system'] || 'unknown'
}
/**
* Returns the home directory of the current user.
* @return {string}
*/
export function homedir () {
return globalThis.__args.env.HOME ?? HOME ?? ''
}
// eslint-disable-next-line
import * as exports from './os.js'
export default exports