import { v4 as uuidv4 } from 'uuid';
import { FigmaCommand, CommandType, CommandResult } from '../types/commands.js';
export class CommandQueue {
private commands: Map<string, FigmaCommand> = new Map();
private results: Map<string, CommandResult> = new Map();
private readonly TIMEOUT_MS = 30000; // 30 seconds
constructor() {
// Auto-cleanup stale commands every 10 seconds
setInterval(() => this.cleanup(), 10000);
}
enqueue(type: CommandType, params: Record<string, unknown>): string {
const id = uuidv4();
const command: FigmaCommand = {
id,
type,
params,
status: 'pending',
createdAt: Date.now()
};
this.commands.set(id, command);
return id;
}
dequeue(): FigmaCommand[] {
const pending: FigmaCommand[] = [];
for (const [id, cmd] of this.commands) {
if (cmd.status === 'pending') {
cmd.status = 'processing';
pending.push(cmd);
}
}
return pending;
}
setResult(id: string, result: CommandResult): void {
const command = this.commands.get(id);
if (command) {
command.status = result.error ? 'failed' : 'completed';
command.result = { nodeId: result.nodeId, error: result.error };
this.results.set(id, result);
}
}
getResult(id: string): CommandResult | undefined {
return this.results.get(id);
}
async waitForResult(id: string, timeoutMs: number = this.TIMEOUT_MS): Promise<CommandResult> {
const startTime = Date.now();
return new Promise((resolve, reject) => {
const checkResult = () => {
const result = this.results.get(id);
if (result) {
resolve(result);
return;
}
if (Date.now() - startTime > timeoutMs) {
reject(new Error(`Command ${id} timed out after ${timeoutMs}ms`));
return;
}
setTimeout(checkResult, 100);
};
checkResult();
});
}
getQueueSize(): number {
return this.commands.size;
}
getPendingCount(): number {
let count = 0;
for (const cmd of this.commands.values()) {
if (cmd.status === 'pending' || cmd.status === 'processing') {
count++;
}
}
return count;
}
private cleanup(): void {
const now = Date.now();
for (const [id, cmd] of this.commands) {
if (now - cmd.createdAt > this.TIMEOUT_MS && cmd.status !== 'completed') {
cmd.status = 'failed';
cmd.result = { error: 'Command timed out' };
this.results.set(id, { error: 'Command timed out', success: false });
}
// Clean up old completed commands
if (now - cmd.createdAt > 60000) {
this.commands.delete(id);
this.results.delete(id);
}
}
}
}
// Singleton instance
export const commandQueue = new CommandQueue();