import {DetectTaskHandler} from './tasks/DetectTaskHandler'; import {DescribeTaskHandler} from './tasks/DescribeTaskHandler'; import {AbstractModelTaskHandler} from './tasks/AbstractModelTaskHandler'; import type { ClusterTaskHandlerOptions, ClusterTaskHostContext, ClusterTaskKind, HostTaskMessage, } from './tasks/types'; export type {ClusterTaskKind, HostTaskMessage, ClusterTaskHandlerOptions} from './tasks/types'; export class ClusterTaskHandler { private readonly taskQueue: HostTaskMessage[] = []; private processing = false; private readonly host: ClusterTaskHostContext; private readonly handlers: Map; constructor(options: ClusterTaskHandlerOptions) { this.host = { apiBase: options.apiBase, getSelectedModelId: options.getSelectedModelId, setStatus: options.setStatus, }; this.handlers = new Map([ ['detect', new DetectTaskHandler(this.host, options.getDetector)], ['describe', new DescribeTaskHandler(this.host, options.getDescriber)], ]); } enqueueTask(task: HostTaskMessage): void { this.taskQueue.push(task); void this.drainTaskQueue(); } parseIncomingTask( raw: HostTaskMessage & {kind?: ClusterTaskKind}, defaultKind: ClusterTaskKind, ): HostTaskMessage { return { ...raw, kind: raw.kind ?? defaultKind, }; } private async drainTaskQueue(): Promise { if (this.processing || this.taskQueue.length === 0) { return; } const task = this.taskQueue.shift(); if (task) { await this.processTask(task); } } private async processTask(task: HostTaskMessage): Promise { const handler = this.handlers.get(task.kind); if (!handler) { throw new Error(`No handler for task kind '${task.kind}'`); } this.processing = true; this.host.setStatus(`Processing task ${task.id.slice(0, 8)}…`); try { await handler.process(task); this.host.setStatus(`Task ${task.id.slice(0, 8)} complete. Waiting for requests…`); } catch (error) { const message = error instanceof Error ? error.message : String(error); this.host.setStatus(`Task failed: ${message}`); } finally { this.processing = false; void this.drainTaskQueue(); } } }