118 lines
3.2 KiB
JavaScript
118 lines
3.2 KiB
JavaScript
'use strict'
|
|
/**
|
|
* Optional bare-worker thread for heavy `/bin` utilities when
|
|
* `BARE_OS_BIN_WORKER_OFFLOAD=1` (Bare runtime only; Node falls back to in-process).
|
|
*/
|
|
const Worker = require('bare-worker')
|
|
|
|
if (Worker.isMainThread) {
|
|
/**
|
|
* @param {{ source: string, argv: string[] }} workerData
|
|
* @param {{ maxWasmMs?: number }} [opts]
|
|
* @returns {Promise<Record<string, unknown> | null>}
|
|
*/
|
|
exports.runBinOffloaded = function runBinOffloaded(workerData, opts) {
|
|
const raw =
|
|
opts &&
|
|
typeof opts.maxWasmMs === 'number' &&
|
|
Number.isFinite(opts.maxWasmMs) &&
|
|
opts.maxWasmMs > 0
|
|
? Math.floor(opts.maxWasmMs)
|
|
: 0
|
|
const maxWasmMs = raw > 0 ? Math.min(raw, 3_600_000) : 0
|
|
return new Promise((resolve) => {
|
|
let w
|
|
let done = false
|
|
/** @type {ReturnType<typeof setTimeout> | null} */
|
|
let timer = null
|
|
const finish = (msg) => {
|
|
if (done) return
|
|
done = true
|
|
if (timer) clearTimeout(timer)
|
|
resolve(msg)
|
|
}
|
|
try {
|
|
w = new Worker(__filename, { workerData })
|
|
} catch {
|
|
finish(null)
|
|
return
|
|
}
|
|
if (maxWasmMs > 0) {
|
|
timer = setTimeout(() => {
|
|
try {
|
|
w.terminate()
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
finish({ ok: false, reason: 'wasm_time_budget', error: 'worker terminated by wasm budget' })
|
|
}, maxWasmMs)
|
|
}
|
|
w.on('message', (msg) => finish(msg))
|
|
w.on('error', (err) =>
|
|
finish({
|
|
ok: false,
|
|
reason: 'worker_error',
|
|
error: err && err.message ? err.message : String(err)
|
|
})
|
|
)
|
|
})
|
|
}
|
|
} else {
|
|
const { source, argv } = Worker.workerData || {}
|
|
;(async () => {
|
|
try {
|
|
const AsyncFunction = Object.getPrototypeOf(async function () {})
|
|
.constructor
|
|
/** @type {string[]} */
|
|
const logs = []
|
|
/** @type {string[]} */
|
|
const errs = []
|
|
const MAX_LINES = 2000
|
|
let droppedLogs = 0
|
|
let droppedErrs = 0
|
|
const ctx = {
|
|
exitCode: 0,
|
|
console: {
|
|
log: (...a) => {
|
|
if (logs.length >= MAX_LINES) {
|
|
droppedLogs++
|
|
return
|
|
}
|
|
logs.push(a.map(String).join(' '))
|
|
},
|
|
error: (...a) => {
|
|
if (errs.length >= MAX_LINES) {
|
|
droppedErrs++
|
|
return
|
|
}
|
|
errs.push(a.map(String).join(' '))
|
|
}
|
|
}
|
|
}
|
|
const raw = typeof source === 'string' ? source : ''
|
|
const body = raw.startsWith('#!') ? raw.replace(/^#[^\n]*\n/, '') : raw
|
|
const fn = new AsyncFunction(
|
|
'ctx',
|
|
'argv',
|
|
`${body}\nif (typeof run === 'function') await run(ctx, argv)\n`
|
|
)
|
|
await fn(ctx, Array.isArray(argv) ? argv : [])
|
|
Worker.parentPort.postMessage({
|
|
ok: true,
|
|
exitCode:
|
|
ctx.exitCode != null ? Number(ctx.exitCode) || 0 : 0,
|
|
logs,
|
|
errs,
|
|
droppedLogs,
|
|
droppedErrs
|
|
})
|
|
} catch (e) {
|
|
Worker.parentPort.postMessage({
|
|
ok: false,
|
|
reason: 'worker_runtime_error',
|
|
error: e && e.message ? e.message : String(e)
|
|
})
|
|
}
|
|
})()
|
|
}
|