import { AiApiError, AiErrorCodes } from './AiError'; interface Waiter { resolve(release: () => void): void; reject(error: unknown): void; signal?: AbortSignal; onAbort?: () => void; } export class AiSemaphore { private readonly waiters: Waiter[] = []; private active = 0; constructor( private readonly capacity: number, private readonly maxQueue = capacity, ) { if (!Number.isInteger(capacity) || capacity < 1) { throw new RangeError('AI semaphore capacity must be a positive integer'); } if (!Number.isInteger(maxQueue) || maxQueue < 0) { throw new RangeError('AI semaphore queue limit must be a non-negative integer'); } } async acquire(signal?: AbortSignal): Promise<() => void> { signal?.throwIfAborted(); if (this.active < this.capacity) { this.active += 1; return this.createRelease(); } if (this.waiters.length >= this.maxQueue) { throw new AiApiError(AiErrorCodes.AI_RATE_LIMITED, 'AI 服务繁忙,请稍后重试'); } return new Promise<() => void>((resolve, reject) => { const waiter: Waiter = { resolve, reject, signal }; if (signal) { waiter.onAbort = () => { const index = this.waiters.indexOf(waiter); if (index >= 0) { this.waiters.splice(index, 1); } reject(signal.reason); }; signal.addEventListener('abort', waiter.onAbort, { once: true }); } this.waiters.push(waiter); }); } async run(operation: () => Promise, signal?: AbortSignal): Promise { const release = await this.acquire(signal); try { return await operation(); } finally { release(); } } private createRelease(): () => void { let released = false; return () => { if (released) { return; } released = true; this.releaseNext(); }; } private releaseNext(): void { const waiter = this.waiters.shift(); if (!waiter) { this.active -= 1; return; } if (waiter.signal && waiter.onAbort) { waiter.signal.removeEventListener('abort', waiter.onAbort); } waiter.resolve(this.createRelease()); } }