Deploy: 2026-07-15 04:57:29

This commit is contained in:
Hamza-Ayed
2026-07-15 04:57:29 +03:00
parent 134ed08f45
commit 3de7764cdd
4 changed files with 522 additions and 40 deletions
+67 -39
View File
@@ -6,6 +6,7 @@ const NodeCache = require('node-cache');
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const throttleManager = require('./throttle-manager');
class InMemoryStore {
constructor() {
@@ -573,44 +574,40 @@ function convertToOggOpus(base64Audio) {
/**
* Send a message using an active session
*/
async function sendMessage(session_key, phone, message, mediaUrl = null, audioBase64 = null, mimetype = null, imageBase64 = null) {
const sock = sessions.get(session_key);
if (!sock) {
throw new Error(`Session ${session_key} is not active or connected`);
}
// Use the LID JID if we have a mapping for this phone number.
// This is CRITICAL: Signal E2EE sessions are bound to the LID JID,
// so replying to the phone JID creates a separate session that
// conflicts with the LID session, causing "Waiting for this message".
let jid;
/**
* Resolve the correct JID for a phone number (handles LID privacy scheme)
*/
async function resolveJid(sock, phone) {
if (phone.includes('@')) {
jid = phone;
} else if (phoneToLid.has(phone)) {
jid = phoneToLid.get(phone);
console.log(`[LID] Routing reply to ${phone} via LID: ${jid}`);
} else {
// Query WhatsApp to resolve the correct JID/LID for this phone number.
// This is CRITICAL for newer WhatsApp versions (especially iOS) to prevent
// E2EE session conflicts and the "Waiting for this message" decryption delay.
try {
console.log(`[JID Resolve] Resolving JID for ${phone}...`);
const [result] = await sock.onWhatsApp(phone);
if (result && result.exists) {
jid = result.jid;
console.log(`[JID Resolve] Successfully resolved JID for ${phone}: ${jid}`);
// Cache it for subsequent messages
if (jid.endsWith('@lid')) {
phoneToLid.set(phone, jid);
}
} else {
jid = `${phone}@s.whatsapp.net`;
}
} catch (err) {
console.error(`[JID Resolve] Failed to query onWhatsApp for ${phone}:`, err.message);
jid = `${phone}@s.whatsapp.net`;
}
return phone;
}
if (phoneToLid.has(phone)) {
const lid = phoneToLid.get(phone);
console.log(`[LID] Routing reply to ${phone} via LID: ${lid}`);
return lid;
}
// Query WhatsApp to resolve the correct JID/LID for this phone number.
try {
console.log(`[JID Resolve] Resolving JID for ${phone}...`);
const [result] = await sock.onWhatsApp(phone);
if (result && result.exists) {
console.log(`[JID Resolve] Successfully resolved JID for ${phone}: ${result.jid}`);
if (result.jid.endsWith('@lid')) {
phoneToLid.set(phone, result.jid);
}
return result.jid;
}
} catch (err) {
console.error(`[JID Resolve] Failed to query onWhatsApp for ${phone}:`, err.message);
}
return `${phone}@s.whatsapp.net`;
}
/**
* Internal raw send — performs the actual sock.sendMessage without throttling.
* Used inside the throttle queue's sendFn callback.
*/
async function _rawSend(sock, jid, message, mediaUrl, audioBase64, mimetype, imageBase64) {
let sentMsg;
if (imageBase64) {
@@ -631,7 +628,6 @@ async function sendMessage(session_key, phone, message, mediaUrl = null, audioBa
finalMime = 'audio/ogg; codecs=opus';
} catch (err) {
console.error(`[Baileys] FFmpeg conversion failed:`, err.message);
// Fallback to sending as normal audio if conversion fails
finalMime = 'audio/mp4';
}
}
@@ -642,7 +638,7 @@ async function sendMessage(session_key, phone, message, mediaUrl = null, audioBa
sentMsg = await sock.sendMessage(jid, {
audio: buffer,
mimetype: finalMime,
ptt: !isMp3 // PTT enabled for OGG/MP4, disabled for raw MP3
ptt: !isMp3
});
} else if (mediaUrl) {
const ext = mediaUrl.split('.').pop().toLowerCase();
@@ -669,6 +665,37 @@ async function sendMessage(session_key, phone, message, mediaUrl = null, audioBa
return sentMsg;
}
/**
* Send a message using an active session — routed through ThrottleManager
* for human-like delays, typing indicators, and anti-ban protection.
*/
async function sendMessage(session_key, phone, message, mediaUrl = null, audioBase64 = null, mimetype = null, imageBase64 = null) {
const sock = sessions.get(session_key);
if (!sock) {
throw new Error(`Session ${session_key} is not active or connected`);
}
const jid = await resolveJid(sock, phone);
// Determine message type for throttle delay calculation
let msgType = 'auto_reply';
if (audioBase64) msgType = 'voice_reply';
// Build the content descriptor for typing delay calculation
const content = { text: message || '' };
// Enqueue through ThrottleManager for anti-ban protection
const sentMsg = await throttleManager.enqueue(session_key, {
jid,
sock,
content,
type: msgType,
sendFn: () => _rawSend(sock, jid, message, mediaUrl, audioBase64, mimetype, imageBase64)
});
return sentMsg;
}
async function checkContact(session_key, phone) {
const sock = sessions.get(session_key);
if (!sock) {
@@ -770,6 +797,7 @@ module.exports = {
sendMessage,
getActiveSessions,
checkContact,
exportChatHistory
exportChatHistory,
throttleManager
};