whatsapp-crm-common
Version:
Componentes compartidos para servicios de WhatsApp CRM - Common utilities and types for WhatsApp CRM system
277 lines • 10.6 kB
JavaScript
"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