my / src /services /whatsappService.js
understanding's picture
Upload 13 files
14960b8 verified
// src/services/whatsappService.js
const { randomDelay, sleep } = require('../utils');
const logger = require('../logger');
const config = require('../config');
let sockInstance = null;
/**
* Initializes the WhatsApp Service with the Baileys socket instance.
* Should be called once after connection is established.
* @param {object} sock - The Baileys socket instance.
*/
function initialize(sock) {
if (!sockInstance) {
sockInstance = sock;
logger.info('WhatsApp Service Initialized.');
}
}
/**
* Sends a presence update (typing, paused, available, unavailable).
* @param {'composing' | 'paused' | 'available' | 'unavailable'} status - The presence status.
* @param {string} jid - The target JID.
*/
async function sendPresenceUpdate(status, jid) {
if (!sockInstance) return logger.error('WhatsApp Service not initialized for sendPresenceUpdate');
try {
await sockInstance.sendPresenceUpdate(status, jid);
} catch (err) {
logger.error({ err, jid, status }, '[WhatsAppService] Failed to send presence update');
}
}
/**
* Marks specific messages as read.
* @param {Array<object>} keys - An array of message key objects.
*/
async function readReceipt(keys) {
if (!sockInstance) return logger.error('WhatsApp Service not initialized for readReceipt');
try {
await sockInstance.readMessages(keys);
// Log the first key for brevity if needed
if (keys && keys[0]) {
logger.debug({ jid: keys[0].remoteJid, msgId: keys[0].id }, `[WhatsAppService] Marked message(s) as read`);
}
} catch (err) {
const jid = keys && keys[0] ? keys[0].remoteJid : 'unknown';
logger.warn({ err, jid }, '[WhatsAppService] Failed to mark message(s) as read');
}
}
/**
* Sends a message with simulated typing and random delay.
* @param {string} jid - The target JID.
* @param {object} message - The Baileys message object (e.g., { text: 'Hello' }).
* @param {object} [options={}] - Options object.
* @param {number} [options.minDelay] - Minimum delay (defaults to config.defaultMinDelay).
* @param {number} [options.maxDelay] - Maximum delay (defaults to config.defaultMaxDelay).
* @returns {Promise<object|null>} - The result from Baileys sendMessage or null on init error.
*/
async function sendMessageWithTyping(jid, message, options = {}) {
if (!sockInstance) {
logger.error({ jid, message }, 'WhatsApp Service not initialized for sendMessage');
return null; // Indicate failure
}
// Use provided delays or fall back to config defaults
const minDelayMs = options.minDelay ?? config.defaultMinDelay;
const maxDelayMs = options.maxDelay ?? config.defaultMaxDelay;
try {
await sendPresenceUpdate('composing', jid);
await randomDelay(minDelayMs, maxDelayMs);
await sendPresenceUpdate('paused', jid); // Clear composing state before sending
const result = await sockInstance.sendMessage(jid, message);
logger.debug({ jid, msgContent: message.text || '[Non-Text]' }, '[WhatsAppService] Message sent');
return result;
} catch (err) {
logger.error({ err, jid, msgContent: message.text || '[Non-Text]' }, '[WhatsAppService] Failed to send message');
// Re-throw error for the calling handler to potentially manage
// Avoid sending another message from here to prevent loops
throw err;
}
}
module.exports = {
initialize,
sendMessageWithTyping,
readReceipt,
// Only export specific actions needed by handlers
};