/** * Idempotent managed Holesail entry for the stock www static server port. */ import { bareHolesailEnvTruthy } from '../p2p/bare-holesail-env.js' import { bareHolesailManagedEnsureServerSeedPersisted, bareHolesailManagedGenerateSeedHex, bareHolesailManagedReadState, bareHolesailManagedRuntimeRunning, bareHolesailManagedServiceIsRunning, bareHolesailManagedStartOne, bareHolesailManagedStopOne, bareHolesailManagedWriteState } from '../p2p/bare-holesail-managed.js' export const BARE_OS_WWW_HOLESAIL_CONNECTION_ID_PREFIX = 'bare-www-' /** * @param {Record} env * @param {number} port */ export function bareOsWwwHolesailConnectionId(port) { return `${BARE_OS_WWW_HOLESAIL_CONNECTION_ID_PREFIX}${port}` } /** * Pick one persisted WWW holesail entry to reuse and return any duplicates to prune. * @param {{ connections: Record }} state * @param {number} port */ function bareOsWwwResolveManagedIdentity(state, port) { const exactId = bareOsWwwHolesailConnectionId(port) const allIds = Object.keys(state.connections).filter((id) => id.startsWith(BARE_OS_WWW_HOLESAIL_CONNECTION_ID_PREFIX) ) if (allIds.includes(exactId)) { return { id: exactId, staleIds: allIds.filter((id) => id !== exactId) } } if (allIds.length === 0) return { id: exactId, staleIds: [] } const idsSorted = allIds.sort() return { id: idsSorted[0], staleIds: idsSorted.slice(1) } } /** * @param {Record} env */ export function bareOsWwwHolesailAutoEnabled(env) { const v = env.BARE_OS_WWW_HOLESAIL if (v === '0' || v === 'false') return false return true } /** * Persist a managed server tunnel for `port` and start it if bare-holesail is already active. * @param {Record} ctx * @param {Record} env * @param {number} port */ export async function ensureBareOsWwwHolesailTunnel(ctx, env, port) { if (!bareOsWwwHolesailAutoEnabled(env)) return const p = Number.isFinite(port) && port > 0 && port < 65536 ? Math.floor(port) : 8088 const vfs = ctx.vfs if (!vfs || typeof vfs.readFile !== 'function' || typeof vfs.writeFile !== 'function') { return } if (!ctx.b4a || typeof ctx.b4a.from !== 'function') return const { path, state } = await bareHolesailManagedReadState( ctx, /** @type {Record} */ (env) ) const { id, staleIds } = bareOsWwwResolveManagedIdentity(state, p) /** Holesail server mode requires an explicit loopback host. */ const wantHost = '127.0.0.1' /** @type {Record} */ const want = { server: true, port: p, host: wantHost, enabled: true } const existing = state.connections[id] let shouldRestartRuntime = false if (existing && typeof existing === 'object') { const ex = /** @type {Record} */ (existing) const curPort = Number.parseInt(String(ex.port ?? ''), 10) const server = bareHolesailEnvTruthy(ex.server) const enabled = ex.enabled === undefined || ex.enabled === null || String(ex.enabled) === '' ? true : bareHolesailEnvTruthy(ex.enabled) const rawHost = String(ex.host ?? '').trim() const hostOk = rawHost === wantHost shouldRestartRuntime = !(curPort === p && hostOk && server && enabled) if (server && curPort === p && enabled && hostOk) { await bareHolesailManagedEnsureServerSeedPersisted( ctx, /** @type {Record} */ (env), id ) if ( bareHolesailManagedServiceIsRunning() && !bareHolesailManagedRuntimeRunning(id) ) { try { await bareHolesailManagedStartOne( ctx, /** @type {Record} */ (env), id ) } catch { /* may already run */ } } return } } /** @type {Record} */ const next = { ...want } if (existing && typeof existing === 'object') { const ex = /** @type {Record} */ (existing) const k = String(ex.key ?? '').trim() if (k) next.key = k const s = String(ex.seed ?? '').trim() if (s) next.seed = s } const legacyHsOnly = /^hs:\/\//i.test(String(next.key ?? '').trim()) && !String(next.seed ?? '').trim() if (!legacyHsOnly && !String(next.seed ?? '').trim()) { next.seed = bareHolesailManagedGenerateSeedHex() } state.connections[id] = next for (const staleId of staleIds) delete state.connections[staleId] await bareHolesailManagedWriteState( ctx, /** @type {Record} */ (env), state ) await bareHolesailManagedEnsureServerSeedPersisted( ctx, /** @type {Record} */ (env), id ) void path if (shouldRestartRuntime && bareHolesailManagedRuntimeRunning(id)) { try { await bareHolesailManagedStopOne(ctx, id) } catch { /* ignore */ } } for (const staleId of staleIds) { if (bareHolesailManagedRuntimeRunning(staleId)) { try { await bareHolesailManagedStopOne(ctx, staleId) } catch { /* ignore */ } } } if ( bareHolesailManagedServiceIsRunning() && !bareHolesailManagedRuntimeRunning(id) ) { try { await bareHolesailManagedStartOne( ctx, /** @type {Record} */ (env), id ) } catch (e) { try { ctx.console?.error?.( `[bare-os-www] holesail start ${id}: ${(e && /** @type {{ message?: string }} */ (e).message) || String(e)}` ) } catch { /* ignore */ } } } }