mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-17 04:50:51 +00:00
108 lines
2.8 KiB
TypeScript
108 lines
2.8 KiB
TypeScript
import type { ChannelAccountSnapshot } from "../channels/plugins/types.core.js";
|
|
|
|
type CloseAwareServer = {
|
|
once: (event: "close", listener: () => void) => unknown;
|
|
};
|
|
|
|
type PassiveAccountLifecycleParams<Handle> = {
|
|
abortSignal?: AbortSignal;
|
|
start: () => Promise<Handle>;
|
|
stop?: (handle: Handle) => void | Promise<void>;
|
|
onStop?: () => void | Promise<void>;
|
|
};
|
|
|
|
export function createAccountStatusSink(params: {
|
|
accountId: string;
|
|
setStatus: (next: ChannelAccountSnapshot) => void;
|
|
}): (patch: Omit<ChannelAccountSnapshot, "accountId">) => void {
|
|
return (patch) => {
|
|
params.setStatus({ accountId: params.accountId, ...patch });
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Return a promise that resolves when the signal is aborted.
|
|
*
|
|
* If no signal is provided, the promise stays pending forever. When provided,
|
|
* `onAbort` runs once before the promise resolves.
|
|
*/
|
|
export function waitUntilAbort(
|
|
signal?: AbortSignal,
|
|
onAbort?: () => void | Promise<void>,
|
|
): Promise<void> {
|
|
return new Promise<void>((resolve, reject) => {
|
|
const complete = () => {
|
|
Promise.resolve(onAbort?.()).then(() => resolve(), reject);
|
|
};
|
|
if (!signal) {
|
|
return;
|
|
}
|
|
if (signal.aborted) {
|
|
complete();
|
|
return;
|
|
}
|
|
signal.addEventListener("abort", complete, { once: true });
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Keep a passive account task alive until abort, then run optional cleanup.
|
|
*/
|
|
export async function runPassiveAccountLifecycle<Handle>(
|
|
params: PassiveAccountLifecycleParams<Handle>,
|
|
): Promise<void> {
|
|
const handle = await params.start();
|
|
|
|
try {
|
|
await waitUntilAbort(params.abortSignal);
|
|
} finally {
|
|
await params.stop?.(handle);
|
|
await params.onStop?.();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Keep a channel/provider task pending until the HTTP server closes.
|
|
*
|
|
* When an abort signal is provided, `onAbort` is invoked once and should
|
|
* trigger server shutdown. The returned promise resolves only after `close`.
|
|
*/
|
|
export async function keepHttpServerTaskAlive(params: {
|
|
server: CloseAwareServer;
|
|
abortSignal?: AbortSignal;
|
|
onAbort?: () => void | Promise<void>;
|
|
}): Promise<void> {
|
|
const { server, abortSignal, onAbort } = params;
|
|
let abortTask: Promise<void> = Promise.resolve();
|
|
let abortTriggered = false;
|
|
|
|
const triggerAbort = () => {
|
|
if (abortTriggered) {
|
|
return;
|
|
}
|
|
abortTriggered = true;
|
|
abortTask = Promise.resolve(onAbort?.()).then(() => undefined);
|
|
};
|
|
|
|
const onAbortSignal = () => {
|
|
triggerAbort();
|
|
};
|
|
|
|
if (abortSignal) {
|
|
if (abortSignal.aborted) {
|
|
triggerAbort();
|
|
} else {
|
|
abortSignal.addEventListener("abort", onAbortSignal, { once: true });
|
|
}
|
|
}
|
|
|
|
await new Promise<void>((resolve) => {
|
|
server.once("close", () => resolve());
|
|
});
|
|
|
|
if (abortSignal) {
|
|
abortSignal.removeEventListener("abort", onAbortSignal);
|
|
}
|
|
await abortTask;
|
|
}
|