// Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { parentPort } from 'worker_threads'; import type { LoggerType } from '../types/Logging'; import * as Errors from '../types/errors'; import type { WrappedWorkerRequest, WrappedWorkerResponse, WrappedWorkerLogEntry, } from './main'; import db from './Server'; import { SqliteErrorKind, parseSqliteError } from './errors'; if (!parentPort) { throw new Error('Must run as a worker thread'); } const port = parentPort; // eslint-disable-next-line @typescript-eslint/no-explicit-any function respond(seq: number, error: Error | undefined, response?: any) { let errorKind: SqliteErrorKind | undefined; let errorString: string | undefined; if (error !== undefined) { errorKind = parseSqliteError(error); errorString = Errors.toLogFormat(error); if (errorKind === SqliteErrorKind.Corrupted) { db.runCorruptionChecks(); } } const wrappedResponse: WrappedWorkerResponse = { type: 'response', seq, error: errorString, errorKind, response, }; port.postMessage(wrappedResponse); } const log = ( level: WrappedWorkerLogEntry['level'], args: Array ): void => { const wrappedResponse: WrappedWorkerResponse = { type: 'log', level, args, }; port.postMessage(wrappedResponse); }; const logger: LoggerType = { fatal(...args: Array) { log('fatal', args); }, error(...args: Array) { log('error', args); }, warn(...args: Array) { log('warn', args); }, info(...args: Array) { log('info', args); }, debug(...args: Array) { log('debug', args); }, trace(...args: Array) { log('trace', args); }, }; port.on('message', async ({ seq, request }: WrappedWorkerRequest) => { try { if (request.type === 'init') { await db.initialize({ ...request.options, logger, }); respond(seq, undefined, undefined); return; } if (request.type === 'close') { await db.close(); respond(seq, undefined, undefined); process.exit(0); return; } if (request.type === 'removeDB') { await db.removeDB(); respond(seq, undefined, undefined); return; } if (request.type === 'sqlCall') { // eslint-disable-next-line @typescript-eslint/no-explicit-any const method = (db as any)[request.method]; if (typeof method !== 'function') { throw new Error(`Invalid sql method: ${method}`); } const start = performance.now(); const result = await method.apply(db, request.args); const end = performance.now(); respond(seq, undefined, { result, duration: end - start }); } else { throw new Error('Unexpected request type'); } } catch (error) { respond(seq, error, undefined); } });