fix worker message race: wait for ready signal before posting messages

This commit is contained in:
shum
2026-02-19 09:00:36 +00:00
parent 15ef669354
commit 7fdc8eac2f
2 changed files with 24 additions and 3 deletions

View File

@@ -28,10 +28,27 @@ class WorkerBackend implements CryptoBackend {
private pending = new Map<number, PendingRequest>()
private nextId = 1
private progressCb: ((done: number, total: number) => void) | null = null
private ready: Promise<void>
constructor() {
this.worker = new Worker(new URL('./crypto.worker.ts', import.meta.url), {type: 'module'})
this.worker.onmessage = (e) => this.handleMessage(e.data)
let rejectReady: (e: Error) => void
this.ready = new Promise((resolve, reject) => {
rejectReady = reject
this.worker.onmessage = (e) => {
if (e.data?.type === 'ready') {
this.worker.onmessage = (e) => this.handleMessage(e.data)
resolve()
} else {
reject(new Error('Worker: unexpected first message'))
}
}
})
this.worker.onerror = (e) => {
rejectReady(new Error('Worker failed to load: ' + e.message))
for (const p of this.pending.values()) p.reject(new Error('Worker error: ' + e.message))
this.pending.clear()
}
}
private handleMessage(msg: {id: number, type: string, [k: string]: any}) {
@@ -49,7 +66,8 @@ class WorkerBackend implements CryptoBackend {
}
}
private send(msg: Record<string, any>, transfer?: Transferable[]): Promise<any> {
private async send(msg: Record<string, any>, transfer?: Transferable[]): Promise<any> {
await this.ready
const id = this.nextId++
return new Promise((resolve, reject) => {
this.pending.set(id, {resolve, reject})

View File

@@ -256,9 +256,9 @@ async function handleCleanup(id: number) {
// ── Message dispatch ────────────────────────────────────────────
self.onmessage = async (e: MessageEvent) => {
await initPromise
const msg = e.data
try {
await initPromise
switch (msg.type) {
case 'encrypt':
await handleEncrypt(msg.id, msg.data, msg.fileName)
@@ -302,3 +302,6 @@ const initPromise = (async () => {
await sodium.ready
await sweepStale()
})()
// Signal main thread that the worker is ready to receive messages
initPromise.then(() => self.postMessage({type: 'ready'}), () => {})