whatsapp-crm-common
Version:
Componentes compartidos para servicios de WhatsApp CRM - Common utilities and types for WhatsApp CRM system
279 lines • 11.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HybridEventRouter = void 0;
const event_types_1 = require("../../events/types/event-types");
const logger_1 = __importDefault(require("../../utils/logger"));
/**
* Router híbrido que decide si usar BullMQ, Pub/Sub o ambos
* basado en la criticidad y tipo de evento
*/
class HybridEventRouter {
constructor(bullMQ, pubSub, config = {}) {
this.bullMQ = bullMQ;
this.pubSub = pubSub;
this.config = {
enablePubSubNotifications: true,
criticalEventsBothSystems: true,
pubSubRetryOnFailure: false,
...config
};
logger_1.default.info('Hybrid Event Router initialized', this.config);
}
/**
* Publica un evento usando el sistema apropiado
*/
async publishEvent(event) {
const isCritical = this.isCriticalEvent(event.eventType);
const isRealtime = this.isRealtimeEvent(event.eventType);
try {
// Eventos críticos → BullMQ (siempre)
if (isCritical) {
await this.bullMQ.publishEvent(event, this.getQueueForEvent(event.eventType));
logger_1.default.debug(`Critical event ${event.eventType} sent to BullMQ`, {
tenantId: event.tenantId,
agentId: event.agentId
});
// Si también necesita notificación en tiempo real
if (this.config.criticalEventsBothSystems && this.shouldBroadcast(event.eventType)) {
await this.publishToPubSub(event, 'notification');
}
}
// Eventos de tiempo real → Pub/Sub (siempre)
if (isRealtime && !isCritical) {
await this.publishToPubSub(event, 'realtime');
}
// Notificaciones generales → Pub/Sub
if (this.config.enablePubSubNotifications && this.isNotificationEvent(event.eventType)) {
await this.pubSub.publishNotification(event);
}
}
catch (error) {
logger_1.default.error(`Failed to route event ${event.eventType}:`, error);
// Fallback: si falla Pub/Sub en evento crítico, asegurar que esté en BullMQ
if (isCritical && !await this.isEventInBullMQ(event)) {
await this.bullMQ.publishEvent(event, this.getQueueForEvent(event.eventType));
}
throw error;
}
}
/**
* Publica múltiples eventos de forma optimizada
*/
async publishBatch(events) {
const criticalEvents = events.filter(e => this.isCriticalEvent(e.eventType));
const realtimeEvents = events.filter(e => this.isRealtimeEvent(e.eventType) && !this.isCriticalEvent(e.eventType));
try {
// Procesar eventos críticos en BullMQ
if (criticalEvents.length > 0) {
await Promise.all(criticalEvents.map(event => this.bullMQ.publishEvent(event, this.getQueueForEvent(event.eventType))));
logger_1.default.debug(`Batch: ${criticalEvents.length} critical events sent to BullMQ`);
}
// Procesar eventos en tiempo real en Pub/Sub
if (realtimeEvents.length > 0) {
await Promise.all(realtimeEvents.map(event => this.publishToPubSub(event, 'realtime')));
logger_1.default.debug(`Batch: ${realtimeEvents.length} realtime events sent to PubSub`);
}
}
catch (error) {
logger_1.default.error('Failed to process event batch:', error);
throw error;
}
}
/**
* Publica un evento de sistema para monitoreo
*/
async publishSystemEvent(eventType, data) {
const systemEvent = {
tenantId: 'system',
agentId: 0,
eventType: event_types_1.WhatsAppEventType.SYSTEM_HEALTH,
data: {
status: 'active',
metrics: data,
timestamp: Date.now()
},
sessionKey: 'system',
timestamp: Date.now(),
priority: event_types_1.EventPriority.MEDIUM
};
// Eventos de sistema siempre van a Pub/Sub para monitoreo en tiempo real
await this.publishToPubSub(systemEvent, 'system');
}
/**
* Obtiene estadísticas del router
*/
async getStats() {
try {
const [bullMQStats, pubSubStats] = await Promise.all([
this.bullMQ.getAllQueueStats(),
this.pubSub.getStats()
]);
return {
router: {
config: this.config,
criticalEventTypes: this.getCriticalEventTypes(),
realtimeEventTypes: this.getRealtimeEventTypes()
},
bullMQ: bullMQStats,
pubSub: pubSubStats
};
}
catch (error) {
logger_1.default.error('Failed to get router stats:', error);
return { error: error instanceof Error ? error.message : String(error) };
}
}
/**
* Actualiza la configuración del router
*/
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
logger_1.default.info('Hybrid Event Router config updated', this.config);
}
/**
* Verifica si un evento es crítico
*/
isCriticalEvent(eventType) {
return [
event_types_1.WhatsAppEventType.MESSAGE_NEW,
event_types_1.WhatsAppEventType.MESSAGE_UPDATE,
event_types_1.WhatsAppEventType.HISTORY_SYNC,
event_types_1.WhatsAppEventType.CONTACT_UPDATE,
event_types_1.WhatsAppEventType.CHAT_UPSERT,
event_types_1.WhatsAppEventType.GROUP_UPSERT,
event_types_1.WhatsAppEventType.GROUP_PARTICIPANTS_UPDATE,
event_types_1.WhatsAppEventType.MESSAGE_DELETE,
event_types_1.WhatsAppEventType.MESSAGE_REACTION,
event_types_1.WhatsAppEventType.WEBHOOK_DELIVERY
].includes(eventType);
}
/**
* Verifica si un evento es de tiempo real
*/
isRealtimeEvent(eventType) {
return [
event_types_1.WhatsAppEventType.QR_CODE_GENERATED,
event_types_1.WhatsAppEventType.CONNECTION_UPDATE,
event_types_1.WhatsAppEventType.PRESENCE_UPDATE,
event_types_1.WhatsAppEventType.TYPING_START,
event_types_1.WhatsAppEventType.TYPING_STOP,
event_types_1.WhatsAppEventType.SYSTEM_HEALTH,
event_types_1.WhatsAppEventType.LIVE_LOCATION_UPDATE,
event_types_1.WhatsAppEventType.CALL_INCOMING,
event_types_1.WhatsAppEventType.CALL_ENDED
].includes(eventType);
}
/**
* Verifica si un evento necesita notificación
*/
isNotificationEvent(eventType) {
return [
event_types_1.WhatsAppEventType.MESSAGE_NEW,
event_types_1.WhatsAppEventType.QR_CODE_GENERATED,
event_types_1.WhatsAppEventType.CONNECTION_UPDATE,
event_types_1.WhatsAppEventType.CALL_INCOMING,
event_types_1.WhatsAppEventType.GROUP_INVITE_RECEIVED
].includes(eventType);
}
/**
* Verifica si un evento crítico también necesita broadcast
*/
shouldBroadcast(eventType) {
return [
event_types_1.WhatsAppEventType.MESSAGE_NEW,
event_types_1.WhatsAppEventType.MESSAGE_UPDATE,
event_types_1.WhatsAppEventType.CONTACT_UPDATE
].includes(eventType);
}
/**
* Obtiene la cola apropiada para un evento crítico
*/
getQueueForEvent(eventType) {
switch (eventType) {
case event_types_1.WhatsAppEventType.MESSAGE_NEW:
case event_types_1.WhatsAppEventType.MESSAGE_UPDATE:
case event_types_1.WhatsAppEventType.MESSAGE_DELETE:
case event_types_1.WhatsAppEventType.MESSAGE_REACTION:
return event_types_1.QueueName.REALTIME;
case event_types_1.WhatsAppEventType.HISTORY_SYNC:
case event_types_1.WhatsAppEventType.CONTACT_UPDATE:
case event_types_1.WhatsAppEventType.CHAT_UPSERT:
return event_types_1.QueueName.BULK;
case event_types_1.WhatsAppEventType.WEBHOOK_DELIVERY:
return event_types_1.QueueName.WEBHOOK;
default:
return event_types_1.QueueName.NOTIFICATIONS;
}
}
/**
* Publica a Pub/Sub con manejo de errores
*/
async publishToPubSub(event, type) {
try {
if (type === 'notification') {
await this.pubSub.publishNotification(event);
}
else {
await this.pubSub.publishEvent(event);
}
logger_1.default.debug(`${type} event ${event.eventType} sent to PubSub`, {
tenantId: event.tenantId,
agentId: event.agentId
});
}
catch (error) {
logger_1.default.warn(`Failed to publish ${type} event to PubSub:`, error);
if (!this.config.pubSubRetryOnFailure) {
// No relanzar error para eventos de Pub/Sub si no está configurado retry
return;
}
throw error;
}
}
/**
* Verifica si un evento ya está en BullMQ (para fallback)
*/
async isEventInBullMQ(event) {
// Implementación simplificada - en producción podrías verificar en Redis
// si el evento específico ya está encolado
return false;
}
/**
* Obtiene tipos de eventos críticos
*/
getCriticalEventTypes() {
return [
event_types_1.WhatsAppEventType.MESSAGE_NEW,
event_types_1.WhatsAppEventType.MESSAGE_UPDATE,
event_types_1.WhatsAppEventType.HISTORY_SYNC,
event_types_1.WhatsAppEventType.CONTACT_UPDATE,
event_types_1.WhatsAppEventType.CHAT_UPSERT,
event_types_1.WhatsAppEventType.GROUP_UPSERT,
event_types_1.WhatsAppEventType.GROUP_PARTICIPANTS_UPDATE,
event_types_1.WhatsAppEventType.MESSAGE_DELETE,
event_types_1.WhatsAppEventType.MESSAGE_REACTION,
event_types_1.WhatsAppEventType.WEBHOOK_DELIVERY
];
}
/**
* Obtiene tipos de eventos de tiempo real
*/
getRealtimeEventTypes() {
return [
event_types_1.WhatsAppEventType.QR_CODE_GENERATED,
event_types_1.WhatsAppEventType.CONNECTION_UPDATE,
event_types_1.WhatsAppEventType.PRESENCE_UPDATE,
event_types_1.WhatsAppEventType.TYPING_START,
event_types_1.WhatsAppEventType.TYPING_STOP,
event_types_1.WhatsAppEventType.SYSTEM_HEALTH,
event_types_1.WhatsAppEventType.LIVE_LOCATION_UPDATE,
event_types_1.WhatsAppEventType.CALL_INCOMING,
event_types_1.WhatsAppEventType.CALL_ENDED
];
}
}
exports.HybridEventRouter = HybridEventRouter;
//# sourceMappingURL=hybrid-event-router.js.map