UNPKG

whatsapp-crm-common

Version:

Componentes compartidos para servicios de WhatsApp CRM - Common utilities and types for WhatsApp CRM system

277 lines 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ManejadorHistoriaChats = void 0; /** * Clase para manejar el historial de mensajes, incluyendo sincronizaciones parciales */ class ManejadorHistoriaChats { constructor(maxChats = 0) { this.historyCache = new Set(); // Inicializar el resultado con metadatos vacíos this.resultado = { metadatos: { completado: false, }, }; this.maxChats = maxChats; } /** * Procesa los datos del evento messaging-history.set * @param data - Datos del evento * @returns El resultado procesado acumulado */ procesarHistoriaDeChats(data) { const { chats, contacts, messages, syncType, isLatest, progress, peerDataRequestSessionId, } = data; // Actualizar metadatos this.resultado.metadatos = { ...this.resultado.metadatos, syncType, isLatest: isLatest || this.resultado.metadatos.isLatest, progress, peerDataRequestSessionId, completado: isLatest === true || progress === 100, }; // Inicializar todosLosContactos si no existe if (!this.resultado.todosLosContactos) { this.resultado.todosLosContactos = {}; } // Procesar chats for (const chat of chats) { // Si el chat ya existe, actualizamos solo los campos nuevos if (this.resultado[chat.id]) { const existing = this.resultado[chat.id]; existing.chat = { ...existing.chat, ...chat, }; } else { // Si es un chat nuevo, lo agregamos this.resultado[chat.id] = { chat: chat, contacto: null, mensajes: [], participantes: {}, esGrupo: chat.id.endsWith("@g.us"), }; } // Marcar como procesado en el cache this.historyCache.add(chat.id); } // Procesar contactos for (const contacto of contacts) { // Guardar en todosLosContactos if (contacto.id) { this.resultado.todosLosContactos[contacto.id] = { ...this.resultado.todosLosContactos[contacto.id], ...contacto, }; } // Asociar con su chat si existe y es un ChatProcesado if (contacto.id) { const entry = this.resultado[contacto.id]; if (entry && "mensajes" in entry) { entry.contacto = contacto; } } // Marcar como procesado en el cache const historyContactId = `c:${contacto.id}`; this.historyCache.add(historyContactId); } // Procesar mensajes for (const mensaje of messages) { const chatId = mensaje.key.remoteJid; if (!chatId) continue; // Crear el chat si no existe (puede ocurrir en sincronizaciones parciales) if (!this.resultado[chatId]) { this.resultado[chatId] = { chat: { id: chatId }, contacto: null, mensajes: [], participantes: {}, esGrupo: chatId.endsWith("@g.us"), }; } // Verificar si el mensaje ya existe para evitar duplicados const messageKey = this.getMessageKey(mensaje); const chatEntry = this.resultado[chatId]; const existingMessageIndex = chatEntry.mensajes.findIndex((m) => this.getMessageKey(m) === messageKey); if (existingMessageIndex === -1) { // Añadir mensaje nuevo chatEntry.mensajes.push(mensaje); // Si es un grupo, organizar por participante if (chatEntry.esGrupo && mensaje.key.participant) { const participanteId = mensaje.key.participant; if (!chatEntry.participantes[participanteId]) { chatEntry.participantes[participanteId] = []; } chatEntry.participantes[participanteId].push(mensaje); } } else { // Actualizar mensaje existente // Actualizar mensaje existente chatEntry.mensajes[existingMessageIndex] = { ...chatEntry.mensajes[existingMessageIndex], ...mensaje, }; // Actualizar también en participantes si es grupo if (chatEntry.esGrupo && mensaje.key.participant) { const participanteId = mensaje.key.participant; if (chatEntry.participantes[participanteId]) { const partMsgIndex = chatEntry.participantes[participanteId].findIndex((m) => this.getMessageKey(m) === messageKey); if (partMsgIndex !== -1) { chatEntry.participantes[participanteId][partMsgIndex] = mensaje; } } } // Marcar como procesado en el cache this.historyCache.add(messageKey); } } // Ordenar mensajes por timestamp después de cada actualización this.ordenarMensajes(); return this.resultado; } /** * Obtiene una clave única para un mensaje */ getMessageKey(mensaje) { const { id, remoteJid, fromMe } = mensaje.key; return `${remoteJid}:${id}:${fromMe ? "1" : "0"}`; } /** * Ordena los mensajes por timestamp */ ordenarMensajes() { for (const chatId in this.resultado) { if (chatId !== "todosLosContactos" && chatId !== "metadatos") { const chatInfo = this.resultado[chatId]; // Ordenar mensajes del chat if (chatInfo && chatInfo.mensajes && Array.isArray(chatInfo.mensajes)) { chatInfo.mensajes.sort((a, b) => { return ((Number(a.messageTimestamp) || 0) - (Number(b.messageTimestamp) || 0)); }); } // Ordenar mensajes por participante if (chatInfo && chatInfo.esGrupo) { for (const participanteId in chatInfo.participantes) { chatInfo.participantes[participanteId].sort((a, b) => { return ((Number(a.messageTimestamp) || 0) - (Number(b.messageTimestamp) || 0)); }); } } } } } /** * Reinicia el procesador para una nueva sincronización completa */ reiniciar() { this.resultado = { metadatos: { completado: false, }, }; this.historyCache.clear(); } /** * Obtiene el resultado actual, limitando a los N chats más recientes si maxChats > 0 */ obtenerResultado() { if (this.maxChats <= 0) { return this.resultado; } // Crear una copia del resultado original const resultadoLimitado = { metadatos: this.resultado.metadatos, todosLosContactos: this.resultado.todosLosContactos, }; // Extraer todos los chats y ordenarlos por fecha del último mensaje const chats = Object.entries(this.resultado) .filter(([key, value]) => key !== "todosLosContactos" && key !== "metadatos" && value && "mensajes" in value) .map(([chatId, chatInfo]) => ({ chatId, chatInfo: chatInfo, ultimoTimestamp: this.obtenerTimestampUltimoMensaje(chatInfo), })) .sort((a, b) => b.ultimoTimestamp - a.ultimoTimestamp) // Ordenar por más reciente .slice(0, this.maxChats); // Limitar al número máximo // Agregar los chats seleccionados al resultado chats.forEach(({ chatId, chatInfo }) => { resultadoLimitado[chatId] = chatInfo; }); return resultadoLimitado; } /** * Obtiene el timestamp del mensaje más reciente en un chat */ obtenerTimestampUltimoMensaje(chat) { if (!chat.mensajes || chat.mensajes.length === 0) { return 0; } return Math.max(...chat.mensajes.map((msg) => Number(msg.messageTimestamp) || 0)); } /** * Obtiene el estado serializable del manager para cache distribuido */ getSerializableState() { return { resultado: this.resultado, historyCache: Array.from(this.historyCache), maxChats: this.maxChats, timestamp: Date.now(), }; } /** * Restaura el estado desde datos serializados */ restoreFromState(state) { if (state.resultado) { this.resultado = state.resultado; } if (state.historyCache && Array.isArray(state.historyCache)) { this.historyCache = new Set(state.historyCache); } if (typeof state.maxChats === "number") { this.maxChats = state.maxChats; } } /** * Obtiene estadísticas del manager */ getStats() { const chatsCount = Object.keys(this.resultado).filter((key) => key !== "todosLosContactos" && key !== "metadatos").length; let messagesCount = 0; Object.values(this.resultado).forEach((value) => { if (value && typeof value === "object" && "mensajes" in value) { const chat = value; messagesCount += chat.mensajes?.length || 0; } }); const contactsCount = Object.keys(this.resultado.todosLosContactos || {}).length; return { chatsCount, messagesCount, contactsCount, cacheSize: this.historyCache.size, isCompleted: this.resultado.metadatos.completado, }; } /** * Obtiene el valor de maxChats (getter para compatibilidad) */ getMaxChats() { return this.maxChats; } } exports.ManejadorHistoriaChats = ManejadorHistoriaChats; //# sourceMappingURL=history-manager.js.map