import { MessageChannel, Worker } from 'node:worker_threads';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export class DbWorker {
    constructor(address, db, onExit, workerName) {
        const { port1, port2 } = new MessageChannel();
        this.db = db;
        this.channel = port1;
        this.worker = new Worker(join(__dirname, workerName), {
            workerData: {
                isDbWorker: true,
                channel: port2,
                address,
            },
            transferList: [port2],
        });
        this.readyPromise = new Promise((resolve) => {
            const onReady = (msg) => {
                if (msg === 'READY') {
                    this.worker.off('message', onReady);
                    resolve(true);
                }
            };
            this.worker.on('message', onReady);
        });
        this.worker.on('error', (err) => {
            console.error('error in query worker:', err);
            this.worker.terminate().catch((err) => {
                console.error('error terminating query worker:', err);
            });
        });
        this.worker.on('exit', (code) => {
            if (!this.db.stopped) {
                console.info('unexpected exit query worker with code:', code);
                const err = new Error('Worker could not process query');
                for (const resolve of this.resolvers) {
                    resolve(err);
                }
                this.resolvers = [];
                onExit(code);
            }
        });
        this.channel.on('message', (buf) => {
            this.resolvers.shift()(new Uint8Array(buf));
            this.handleMsg(buf);
        });
    }
    db;
    channel;
    worker;
    resolvers = [];
    readyPromise;
    async terminate() {
        // TODO do we want to force this.worker.terminate() after a timeout?
        await this.call(0n);
    }
    callback = (resolve) => {
        this.resolvers.push(resolve);
    };
    /**
     * Send msg to the worker thread and return a promise to the response.
     */
    call(msg) {
        this.channel.postMessage(msg);
        return new Promise(this.callback);
    }
    updateCtx(address) {
        return this.call(address);
    }
}
//# sourceMappingURL=DbWorker.js.map