UNPKG

@vreden/meta

Version:

Baileys is a lightweight JavaScript library for interacting with the WhatsApp Web API using WebSocket.

160 lines (153 loc) 5.36 kB
"use strict" Object.defineProperty(exports, "__esModule", { value: true }) const LRUCache_1 = require("lru-cache") /** Number of sent messages to cache in memory for handling retry receipts */ const RECENT_MESSAGES_SIZE = 512 /** Timeout for session recreation - 1 hour */ const RECREATE_SESSION_TIMEOUT = 60 * 60 * 1000 // 1 hour in milliseconds const PHONE_REQUEST_DELAY = 3000 class MessageRetryManager { constructor(logger, maxMsgRetryCount) { this.logger = logger this.recentMessagesMap = new LRUCache_1.LRUCache({ max: RECENT_MESSAGES_SIZE }) this.sessionRecreateHistory = new LRUCache_1.LRUCache({ ttl: RECREATE_SESSION_TIMEOUT * 2, ttlAutopurge: true }) this.retryCounters = new LRUCache_1.LRUCache({ ttl: 15 * 60 * 1000, ttlAutopurge: true, updateAgeOnGet: true }) // 15 minutes TTL this.pendingPhoneRequests = {} this.maxMsgRetryCount = 5 this.statistics = { totalRetries: 0, successfulRetries: 0, failedRetries: 0, mediaRetries: 0, sessionRecreations: 0, phoneRequests: 0 } this.maxMsgRetryCount = maxMsgRetryCount } /** * Add a recent message to the cache for retry handling */ addRecentMessage(to, id, message) { const key = { to, id } const keyStr = this.keyToString(key) // Add new message this.recentMessagesMap.set(keyStr, { message, timestamp: Date.now() }) this.logger.debug(`Added message to retry cache: ${to}/${id}`) } /** * Get a recent message from the cache */ getRecentMessage(to, id) { const key = { to, id } const keyStr = this.keyToString(key) return this.recentMessagesMap.get(keyStr) } /** * Check if a session should be recreated based on retry count and history */ shouldRecreateSession(jid, retryCount, hasSession) { // If we don't have a session, always recreate if (!hasSession) { this.sessionRecreateHistory.set(jid, Date.now()) this.statistics.sessionRecreations++ return { reason: "we don't have a Signal session with them", recreate: true } } // Only consider recreation if retry count > 1 if (retryCount < 2) { return { reason: '', recreate: false } } const now = Date.now() const prevTime = this.sessionRecreateHistory.get(jid) // If no previous recreation or it's been more than an hour if (!prevTime || now - prevTime > RECREATE_SESSION_TIMEOUT) { this.sessionRecreateHistory.set(jid, now) this.statistics.sessionRecreations++ return { reason: 'retry count > 1 and over an hour since last recreation', recreate: true } } return { reason: '', recreate: false } } /** * Increment retry counter for a message */ incrementRetryCount(messageId) { this.retryCounters.set(messageId, (this.retryCounters.get(messageId) || 0) + 1) this.statistics.totalRetries++ return this.retryCounters.get(messageId) } /** * Get retry count for a message */ getRetryCount(messageId) { return this.retryCounters.get(messageId) || 0 } /** * Check if message has exceeded maximum retry attempts */ hasExceededMaxRetries(messageId) { return this.getRetryCount(messageId) >= this.maxMsgRetryCount } /** * Mark retry as successful */ markRetrySuccess(messageId) { this.statistics.successfulRetries++ // Clean up retry counter for successful message this.retryCounters.delete(messageId) this.cancelPendingPhoneRequest(messageId) } /** * Mark retry as failed */ markRetryFailed(messageId) { this.statistics.failedRetries++ this.retryCounters.delete(messageId) } /** * Schedule a phone request with delay */ schedulePhoneRequest(messageId, callback, delay = PHONE_REQUEST_DELAY) { // Cancel any existing request for this message this.cancelPendingPhoneRequest(messageId) this.pendingPhoneRequests[messageId] = setTimeout(() => { delete this.pendingPhoneRequests[messageId] this.statistics.phoneRequests++ callback() }, delay) this.logger.debug(`Scheduled phone request for message ${messageId} with ${delay}ms delay`) } /** * Cancel pending phone request */ cancelPendingPhoneRequest(messageId) { const timeout = this.pendingPhoneRequests[messageId] if (timeout) { clearTimeout(timeout) delete this.pendingPhoneRequests[messageId] this.logger.debug(`Cancelled pending phone request for message ${messageId}`) } } keyToString(key) { return `${key.to}:${key.id}` } } module.exports = { MessageRetryManager }