import "server-only"; import { normalizeCanvasImageTaskQueueConfig } from "./image-task-config"; const stateKey = "__unrestricted_canvas_image_models__"; type ModelState = { running: Set; durations: number[] }; function getModels() { const globalState = globalThis as typeof globalThis & { [stateKey]?: Map; }; return (globalState[stateKey] ??= new Map()); } function getModel(key: string) { const models = getModels(); const normalized = normalizeCanvasImageModelKey(key); let state = models.get(normalized); if (!state) { state = { running: new Set(), durations: [] }; models.set(normalized, state); } return state; } export function normalizeCanvasImageModelKey(value: unknown) { return typeof value === "string" && value.trim() ? value.trim() : "__default__"; } export async function getCanvasImageTaskQueueConfig() { return normalizeCanvasImageTaskQueueConfig(undefined); } export async function getCanvasImageSingleModelConcurrency() { return 0; } export async function getCanvasImageBatchDispatchIntervalMs() { return 0; } export function getCanvasImageRunningCountForModel(modelKey: string) { return getModels().get(normalizeCanvasImageModelKey(modelKey))?.running.size || 0; } export type CanvasImageModelQueueStatus = { status: "pending" | "running" | "succeeded" | "failed"; queuePosition: number; sameModelPendingCount: number; sameModelRunningCount: number; concurrencyLimit: number; estimatedWaitMs: number; source: "model_queue"; }; export async function getCanvasImageModelQueueStatus(params: { modelKey: string; }): Promise { return { status: "running", queuePosition: 0, sameModelPendingCount: 0, sameModelRunningCount: getCanvasImageRunningCountForModel(params.modelKey), concurrencyLimit: 0, estimatedWaitMs: 0, source: "model_queue", }; } export function recordCanvasImageModelExecutionDuration(modelKey: string, durationMs: number) { if (!Number.isFinite(durationMs) || durationMs <= 0) return; const state = getModel(modelKey); state.durations.push(durationMs); if (state.durations.length > 24) state.durations.shift(); } // Keep execution tracking/release semantics, without model or owner admission limits. export async function acquireCanvasImageModelSlot(params: { modelKey: string; ownerKey?: string; debugLabel?: string; debugMeta?: Record; onQueued?: (status: CanvasImageModelQueueStatus) => void | Promise; }) { const state = getModel(params.modelKey); const ticket = crypto.randomUUID(); state.running.add(ticket); return { release: async () => { state.running.delete(ticket); }, waitMs: 0, maxConcurrent: 0, batchDispatchIntervalMs: 0, }; }