web: reuse active listener for sends
parent
f34b238713
commit
5a8d18edf3
|
|
@ -0,0 +1,20 @@
|
||||||
|
export type ActiveWebListener = {
|
||||||
|
sendMessage: (
|
||||||
|
to: string,
|
||||||
|
text: string,
|
||||||
|
mediaBuffer?: Buffer,
|
||||||
|
mediaType?: string,
|
||||||
|
) => Promise<{ messageId: string }>;
|
||||||
|
sendComposingTo: (to: string) => Promise<void>;
|
||||||
|
close?: () => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
let currentListener: ActiveWebListener | null = null;
|
||||||
|
|
||||||
|
export function setActiveWebListener(listener: ActiveWebListener | null) {
|
||||||
|
currentListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getActiveWebListener(): ActiveWebListener | null {
|
||||||
|
return currentListener;
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ import { jidToE164, normalizeE164 } from "../utils.js";
|
||||||
import { monitorWebInbox } from "./inbound.js";
|
import { monitorWebInbox } from "./inbound.js";
|
||||||
import { loadWebMedia } from "./media.js";
|
import { loadWebMedia } from "./media.js";
|
||||||
import { sendMessageWhatsApp } from "./outbound.js";
|
import { sendMessageWhatsApp } from "./outbound.js";
|
||||||
|
import { setActiveWebListener } from "./active-listener.js";
|
||||||
import {
|
import {
|
||||||
computeBackoff,
|
computeBackoff,
|
||||||
newConnectionId,
|
newConnectionId,
|
||||||
|
|
@ -1016,7 +1017,10 @@ export async function monitorWebProvider(
|
||||||
`WhatsApp gateway connected${selfE164 ? ` as ${selfE164}` : ""}.`,
|
`WhatsApp gateway connected${selfE164 ? ` as ${selfE164}` : ""}.`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
setActiveWebListener(listener);
|
||||||
|
|
||||||
const closeListener = async () => {
|
const closeListener = async () => {
|
||||||
|
setActiveWebListener(null);
|
||||||
if (heartbeat) clearInterval(heartbeat);
|
if (heartbeat) clearInterval(heartbeat);
|
||||||
if (replyHeartbeatTimer) clearInterval(replyHeartbeatTimer);
|
if (replyHeartbeatTimer) clearInterval(replyHeartbeatTimer);
|
||||||
if (watchdogTimer) clearInterval(watchdogTimer);
|
if (watchdogTimer) clearInterval(watchdogTimer);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { logInfo } from "../logger.js";
|
||||||
import { getChildLogger } from "../logging.js";
|
import { getChildLogger } from "../logging.js";
|
||||||
import { toWhatsappJid } from "../utils.js";
|
import { toWhatsappJid } from "../utils.js";
|
||||||
import { loadWebMedia } from "./media.js";
|
import { loadWebMedia } from "./media.js";
|
||||||
|
import { getActiveWebListener } from "./active-listener.js";
|
||||||
import { createWaSocket, waitForWaConnection } from "./session.js";
|
import { createWaSocket, waitForWaConnection } from "./session.js";
|
||||||
|
|
||||||
export async function sendMessageWhatsApp(
|
export async function sendMessageWhatsApp(
|
||||||
|
|
@ -15,22 +16,25 @@ export async function sendMessageWhatsApp(
|
||||||
options: { verbose: boolean; mediaUrl?: string },
|
options: { verbose: boolean; mediaUrl?: string },
|
||||||
): Promise<{ messageId: string; toJid: string }> {
|
): Promise<{ messageId: string; toJid: string }> {
|
||||||
const correlationId = randomUUID();
|
const correlationId = randomUUID();
|
||||||
const sock = await createWaSocket(false, options.verbose);
|
const active = getActiveWebListener();
|
||||||
|
const usingActive = Boolean(active);
|
||||||
|
const sock = usingActive ? null : await createWaSocket(false, options.verbose);
|
||||||
const logger = getChildLogger({
|
const logger = getChildLogger({
|
||||||
module: "web-outbound",
|
module: "web-outbound",
|
||||||
correlationId,
|
correlationId,
|
||||||
to,
|
to,
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
logInfo("🔌 Connecting to WhatsApp Web…");
|
|
||||||
logger.info("connecting to whatsapp web");
|
|
||||||
await waitForWaConnection(sock);
|
|
||||||
// waitForWaConnection sets up listeners and error handling; keep the presence update safe.
|
|
||||||
const jid = toWhatsappJid(to);
|
const jid = toWhatsappJid(to);
|
||||||
try {
|
if (!usingActive) {
|
||||||
await sock.sendPresenceUpdate("composing", jid);
|
logInfo("🔌 Connecting to WhatsApp Web…");
|
||||||
} catch (err) {
|
logger.info("connecting to whatsapp web");
|
||||||
logVerbose(`Presence update skipped: ${String(err)}`);
|
await waitForWaConnection(sock!);
|
||||||
|
try {
|
||||||
|
await sock!.sendPresenceUpdate("composing", jid);
|
||||||
|
} catch (err) {
|
||||||
|
logVerbose(`Presence update skipped: ${String(err)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let payload: AnyMessageContent = { text: body };
|
let payload: AnyMessageContent = { text: body };
|
||||||
if (options.mediaUrl) {
|
if (options.mediaUrl) {
|
||||||
|
|
@ -76,18 +80,34 @@ export async function sendMessageWhatsApp(
|
||||||
{ jid, hasMedia: Boolean(options.mediaUrl) },
|
{ jid, hasMedia: Boolean(options.mediaUrl) },
|
||||||
"sending message",
|
"sending message",
|
||||||
);
|
);
|
||||||
const result = await sock.sendMessage(jid, payload);
|
const result = usingActive
|
||||||
const messageId = result?.key?.id ?? "unknown";
|
? await (async () => {
|
||||||
|
let mediaBuffer: Buffer | undefined;
|
||||||
|
let mediaType: string | undefined;
|
||||||
|
if (options.mediaUrl) {
|
||||||
|
const media = await loadWebMedia(options.mediaUrl);
|
||||||
|
mediaBuffer = media.buffer;
|
||||||
|
mediaType = media.contentType;
|
||||||
|
}
|
||||||
|
await active!.sendComposingTo(to);
|
||||||
|
return active!.sendMessage(to, body, mediaBuffer, mediaType);
|
||||||
|
})()
|
||||||
|
: await sock!.sendMessage(jid, payload);
|
||||||
|
const messageId = usingActive
|
||||||
|
? (result as { messageId?: string })?.messageId ?? "unknown"
|
||||||
|
: (result as any)?.key?.id ?? "unknown";
|
||||||
logInfo(
|
logInfo(
|
||||||
`✅ Sent via web session. Message ID: ${messageId} -> ${jid}${options.mediaUrl ? " (media)" : ""}`,
|
`✅ Sent via web session. Message ID: ${messageId} -> ${jid}${options.mediaUrl ? " (media)" : ""}`,
|
||||||
);
|
);
|
||||||
logger.info({ jid, messageId }, "sent message");
|
logger.info({ jid, messageId }, "sent message");
|
||||||
return { messageId, toJid: jid };
|
return { messageId, toJid: jid };
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
if (!usingActive) {
|
||||||
sock.ws?.close();
|
try {
|
||||||
} catch (err) {
|
sock?.ws?.close();
|
||||||
logVerbose(`Socket close failed: ${String(err)}`);
|
} catch (err) {
|
||||||
|
logVerbose(`Socket close failed: ${String(err)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue