mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-09 04:02:35 +00:00
76 lines
2.2 KiB
JavaScript
76 lines
2.2 KiB
JavaScript
/** Shared lifecycle for snapshot HTTP fixtures that bind an ephemeral loopback port. */
|
|
import { createServer } from 'node:http'
|
|
|
|
function listen(server) {
|
|
return new Promise((resolve, reject) => {
|
|
const onError = (error) => {
|
|
server.off('error', onError)
|
|
reject(error)
|
|
}
|
|
server.once('error', onError)
|
|
try {
|
|
server.listen(0, '127.0.0.1', () => {
|
|
server.off('error', onError)
|
|
resolve(undefined)
|
|
})
|
|
} catch (error) {
|
|
server.off('error', onError)
|
|
reject(error)
|
|
}
|
|
})
|
|
}
|
|
|
|
async function close(server) {
|
|
if (!server.listening) return
|
|
await new Promise((resolve, reject) => {
|
|
server.close(error => error ? reject(error) : resolve(undefined))
|
|
server.closeAllConnections()
|
|
})
|
|
}
|
|
|
|
async function cleanup(server, onCleanup, label) {
|
|
const errors = []
|
|
try {
|
|
onCleanup()
|
|
} catch (error) {
|
|
errors.push(error)
|
|
}
|
|
try {
|
|
await close(server)
|
|
} catch (error) {
|
|
errors.push(error)
|
|
}
|
|
if (errors.length === 1) throw errors[0]
|
|
if (errors.length > 1) throw new AggregateError(errors, `${label}: cleanup failed`)
|
|
}
|
|
|
|
/**
|
|
* Start a loopback server as a Cordis effect and join cleanup with its setup.
|
|
* @param ctx - Cordis context that owns the listener effect.
|
|
* @param options - Fixture callbacks and the effect label used in diagnostics.
|
|
*/
|
|
export async function applyLoopbackServerEffect(ctx, options) {
|
|
const { label, onCleanup, onListening, requestListener } = options
|
|
await ctx.effect(async () => {
|
|
const server = createServer(requestListener)
|
|
try {
|
|
await listen(server)
|
|
const address = server.address()
|
|
if (address === null || typeof address === 'string') {
|
|
throw new Error(`${label}: loopback listener has no TCP address`)
|
|
}
|
|
onListening(address)
|
|
// Snapshot fixtures must never hold the process open past protocol shutdown.
|
|
server.unref()
|
|
return () => cleanup(server, onCleanup, label)
|
|
} catch (cause) {
|
|
try {
|
|
await cleanup(server, onCleanup, label)
|
|
} catch (cleanupError) {
|
|
throw new AggregateError([cause, cleanupError], `${label}: setup and cleanup failed`)
|
|
}
|
|
throw cause
|
|
}
|
|
}, label)
|
|
}
|