Files
bare-operating-system/packages/bare-os-booter/lib/host/corestore-host-lifecycle.js
T
2026-08-18 18:11:28 -04:00

133 lines
4.9 KiB
JavaScript

import { runTransactionalLifecycleHooks } from './bare-os-lifecycle-manager.js'
/**
* Host lifecycle: when Corestore / Hyperswarm expose `suspend`/`resume`, wire them into
* `ctx.bareOsInvokeSuspendHooks` / `ctx.bareOsInvokeResumeHooks` (mobile sleep, etc.).
*/
/** @type {{ store: unknown, swarm: unknown } | null} */
let pendingPair = null
/**
* Called once from main() with live instances; hooks install on first guest ctx.
* @param {unknown} store
* @param {unknown} swarm
*/
export function bareOsRegisterCorestoreSuspendResumeHooks(store, swarm) {
pendingPair = { store, swarm }
}
/**
* Corestore 7.12+ no longer flushes on `suspend()`. Flush open sessions first
* so in-memory tree/blocks hit storage before the RocksDB handle sleeps.
* @param {unknown} store
*/
async function flushCorestoreSessions(store) {
if (!store || typeof store !== 'object') return
const sessions = /** @type {{ sessions?: Iterable<unknown> }} */ (store)
.sessions
if (!sessions || typeof sessions[Symbol.iterator] !== 'function') return
/** @type {Promise<unknown>[]} */
const pending = []
for (const sess of sessions) {
if (!sess || typeof sess !== 'object') continue
const flush = /** @type {{ flush?: () => unknown }} */ (sess).flush
if (typeof flush === 'function')
pending.push(Promise.resolve(flush.call(sess)))
}
if (pending.length) await Promise.all(pending)
}
/**
* @param {unknown} target
* @param {string} label
*/
async function callSuspendResume(target, label) {
if (!target || typeof target !== 'object') return
if (label === 'suspend') await flushCorestoreSessions(target)
const o = /** @type {{ suspend?: () => unknown, resume?: () => unknown }} */ (
target
)
const fn = label === 'suspend' ? o.suspend : o.resume
if (typeof fn !== 'function') return
await Promise.resolve(fn.call(target))
}
/**
* @param {{ bareOsRegisterSuspendHook: (fn: () => void | Promise<void>) => unknown, bareOsRegisterResumeHook: (fn: () => void | Promise<void>) => unknown }} ctx
*/
export function bareOsInstallCorestoreSuspendResumeHooks(ctx) {
if (!pendingPair) return
const { store, swarm } = pendingPair
ctx.bareOsRegisterSuspendHook(async () => {
const rep = await runTransactionalLifecycleHooks([
{
name: 'corestore.suspend',
run: () => callSuspendResume(store, 'suspend')
},
{ name: 'swarm.suspend', run: () => callSuspendResume(swarm, 'suspend') }
])
if (!rep.ok) throw new Error('bare-os suspend hook transaction failed')
})
ctx.bareOsRegisterResumeHook(async () => {
const rep = await runTransactionalLifecycleHooks([
{ name: 'swarm.resume', run: () => callSuspendResume(swarm, 'resume') },
{
name: 'corestore.resume',
run: () => callSuspendResume(store, 'resume')
}
])
if (!rep.ok) throw new Error('bare-os resume hook transaction failed')
})
}
/**
* Non-secret operator hint for integrating **`corestore-snapshot`** on the host.
* @param {unknown} store
*/
export function bareOsCorestoreSnapshotOperatorHint(store) {
const env = globalThis.process?.env
const snapRaw = String(env?.BARE_OS_CORESTORE_SNAPSHOT_JSON || '').trim()
const statsRaw = String(env?.BARE_OS_CORESTORE_STATS_JSON || '').trim()
let snapshotKeyCount = null
let statsNamespaceCount = null
if (snapRaw) {
try {
const s = JSON.parse(snapRaw)
if (s && typeof s === 'object') {
if (Array.isArray(s.handles)) snapshotKeyCount = s.handles.length
else if (Array.isArray(s.keys)) snapshotKeyCount = s.keys.length
}
} catch {
snapshotKeyCount = -1
}
}
if (statsRaw) {
try {
const st = JSON.parse(statsRaw)
if (st && typeof st === 'object' && Array.isArray(st.namespaces))
statsNamespaceCount = st.namespaces.length
} catch {
statsNamespaceCount = -1
}
}
return {
schema: 4,
note: 'Wire the holepunch corestore-snapshot package on the host; guests receive this descriptor only. Schema 4 adds recommendedWorkflow; schema 3 adds merge hints when BARE_OS_CORESTORE_SNAPSHOT_JSON and BARE_OS_CORESTORE_STATS_JSON parse.',
corestoreSnapshotPackage: 'corestore-snapshot',
recommendedWorkflow: [
'Run corestore-snapshot (holepunchto/corestore-snapshot) on the host store.',
'Export JSON into BARE_OS_CORESTORE_SNAPSHOT_JSON and pair BARE_OS_CORESTORE_STATS_JSON for operator diff UX.',
'Use replication_operator_sketch.corestoreSnapshotUxHint counts in /proc and disk.os RPC.'
],
hasLiveStore: !!(store && typeof store === 'object'),
guestSuspendResume: 'ENOTSUP',
guestSuspendResumeNote:
'Kernel guests do not call store.suspend() directly; booter wires hooks when the runtime exposes suspend/resume.',
corestoreSnapshotEnvPresent: !!snapRaw,
corestoreStatsEnvPresent: !!statsRaw,
snapshotManifestKeyCount: snapshotKeyCount,
statsNamespacesCount: statsNamespaceCount,
atMs: Date.now()
}
}