63 lines
1.4 KiB
TypeScript
63 lines
1.4 KiB
TypeScript
|
|
import { Worker, MessageChannel, receiveMessageOnPort } from "worker_threads"
|
||
|
|
import type { LoadedSkill, SkillScope } from "./types"
|
||
|
|
|
||
|
|
interface WorkerInput {
|
||
|
|
dirs: string[]
|
||
|
|
scopes: SkillScope[]
|
||
|
|
}
|
||
|
|
|
||
|
|
interface WorkerOutputSuccess {
|
||
|
|
ok: true
|
||
|
|
skills: LoadedSkill[]
|
||
|
|
}
|
||
|
|
|
||
|
|
interface WorkerOutputError {
|
||
|
|
ok: false
|
||
|
|
error: { message: string; stack?: string }
|
||
|
|
}
|
||
|
|
|
||
|
|
type WorkerOutput = WorkerOutputSuccess | WorkerOutputError
|
||
|
|
|
||
|
|
const TIMEOUT_MS = 30000
|
||
|
|
|
||
|
|
export function discoverAllSkillsBlocking(dirs: string[], scopes: SkillScope[]): LoadedSkill[] {
|
||
|
|
const signal = new Int32Array(new SharedArrayBuffer(4))
|
||
|
|
const { port1, port2 } = new MessageChannel()
|
||
|
|
|
||
|
|
const worker = new Worker(new URL("./discover-worker.ts", import.meta.url), {
|
||
|
|
workerData: { signal }
|
||
|
|
})
|
||
|
|
|
||
|
|
worker.postMessage({ port: port2 }, [port2])
|
||
|
|
|
||
|
|
const input: WorkerInput = { dirs, scopes }
|
||
|
|
port1.postMessage(input)
|
||
|
|
|
||
|
|
const waitResult = Atomics.wait(signal, 0, 0, TIMEOUT_MS)
|
||
|
|
|
||
|
|
if (waitResult === "timed-out") {
|
||
|
|
worker.terminate()
|
||
|
|
port1.close()
|
||
|
|
throw new Error(`Worker timeout after ${TIMEOUT_MS}ms`)
|
||
|
|
}
|
||
|
|
|
||
|
|
const message = receiveMessageOnPort(port1)
|
||
|
|
|
||
|
|
worker.terminate()
|
||
|
|
port1.close()
|
||
|
|
|
||
|
|
if (!message) {
|
||
|
|
throw new Error("Worker did not return result")
|
||
|
|
}
|
||
|
|
|
||
|
|
const output = message.message as WorkerOutput
|
||
|
|
|
||
|
|
if (output.ok === false) {
|
||
|
|
const error = new Error(output.error.message)
|
||
|
|
error.stack = output.error.stack
|
||
|
|
throw error
|
||
|
|
}
|
||
|
|
|
||
|
|
return output.skills
|
||
|
|
}
|