Files
bare-operating-system/packages/bare-os-booter/lib/bare-holesail.js
T

337 lines
9.1 KiB
JavaScript

/**
* bare-holesail — Holesail TCP/UDP P2P proxy via the official holesail package API only.
* Initd unit `bare-holesail` (stock-on managed mode; disable via env/initd) and optional early booter instance (kernel-path).
*
* Upstream is AGPL-3.0; the booter imports `holesail` directly (same Pear-staged pattern as
* bare-openssh / bare-ssh2) instead of depending on ctx.bare / drive-bundle resolution.
*/
import { appendVarLog, BARE_OS_VAR_LOG_DIR } from './bare-os-var-log.js'
import { bareHolesailEnvTruthy } from './bare-holesail-env.js'
import {
bareHolesailManagedServiceIsRunning,
bareHolesailManagedStartService,
bareHolesailManagedStopService
} from './bare-holesail-managed.js'
import { loadHolesailConstructor } from './bare-holesail-loader.js'
import {
registerBareInitdDisposer,
registerBareService,
registerKernelShutdownHook
} from './bare-initd.js'
export { bareHolesailEnvTruthy }
export const BARE_HOLESAIL_LOG = `${BARE_OS_VAR_LOG_DIR}/holesail.log`
/** @type {unknown} */
let kernelHolesail = null
/** @type {unknown} */
let initdHolesail = null
/** @type {(() => void)[]} */
let initdHookUnsubs = []
/** @type {(() => void)[]} */
let kernelHookUnsubs = []
/**
* @param {Record<string, string | undefined>} env
* @param {string} key
*/
function envStr(env, key) {
const v = env[key]
if (v === undefined || v === null) return ''
return String(v).trim()
}
/**
* @param {Record<string, string | undefined>} env
* @param {'initd' | 'kernel'} profile
* @returns {{ enabled: boolean, err?: string, opts?: Record<string, unknown> }}
*/
export function bareHolesailParseConfig(env, profile) {
const isKernel = profile === 'kernel'
const enabled = isKernel
? bareHolesailEnvTruthy(env.BARE_OS_HOLESAIL_KERNEL)
: bareHolesailEnvTruthy(env.BARE_OS_HOLESAIL_INITD)
if (!enabled) return { enabled: false }
const P = isKernel ? 'BARE_OS_HOLESAIL_KERNEL_' : 'BARE_OS_HOLESAIL_'
const server = bareHolesailEnvTruthy(env[`${P}SERVER`])
const client = bareHolesailEnvTruthy(env[`${P}CLIENT`])
if (server === client) {
return {
enabled: true,
err: 'holesail: set exactly one of SERVER or CLIENT for this profile'
}
}
const key = envStr(env, `${P}KEY`)
if (client && !key) {
return { enabled: true, err: 'holesail: CLIENT requires KEY' }
}
/** @type {Record<string, unknown>} */
const opts = {
server,
client,
key: key || undefined
}
const sec = envStr(env, `${P}SECURE`)
if (sec !== '') opts.secure = bareHolesailEnvTruthy(sec)
const portRaw = envStr(env, `${P}PORT`)
if (portRaw !== '') {
const n = Number.parseInt(portRaw, 10)
if (!Number.isFinite(n)) {
return { enabled: true, err: 'holesail: invalid PORT' }
}
opts.port = n
}
const host = envStr(env, `${P}HOST`)
if (host !== '') opts.host = host
const udp = envStr(env, `${P}UDP`)
if (udp !== '') opts.udp = bareHolesailEnvTruthy(udp)
const logRaw = envStr(env, `${P}LOG`)
if (logRaw !== '') {
if (/^\d+$/.test(logRaw)) opts.log = Number.parseInt(logRaw, 10)
else opts.log = bareHolesailEnvTruthy(logRaw)
}
return { enabled: true, opts }
}
/**
* @param {Record<string, unknown>} ctx
* @param {string} line
*/
function logLine(ctx, line) {
void appendVarLog(ctx, BARE_HOLESAIL_LOG, 'holesail', line)
}
/**
* @param {Record<string, unknown>} ctx
* @param {Record<string, string | undefined>} env
*/
function debugEnabled(ctx, env) {
return bareHolesailEnvTruthy(env.BARE_OS_HOLESAIL_DEBUG)
}
/**
* @param {unknown} hs
*/
async function safeCloseHolesail(hs) {
if (!hs || typeof hs.close !== 'function') return
try {
await hs.close()
} catch {
/* ignore */
}
}
/**
* Optional early booter instance: runs after ctx is wired (repl phase), before bare-initd.
* Env: BARE_OS_HOLESAIL_KERNEL=1 and BARE_OS_HOLESAIL_KERNEL_SERVER|CLIENT, etc.
*
* @param {Record<string, unknown>} ctx
*/
export async function maybeStartBareHolesailKernelFromBooter(ctx) {
const env =
ctx.env && typeof ctx.env === 'object'
? /** @type {Record<string, string | undefined>} */ (ctx.env)
: /** @type {Record<string, string | undefined>} */ ({})
const parsed = bareHolesailParseConfig(env, 'kernel')
if (!parsed.enabled) return
if (parsed.err) {
logLine(ctx, `kernel: ${parsed.err}`)
try {
ctx.console?.error?.(`[bare-holesail] ${parsed.err}`)
} catch {
/* ignore */
}
return
}
if (!parsed.opts) return
try {
const Holesail = await loadHolesailConstructor(ctx)
const hs = new Holesail(parsed.opts)
await hs.ready()
kernelHolesail = hs
logLine(ctx, 'kernel: ready (early booter instance)')
if (debugEnabled(ctx, env)) {
try {
const info = hs.info
const url = info && typeof info === 'object' ? info.url : ''
ctx.console?.log?.(`[bare-holesail] kernel url=${String(url).slice(0, 120)}`)
} catch {
/* ignore */
}
}
kernelHookUnsubs.push(
ctx.bareOsRegisterSuspendHook(async () => {
if (kernelHolesail && typeof kernelHolesail.pause === 'function') {
try {
await kernelHolesail.pause()
} catch {
/* ignore */
}
}
})
)
kernelHookUnsubs.push(
ctx.bareOsRegisterResumeHook(async () => {
if (kernelHolesail && typeof kernelHolesail.resume === 'function') {
try {
await kernelHolesail.resume()
} catch {
/* ignore */
}
}
})
)
registerKernelShutdownHook(async () => {
for (const u of kernelHookUnsubs.splice(0)) {
try {
u()
} catch {
/* ignore */
}
}
const h = kernelHolesail
kernelHolesail = null
await safeCloseHolesail(h)
logLine(ctx, 'kernel: closed (session shutdown)')
})
} catch (e) {
const msg = (e && /** @type {{ message?: string }} */ (e).message) || String(e)
logLine(ctx, `kernel: start error: ${msg}`)
try {
ctx.console?.error?.(`[bare-holesail] kernel: ${msg}`)
} catch {
/* ignore */
}
}
}
async function initdStartBareHolesail(ctx) {
const env =
ctx.env && typeof ctx.env === 'object'
? /** @type {Record<string, string | undefined>} */ (ctx.env)
: /** @type {Record<string, string | undefined>} */ ({})
const initdOn = bareHolesailEnvTruthy(env.BARE_OS_HOLESAIL_INITD)
const managedOn = bareHolesailEnvTruthy(env.BARE_OS_HOLESAIL_MANAGED)
if (initdOn && managedOn) {
try {
await bareHolesailManagedStartService(ctx, env)
} catch (e) {
const msg = (e && /** @type {{ message?: string }} */ (e).message) || String(e)
logLine(ctx, `initd managed: start error: ${msg}`)
throw e
}
return
}
const parsed = bareHolesailParseConfig(env, 'initd')
if (!parsed.enabled) return
if (parsed.err) {
logLine(ctx, `initd: ${parsed.err}`)
throw new Error(parsed.err)
}
if (!parsed.opts) return
try {
const Holesail = await loadHolesailConstructor(ctx)
const hs = new Holesail(parsed.opts)
await hs.ready()
initdHolesail = hs
logLine(ctx, 'initd: ready')
if (debugEnabled(ctx, env)) {
try {
const info = hs.info
const url = info && typeof info === 'object' ? info.url : ''
ctx.console?.log?.(`[bare-holesail] initd url=${String(url).slice(0, 120)}`)
} catch {
/* ignore */
}
}
initdHookUnsubs.push(
ctx.bareOsRegisterSuspendHook(async () => {
if (initdHolesail && typeof initdHolesail.pause === 'function') {
try {
await initdHolesail.pause()
} catch {
/* ignore */
}
}
})
)
initdHookUnsubs.push(
ctx.bareOsRegisterResumeHook(async () => {
if (initdHolesail && typeof initdHolesail.resume === 'function') {
try {
await initdHolesail.resume()
} catch {
/* ignore */
}
}
})
)
} catch (e) {
const msg = (e && /** @type {{ message?: string }} */ (e).message) || String(e)
logLine(ctx, `initd: start error: ${msg}`)
throw e
}
}
async function initdStopBareHolesail(ctx) {
if (bareHolesailManagedServiceIsRunning()) {
await bareHolesailManagedStopService(ctx)
logLine(ctx, 'initd: stopped (managed)')
return
}
for (const u of initdHookUnsubs.splice(0)) {
try {
u()
} catch {
/* ignore */
}
}
const h = initdHolesail
initdHolesail = null
await safeCloseHolesail(h)
logLine(ctx, 'initd: stopped')
}
registerBareInitdDisposer(() => {
if (bareHolesailManagedServiceIsRunning()) {
void bareHolesailManagedStopService({})
return
}
for (const u of initdHookUnsubs.splice(0)) {
try {
u()
} catch {
/* ignore */
}
}
const h = initdHolesail
initdHolesail = null
void safeCloseHolesail(h)
})
registerBareService({
name: 'bare-holesail',
description:
'Holesail P2P TCP/UDP proxy (official holesail API); on by default (managed multi-tunnel for /bin/holesail); disable with BARE_OS_HOLESAIL_INITD=0 or systemctl disable',
logPath: BARE_HOLESAIL_LOG,
start: initdStartBareHolesail,
stop: initdStopBareHolesail
})