mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 12:26:38 -06:00
bf413374cc
* fix(whatsapp): serve live group directory safely Co-authored-by: xialonglee <li.xialong@xydigit.com> * fix(whatsapp): complete owner lock retry policy * test(whatsapp): match socket end signature * fix(whatsapp): preserve live lookup cleanup errors * refactor(whatsapp): keep owner error code internal --------- Co-authored-by: xialonglee <li.xialong@xydigit.com>
81 lines
2.2 KiB
TypeScript
81 lines
2.2 KiB
TypeScript
// Whatsapp socket shutdown confirms the underlying Baileys transport is closed.
|
|
import type { WASocket } from "baileys";
|
|
|
|
const SOCKET_CLOSE_TIMEOUT_MS = 15_000;
|
|
|
|
async function withCloseTimeout(task: Promise<unknown>, operationName: string): Promise<void> {
|
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
await Promise.race([
|
|
task,
|
|
new Promise<never>((_resolve, reject) => {
|
|
timer = setTimeout(
|
|
() => reject(new Error(`WhatsApp ${operationName} timed out`)),
|
|
SOCKET_CLOSE_TIMEOUT_MS,
|
|
);
|
|
}),
|
|
]).finally(() => {
|
|
if (timer) {
|
|
clearTimeout(timer);
|
|
}
|
|
});
|
|
}
|
|
|
|
async function waitForTransportClose(
|
|
ws: Pick<WASocket["ws"], "isClosed" | "once" | "removeListener">,
|
|
operation: unknown,
|
|
operationName: string,
|
|
): Promise<void> {
|
|
let onClose: (() => void) | undefined;
|
|
const closed = ws.isClosed
|
|
? Promise.resolve()
|
|
: new Promise<void>((resolve) => {
|
|
onClose = resolve;
|
|
ws.once("close", onClose);
|
|
if (ws.isClosed) {
|
|
onClose();
|
|
}
|
|
});
|
|
try {
|
|
await withCloseTimeout(Promise.all([Promise.resolve(operation), closed]), operationName);
|
|
} finally {
|
|
if (onClose) {
|
|
ws.removeListener("close", onClose);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Close Baileys and verify the transport state before connection ownership moves. */
|
|
export async function closeWhatsAppSocketAndWait(
|
|
sock: Pick<WASocket, "end" | "ws">,
|
|
reason: string,
|
|
): Promise<void> {
|
|
const errors: unknown[] = [];
|
|
try {
|
|
const endResult: unknown = sock.end(new Error(reason));
|
|
if (sock.ws.isClosed) {
|
|
await waitForTransportClose(sock.ws, endResult, "socket end");
|
|
return;
|
|
}
|
|
if (sock.ws.isClosing) {
|
|
await waitForTransportClose(sock.ws, endResult, "socket end");
|
|
} else {
|
|
await withCloseTimeout(Promise.resolve(endResult), "socket end");
|
|
}
|
|
} catch (error) {
|
|
errors.push(error);
|
|
}
|
|
if (sock.ws.isClosed) {
|
|
return;
|
|
}
|
|
try {
|
|
const closeResult: unknown = sock.ws.close();
|
|
await waitForTransportClose(sock.ws, closeResult, "WebSocket close");
|
|
} catch (error) {
|
|
errors.push(error);
|
|
}
|
|
if (sock.ws.isClosed) {
|
|
return;
|
|
}
|
|
throw new AggregateError(errors, "WhatsApp socket close could not be confirmed");
|
|
}
|