89 lines
2.7 KiB
TypeScript
89 lines
2.7 KiB
TypeScript
type EmbeddedPiQueueHandle = {
|
|
queueMessage: (text: string) => Promise<void>;
|
|
isStreaming: () => boolean;
|
|
isCompacting: () => boolean;
|
|
abort: () => void;
|
|
};
|
|
|
|
const ACTIVE_EMBEDDED_RUNS = new Map<string, EmbeddedPiQueueHandle>();
|
|
type EmbeddedRunWaiter = {
|
|
resolve: (ended: boolean) => void;
|
|
timer: NodeJS.Timeout;
|
|
};
|
|
const EMBEDDED_RUN_WAITERS = new Map<string, Set<EmbeddedRunWaiter>>();
|
|
|
|
export function queueEmbeddedPiMessage(sessionId: string, text: string): boolean {
|
|
const handle = ACTIVE_EMBEDDED_RUNS.get(sessionId);
|
|
if (!handle) return false;
|
|
if (!handle.isStreaming()) return false;
|
|
if (handle.isCompacting()) return false;
|
|
void handle.queueMessage(text);
|
|
return true;
|
|
}
|
|
|
|
export function abortEmbeddedPiRun(sessionId: string): boolean {
|
|
const handle = ACTIVE_EMBEDDED_RUNS.get(sessionId);
|
|
if (!handle) return false;
|
|
handle.abort();
|
|
return true;
|
|
}
|
|
|
|
export function isEmbeddedPiRunActive(sessionId: string): boolean {
|
|
return ACTIVE_EMBEDDED_RUNS.has(sessionId);
|
|
}
|
|
|
|
export function isEmbeddedPiRunStreaming(sessionId: string): boolean {
|
|
const handle = ACTIVE_EMBEDDED_RUNS.get(sessionId);
|
|
if (!handle) return false;
|
|
return handle.isStreaming();
|
|
}
|
|
|
|
export function waitForEmbeddedPiRunEnd(sessionId: string, timeoutMs = 15_000): Promise<boolean> {
|
|
if (!sessionId || !ACTIVE_EMBEDDED_RUNS.has(sessionId)) return Promise.resolve(true);
|
|
return new Promise((resolve) => {
|
|
const waiters = EMBEDDED_RUN_WAITERS.get(sessionId) ?? new Set();
|
|
const waiter: EmbeddedRunWaiter = {
|
|
resolve,
|
|
timer: setTimeout(
|
|
() => {
|
|
waiters.delete(waiter);
|
|
if (waiters.size === 0) EMBEDDED_RUN_WAITERS.delete(sessionId);
|
|
resolve(false);
|
|
},
|
|
Math.max(100, timeoutMs),
|
|
),
|
|
};
|
|
waiters.add(waiter);
|
|
EMBEDDED_RUN_WAITERS.set(sessionId, waiters);
|
|
if (!ACTIVE_EMBEDDED_RUNS.has(sessionId)) {
|
|
waiters.delete(waiter);
|
|
if (waiters.size === 0) EMBEDDED_RUN_WAITERS.delete(sessionId);
|
|
clearTimeout(waiter.timer);
|
|
resolve(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
function notifyEmbeddedRunEnded(sessionId: string) {
|
|
const waiters = EMBEDDED_RUN_WAITERS.get(sessionId);
|
|
if (!waiters || waiters.size === 0) return;
|
|
EMBEDDED_RUN_WAITERS.delete(sessionId);
|
|
for (const waiter of waiters) {
|
|
clearTimeout(waiter.timer);
|
|
waiter.resolve(true);
|
|
}
|
|
}
|
|
|
|
export function setActiveEmbeddedRun(sessionId: string, handle: EmbeddedPiQueueHandle) {
|
|
ACTIVE_EMBEDDED_RUNS.set(sessionId, handle);
|
|
}
|
|
|
|
export function clearActiveEmbeddedRun(sessionId: string, handle: EmbeddedPiQueueHandle) {
|
|
if (ACTIVE_EMBEDDED_RUNS.get(sessionId) === handle) {
|
|
ACTIVE_EMBEDDED_RUNS.delete(sessionId);
|
|
notifyEmbeddedRunEnded(sessionId);
|
|
}
|
|
}
|
|
|
|
export type { EmbeddedPiQueueHandle };
|