164 lines
4.5 KiB
JavaScript
164 lines
4.5 KiB
JavaScript
/**
|
|
* Build `/proc/bare_os/host_os.json` text (Holepunch `bare-os`-shaped snapshot).
|
|
*
|
|
* Always uses the **`bare-os`** package (ESM on Node and Bare). On Bare, **`bare-module`**
|
|
* `createRequire` is used when needed; there is no `node:os` / `node:module` path.
|
|
*/
|
|
|
|
/**
|
|
* @param {Record<string, string>} env
|
|
* @returns {Promise<string>}
|
|
*/
|
|
export async function buildBareOsHostProcJsonText(env) {
|
|
const rawInject = String(env.BARE_OS_HOST_OS_JSON || '').trim()
|
|
if (rawInject) {
|
|
try {
|
|
const parsed = JSON.parse(rawInject)
|
|
return `${JSON.stringify({
|
|
schema: 1,
|
|
source: 'BARE_OS_HOST_OS_JSON',
|
|
host: parsed,
|
|
atMs: Date.now()
|
|
})}\n`
|
|
} catch {
|
|
return `${JSON.stringify({
|
|
schema: 1,
|
|
error: 'invalid BARE_OS_HOST_OS_JSON',
|
|
atMs: Date.now()
|
|
})}\n`
|
|
}
|
|
}
|
|
const probe =
|
|
env.BARE_OS_HOST_BARE_OS_PROC === '1' ||
|
|
env.BARE_OS_HOST_BARE_OS_PROC === 'true'
|
|
if (!probe) {
|
|
return `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'Set BARE_OS_HOST_BARE_OS_PROC=1 or inject BARE_OS_HOST_OS_JSON.',
|
|
atMs: Date.now()
|
|
})}\n`
|
|
}
|
|
try {
|
|
let os
|
|
if (typeof Bare !== 'undefined') {
|
|
const bm = await import('bare-module')
|
|
const createRequire = bm.createRequire || bm.default?.createRequire
|
|
if (typeof createRequire !== 'function') {
|
|
throw new Error('bare-module createRequire unavailable')
|
|
}
|
|
const _require = createRequire(import.meta.url)
|
|
os = _require('bare-os')
|
|
} else {
|
|
const m = await import('bare-os')
|
|
os = m.default ?? m
|
|
}
|
|
const payload = hostPayloadFromBareOsLike(os, 'bare-os')
|
|
try {
|
|
const px = await import('bare-posix')
|
|
const posix = px.default ?? px
|
|
if (posix && typeof posix === 'object') {
|
|
const groups = callOs(posix, 'getgroups')
|
|
payload.host.posix = {
|
|
uid: callOs(posix, 'getuid'),
|
|
euid: callOs(posix, 'geteuid'),
|
|
gid: callOs(posix, 'getgid'),
|
|
egid: callOs(posix, 'getegid'),
|
|
groupCount: Array.isArray(groups) ? groups.length : null
|
|
}
|
|
}
|
|
} catch {
|
|
/* optional native addon */
|
|
}
|
|
return `${JSON.stringify(payload)}\n`
|
|
} catch {
|
|
return `${JSON.stringify({
|
|
schema: 1,
|
|
note: 'Host OS probe failed; use BARE_OS_HOST_OS_JSON on this runtime.',
|
|
atMs: Date.now()
|
|
})}\n`
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Record<string, unknown>} os
|
|
* @param {string} source
|
|
*/
|
|
function callOs(os, name, ...args) {
|
|
if (typeof os[name] !== 'function') return null
|
|
try {
|
|
return os[name](...args)
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
function hostPayloadFromBareOsLike(os, source) {
|
|
const snap = {
|
|
platform: callOs(os, 'platform'),
|
|
arch: callOs(os, 'arch'),
|
|
hostname: callOs(os, 'hostname'),
|
|
release: callOs(os, 'release'),
|
|
type: callOs(os, 'type'),
|
|
machine: callOs(os, 'machine'),
|
|
endianness: callOs(os, 'endianness'),
|
|
availableParallelism: callOs(os, 'availableParallelism'),
|
|
freemem: callOs(os, 'freemem'),
|
|
totalmem: callOs(os, 'totalmem'),
|
|
availableMemory: callOs(os, 'availableMemory'),
|
|
constrainedMemory: callOs(os, 'constrainedMemory')
|
|
}
|
|
const user = callOs(os, 'userInfo')
|
|
if (user && typeof user === 'object') {
|
|
snap.user = {
|
|
uid: user.uid ?? null,
|
|
gid: user.gid ?? null,
|
|
username: user.username ?? null
|
|
}
|
|
}
|
|
const group = callOs(os, 'groupInfo')
|
|
if (group && typeof group === 'object') {
|
|
snap.group = {
|
|
gid: group.gid ?? null,
|
|
groupname: group.groupname ?? null,
|
|
memberCount: Array.isArray(group.members) ? group.members.length : null
|
|
}
|
|
}
|
|
const cpu = callOs(os, 'cpuUsage')
|
|
if (cpu && typeof cpu === 'object') {
|
|
snap.cpuUsage = {
|
|
user: cpu.user ?? null,
|
|
system: cpu.system ?? null
|
|
}
|
|
}
|
|
const ru = callOs(os, 'resourceUsage')
|
|
if (ru && typeof ru === 'object') {
|
|
snap.resourceUsage = {
|
|
userCPUTime: ru.userCPUTime ?? null,
|
|
systemCPUTime: ru.systemCPUTime ?? null,
|
|
maxRSS: ru.maxRSS ?? null
|
|
}
|
|
}
|
|
let ifaces = null
|
|
try {
|
|
if (typeof os.networkInterfaces === 'function') {
|
|
const n = os.networkInterfaces()
|
|
if (n && typeof n === 'object') {
|
|
ifaces = Object.keys(n)
|
|
.slice(0, 32)
|
|
.map((name) => ({
|
|
name,
|
|
count: Array.isArray(n[name]) ? n[name].length : 0
|
|
}))
|
|
}
|
|
}
|
|
} catch {
|
|
ifaces = null
|
|
}
|
|
return {
|
|
schema: 2,
|
|
source,
|
|
host: { ...snap, networkInterfaceNames: ifaces },
|
|
atMs: Date.now()
|
|
}
|
|
}
|