mirror of
https://github.com/morluto/rea
synced 2026-10-26 14:25:49 -04:00
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
import type { ProviderProcessSupervisor } from "./ProviderProcess.js";
|
|
|
|
type FrameOutcome = "frame" | "failure";
|
|
|
|
/** Own frame waiters and release the losing output-close wait after each race. */
|
|
export class WorkerFrameSignal {
|
|
readonly #waiters = new Set<(outcome: FrameOutcome) => void>();
|
|
|
|
wake(outcome: FrameOutcome): void {
|
|
for (const wake of this.#waiters) wake(outcome);
|
|
this.clear();
|
|
}
|
|
|
|
clear(): void {
|
|
this.#waiters.clear();
|
|
}
|
|
|
|
async waitForOutputClose(
|
|
supervisor: ProviderProcessSupervisor,
|
|
signal: AbortSignal,
|
|
): Promise<FrameOutcome | "closed" | "interrupted"> {
|
|
let wakeFrame!: (outcome: FrameOutcome) => void;
|
|
const frameAvailable = new Promise<FrameOutcome>((resolve) => {
|
|
wakeFrame = resolve;
|
|
this.#waiters.add(wakeFrame);
|
|
});
|
|
const outputCloseController = new AbortController();
|
|
const interruptOutputClose = () =>
|
|
outputCloseController.abort(signal.reason);
|
|
if (signal.aborted) interruptOutputClose();
|
|
else signal.addEventListener("abort", interruptOutputClose, { once: true });
|
|
try {
|
|
const outputClose = supervisor
|
|
.waitForOutputClose(undefined, outputCloseController.signal)
|
|
.then((closed): "closed" | "interrupted" =>
|
|
closed ? "closed" : "interrupted",
|
|
);
|
|
return await Promise.race([frameAvailable, outputClose]);
|
|
} finally {
|
|
outputCloseController.abort();
|
|
signal.removeEventListener("abort", interruptOutputClose);
|
|
this.#waiters.delete(wakeFrame);
|
|
}
|
|
}
|
|
}
|