UNPKG

whatsapp-crm-common

Version:

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

279 lines 11.3 kB
"use strict"; 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