diff --git a/src/api/controllers/instance.controller.ts b/src/api/controllers/instance.controller.ts index e596585c..e003919f 100644 --- a/src/api/controllers/instance.controller.ts +++ b/src/api/controllers/instance.controller.ts @@ -2,7 +2,7 @@ import { InstanceDto, SetPresenceDto } from '@api/dto/instance.dto'; import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service'; import { ProviderFiles } from '@api/provider/sessions'; import { PrismaRepository } from '@api/repository/repository.service'; -import { channelController, eventController } from '@api/server.module'; +import { channelController, eventManager } from '@api/server.module'; import { CacheService } from '@api/services/cache.service'; import { WAMonitoringService } from '@api/services/monitor.service'; import { SettingsService } from '@api/services/settings.service'; @@ -81,7 +81,7 @@ export class InstanceController { this.waMonitor.delInstanceTime(instance.instanceName); // set events - await eventController.setInstance(instance.instanceName, instanceData); + await eventManager.setInstance(instance.instanceName, instanceData); instance.sendDataWebhook(Events.INSTANCE_CREATE, { instanceName: instanceData.instanceName, @@ -154,22 +154,18 @@ export class InstanceController { }, hash, webhook: { - webhookUrl: instanceData.webhookUrl, - webhookByEvents: instanceData.webhookByEvents, - webhookBase64: instanceData.webhookBase64, - // events: getWebhookEvents, + webhookUrl: instanceData.webhook.url, + webhookByEvents: instanceData.webhook.byEvents, + webhookBase64: instanceData.webhook.base64, }, websocket: { - enabled: instanceData.websocketEnabled, - // events: getWebsocketEvents, + enabled: instanceData.websocket.enabled, }, rabbitmq: { - enabled: instanceData.rabbitmqEnabled, - // events: getRabbitmqEvents, + enabled: instanceData.rabbitmq.enabled, }, sqs: { - enabled: instanceData.sqsEnabled, - // events: getSqsEvents, + enabled: instanceData.sqs.enabled, }, settings, qrcode: getQrcode, @@ -245,22 +241,18 @@ export class InstanceController { }, hash, webhook: { - webhookUrl: instanceData.webhookUrl, - webhookByEvents: instanceData.webhookByEvents, - webhookBase64: instanceData.webhookBase64, - // events: getWebhookEvents, + webhookUrl: instanceData.webhook.url, + webhookByEvents: instanceData.webhook.byEvents, + webhookBase64: instanceData.webhook.base64, }, websocket: { - enabled: instanceData.websocketEnabled, - // events: getWebsocketEvents, + enabled: instanceData.websocket.enabled, }, rabbitmq: { - enabled: instanceData.rabbitmqEnabled, - // events: getRabbitmqEvents, + enabled: instanceData.rabbitmq.enabled, }, sqs: { - enabled: instanceData.sqsEnabled, - // events: getSqsEvents, + enabled: instanceData.sqs.enabled, }, settings, chatwoot: { diff --git a/src/api/integrations/chatbot/chatbot.controller.ts b/src/api/integrations/chatbot/chatbot.controller.ts index 7957e2b2..3ae31bf2 100644 --- a/src/api/integrations/chatbot/chatbot.controller.ts +++ b/src/api/integrations/chatbot/chatbot.controller.ts @@ -2,10 +2,10 @@ import { InstanceDto } from '@api/dto/instance.dto'; import { PrismaRepository } from '@api/repository/repository.service'; import { difyController, + eventManager, genericController, openaiController, typebotController, - websocketController, } from '@api/server.module'; import { WAMonitoringService } from '@api/services/monitor.service'; import { Logger } from '@config/logger.config'; @@ -102,12 +102,13 @@ export class ChatbotController { await genericController.emit(emitData); } - public async setInstance(instanceName: string, data: any): Promise { - // chatwoot - if (data.websocketEnabled) - await websocketController.set(instanceName, { - enabled: true, - events: data.websocketEvents, + public async setInstance(instanceName: string, data: InstanceDto): Promise { + if (data.websocket.enabled) + await eventManager.websocket.set(instanceName, { + websocket: { + enabled: true, + events: data.websocket.events, + }, }); } @@ -200,7 +201,7 @@ export class ChatbotController { instance: InstanceDto, session?: IntegrationSession, ) { - let findBot = null; + let findBot: null; if (!session) { findBot = await findBotByTrigger(botRepository, settingsRepository, content, instance.instanceId); diff --git a/src/api/integrations/event/event.controller.ts b/src/api/integrations/event/event.controller.ts index e0a85946..e68e4280 100644 --- a/src/api/integrations/event/event.controller.ts +++ b/src/api/integrations/event/event.controller.ts @@ -1,7 +1,7 @@ +import { EventDto } from '@api/integrations/event/event.dto'; import { PrismaRepository } from '@api/repository/repository.service'; -import { rabbitmqController, sqsController, webhookController, websocketController } from '@api/server.module'; import { WAMonitoringService } from '@api/services/monitor.service'; -import { Server } from 'http'; +import { wa } from '@api/types/wa.types'; export type EmitData = { instanceName: string; @@ -16,19 +16,27 @@ export type EmitData = { }; export interface EventControllerInterface { - integrationEnabled: boolean; set(instanceName: string, data: any): Promise; get(instanceName: string): Promise; emit({ instanceName, origin, event, data, serverUrl, dateTime, sender, apiKey, local }: EmitData): Promise; } export class EventController { - public prismaRepository: PrismaRepository; - public waMonitor: WAMonitoringService; + private prismaRepository: PrismaRepository; + private waMonitor: WAMonitoringService; + private integrationStatus: boolean; + private integrationName: string; - constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + constructor( + prismaRepository: PrismaRepository, + waMonitor: WAMonitoringService, + integrationStatus: boolean, + integrationName: string, + ) { this.prisma = prismaRepository; this.monitor = waMonitor; + this.status = integrationStatus; + this.name = integrationName; } public set prisma(prisma: PrismaRepository) { @@ -47,6 +55,72 @@ export class EventController { return this.waMonitor; } + public set name(name: string) { + this.integrationName = name; + } + + public get name() { + return this.integrationName; + } + + public set status(status: boolean) { + this.integrationStatus = status; + } + + public get status() { + return this.integrationStatus; + } + + public async set(instanceName: string, data: EventDto): Promise { + if (!this.status) { + return; + } + + if (!data[this.name].enabled) { + data[this.name].events = []; + } else { + if (0 === data[this.name].events.length) { + data[this.name].events = this.events; + } + } + + return this.prisma[this.name].upsert({ + where: { + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + update: { + ...data, + }, + create: { + enabled: data[this.name].enabled, + events: data[this.name].events, + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + }); + } + + public async get(instanceName: string): Promise { + if (!this.status) { + return; + } + + if (undefined === this.monitor.waInstances[instanceName]) { + return null; + } + + const data = await this.prisma[this.name].findUnique({ + where: { + instanceId: this.monitor.waInstances[instanceName].instanceId, + }, + }); + + if (!data) { + return null; + } + + return data; + } + public readonly events = [ 'APPLICATION_STARTUP', 'QRCODE_UPDATED', @@ -76,93 +150,4 @@ export class EventController { 'REMOVE_INSTANCE', 'LOGOUT_INSTANCE', ]; - - public init(httpServer: Server): void { - // websocket - websocketController.init(httpServer); - - // rabbitmq - rabbitmqController.init(); - - // sqs - sqsController.init(); - } - - public async emit({ - instanceName, - origin, - event, - data, - serverUrl, - dateTime, - sender, - apiKey, - local, - }: { - instanceName: string; - origin: string; - event: string; - data: Object; - serverUrl: string; - dateTime: string; - sender: string; - apiKey?: string; - local?: boolean; - }): Promise { - const emitData = { - instanceName, - origin, - event, - data, - serverUrl, - dateTime, - sender, - apiKey, - local, - }; - // websocket - await websocketController.emit(emitData); - - // rabbitmq - await rabbitmqController.emit(emitData); - - // sqs - await sqsController.emit(emitData); - - // webhook - await webhookController.emit(emitData); - } - - public async setInstance(instanceName: string, data: any): Promise { - // websocket - if (data.websocketEnabled) - await websocketController.set(instanceName, { - enabled: true, - events: data.websocketEvents, - }); - - // rabbitmq - if (data.rabbitmqEnabled) - await rabbitmqController.set(instanceName, { - enabled: true, - events: data.rabbitmqEvents, - }); - - // sqs - if (data.sqsEnabled) - await sqsController.set(instanceName, { - enabled: true, - events: data.sqsEvents, - }); - - // webhook - if (data.webhookEnabled) - await webhookController.set(instanceName, { - enabled: true, - events: data.webhookEvents, - url: data.webhookUrl, - webhookBase64: data.webhookBase64, - webhookByEvents: data.webhookByEvents, - }); - } } diff --git a/src/api/integrations/event/event.dto.ts b/src/api/integrations/event/event.dto.ts new file mode 100644 index 00000000..e79e308e --- /dev/null +++ b/src/api/integrations/event/event.dto.ts @@ -0,0 +1,53 @@ +import { Constructor } from '@api/integrations/integration.dto'; + +export class EventDto { + webhook?: { + enabled: boolean; + events?: string[]; + url?: string; + byEvents?: boolean; + base64?: boolean; + }; + + websocket?: { + enabled: boolean; + events?: string[]; + }; + + sqs?: { + enabled: boolean; + events?: string[]; + }; + + rabbitmq?: { + enabled: boolean; + events?: string[]; + }; +} + +export function EventInstanceMixin(Base: TBase) { + return class extends Base { + webhook?: { + enabled: boolean; + events?: string[]; + url?: string; + byEvents?: boolean; + base64?: boolean; + }; + + websocket?: { + enabled: boolean; + events?: string[]; + }; + + sqs?: { + enabled: boolean; + events?: string[]; + }; + + rabbitmq?: { + enabled: boolean; + events?: string[]; + }; + }; +} diff --git a/src/api/integrations/event/event.manager.ts b/src/api/integrations/event/event.manager.ts new file mode 100644 index 00000000..50df465a --- /dev/null +++ b/src/api/integrations/event/event.manager.ts @@ -0,0 +1,130 @@ +import { RabbitmqController } from '@api/integrations/event/rabbitmq/rabbitmq.controller'; +import { SqsController } from '@api/integrations/event/sqs/sqs.controller'; +import { WebhookController } from '@api/integrations/event/webhook/webhook.controller'; +import { WebsocketController } from '@api/integrations/event/websocket/websocket.controller'; +import { PrismaRepository } from '@api/repository/repository.service'; +import { WAMonitoringService } from '@api/services/monitor.service'; +import { Server } from 'http'; + +export class EventManager { + private prismaRepository: PrismaRepository; + private waMonitor: WAMonitoringService; + private websocketController: WebsocketController; + private webhookController: WebhookController; + private rabbitmqController: RabbitmqController; + private sqsController: SqsController; + + constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { + this.prisma = prismaRepository; + this.monitor = waMonitor; + + this.websocket = new WebsocketController(prismaRepository, waMonitor); + this.webhook = new WebhookController(prismaRepository, waMonitor); + this.rabbitmq = new RabbitmqController(prismaRepository, waMonitor); + this.sqs = new SqsController(prismaRepository, waMonitor); + } + + public set prisma(prisma: PrismaRepository) { + this.prismaRepository = prisma; + } + + public get prisma() { + return this.prismaRepository; + } + + public set monitor(waMonitor: WAMonitoringService) { + this.waMonitor = waMonitor; + } + + public get monitor() { + return this.waMonitor; + } + + public set websocket(websocket: WebsocketController) { + this.websocketController = websocket; + } + + public get websocket() { + return this.websocketController; + } + + public set webhook(webhook: WebhookController) { + this.webhookController = webhook; + } + + public get webhook() { + return this.webhookController; + } + + public set rabbitmq(rabbitmq: RabbitmqController) { + this.rabbitmqController = rabbitmq; + } + + public get rabbitmq() { + return this.rabbitmqController; + } + + public set sqs(sqs: SqsController) { + this.sqsController = sqs; + } + + public get sqs() { + return this.sqsController; + } + + public init(httpServer: Server): void { + this.websocket.init(httpServer); + this.rabbitmq.init(); + this.sqs.init(); + } + + public async emit(eventData: { + instanceName: string; + origin: string; + event: string; + data: Object; + serverUrl: string; + dateTime: string; + sender: string; + apiKey?: string; + local?: boolean; + }): Promise { + await this.websocket.emit(eventData); + await this.rabbitmq.emit(eventData); + await this.sqs.emit(eventData); + await this.webhook.emit(eventData); + } + + public async setInstance(instanceName: string, data: any): Promise { + await this.websocket.set(instanceName, { + websocket: { + enabled: data.websocket?.enabled, + events: data.websocket?.events, + }, + }); + + await this.rabbitmq.set(instanceName, { + rabbitmq: { + enabled: data.rabbitmq?.enabled, + events: data.rabbitmq?.events, + }, + }); + + await this.sqs.set(instanceName, { + sqs: { + enabled: data.sqs?.enabled, + events: data.sqs?.events, + }, + }); + + await this.webhook.set(instanceName, { + webhook: { + enabled: data.webhook?.enabled, + events: data.webhook?.events, + url: data.webhook.url, + base64: data.webhook.base64, + byEvents: data.webhook.byEvents, + }, + }); + } +} diff --git a/src/api/integrations/event/event.router.ts b/src/api/integrations/event/event.router.ts index 88ce6306..77de221c 100644 --- a/src/api/integrations/event/event.router.ts +++ b/src/api/integrations/event/event.router.ts @@ -1,7 +1,7 @@ -import { RabbitmqRouter } from '@api/integrations/event/rabbitmq/routes/rabbitmq.router'; -import { SqsRouter } from '@api/integrations/event/sqs/routes/sqs.router'; -import { WebhookRouter } from '@api/integrations/event/webhook/routes/webhook.router'; -import { WebsocketRouter } from '@api/integrations/event/websocket/routes/websocket.router'; +import { RabbitmqRouter } from '@api/integrations/event/rabbitmq/rabbitmq.router'; +import { SqsRouter } from '@api/integrations/event/sqs/sqs.router'; +import { WebhookRouter } from '@api/integrations/event/webhook/webhook.router'; +import { WebsocketRouter } from '@api/integrations/event/websocket/websocket.router'; import { Router } from 'express'; export class EventRouter { diff --git a/src/api/integrations/event/event.schema.ts b/src/api/integrations/event/event.schema.ts index 8bd1598d..98b152ea 100644 --- a/src/api/integrations/event/event.schema.ts +++ b/src/api/integrations/event/event.schema.ts @@ -1,4 +1,67 @@ -export * from '@api/integrations/event/rabbitmq/validate/rabbitmq.schema'; -export * from '@api/integrations/event/sqs/validate/sqs.schema'; -export * from '@api/integrations/event/webhook/validate/webhook.schema'; -export * from '@api/integrations/event/websocket/validate/websocket.schema'; +import { JSONSchema7 } from 'json-schema'; +import { v4 } from 'uuid'; + +export * from '@api/integrations/event/webhook/webhook.schema'; + +const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { + const properties = {}; + propertyNames.forEach( + (property) => + (properties[property] = { + minLength: 1, + description: `The "${property}" cannot be empty`, + }), + ); + return { + if: { + propertyNames: { + enum: [...propertyNames], + }, + }, + then: { properties }, + }; +}; + +export const eventSchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + enabled: { type: 'boolean', enum: [true, false] }, + events: { + type: 'array', + minItems: 0, + items: { + type: 'string', + enum: [ + 'APPLICATION_STARTUP', + 'QRCODE_UPDATED', + 'MESSAGES_SET', + 'MESSAGES_UPSERT', + 'MESSAGES_EDITED', + 'MESSAGES_UPDATE', + 'MESSAGES_DELETE', + 'SEND_MESSAGE', + 'CONTACTS_SET', + 'CONTACTS_UPSERT', + 'CONTACTS_UPDATE', + 'PRESENCE_UPDATE', + 'CHATS_SET', + 'CHATS_UPSERT', + 'CHATS_UPDATE', + 'CHATS_DELETE', + 'GROUPS_UPSERT', + 'GROUP_UPDATE', + 'GROUP_PARTICIPANTS_UPDATE', + 'CONNECTION_UPDATE', + 'LABELS_EDIT', + 'LABELS_ASSOCIATION', + 'CALL', + 'TYPEBOT_START', + 'TYPEBOT_CHANGE_STATUS', + ], + }, + }, + }, + required: ['enabled'], + ...isNotEmpty('enabled'), +}; diff --git a/src/api/integrations/event/rabbitmq/dto/rabbitmq.dto.ts b/src/api/integrations/event/rabbitmq/dto/rabbitmq.dto.ts deleted file mode 100644 index 7e7fb6db..00000000 --- a/src/api/integrations/event/rabbitmq/dto/rabbitmq.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Constructor } from '@api/integrations/integration.dto'; - -export class RabbitmqDto { - enabled: boolean; - events?: string[]; -} - -export function RabbitMQInstanceMixin(Base: TBase) { - return class extends Base { - rabbitmqEnabled?: boolean; - rabbitmqEvents?: string[]; - }; -} diff --git a/src/api/integrations/event/rabbitmq/controllers/rabbitmq.controller.ts b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts similarity index 77% rename from src/api/integrations/event/rabbitmq/controllers/rabbitmq.controller.ts rename to src/api/integrations/event/rabbitmq/rabbitmq.controller.ts index 304245c5..360bae17 100644 --- a/src/api/integrations/event/rabbitmq/controllers/rabbitmq.controller.ts +++ b/src/api/integrations/event/rabbitmq/rabbitmq.controller.ts @@ -1,37 +1,38 @@ -import { RabbitmqDto } from '@api/integrations/event/rabbitmq/dto/rabbitmq.dto'; import { PrismaRepository } from '@api/repository/repository.service'; import { WAMonitoringService } from '@api/services/monitor.service'; -import { wa } from '@api/types/wa.types'; import { configService, Log, Rabbitmq } from '@config/env.config'; import { Logger } from '@config/logger.config'; -import { NotFoundException } from '@exceptions'; import * as amqp from 'amqplib/callback_api'; -import { EmitData, EventController, EventControllerInterface } from '../../event.controller'; +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; export class RabbitmqController extends EventController implements EventControllerInterface { public amqpChannel: amqp.Channel | null = null; private readonly logger = new Logger(RabbitmqController.name); - integrationEnabled = configService.get('RABBITMQ')?.ENABLED; constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { - super(prismaRepository, waMonitor); + super(prismaRepository, waMonitor, configService.get('RABBITMQ')?.ENABLED, 'rabbitmq'); } public async init(): Promise { - if (!this.integrationEnabled) return; + if (!this.status) { + return; + } await new Promise((resolve, reject) => { const uri = configService.get('RABBITMQ').URI; + amqp.connect(uri, (error, connection) => { if (error) { reject(error); + return; } connection.createChannel((channelError, channel) => { if (channelError) { reject(channelError); + return; } @@ -45,6 +46,7 @@ export class RabbitmqController extends EventController implements EventControll this.amqpChannel = channel; this.logger.info('AMQP initialized'); + resolve(); }); }); @@ -61,57 +63,6 @@ export class RabbitmqController extends EventController implements EventControll return this.amqpChannel; } - public async set(instanceName: string, data: RabbitmqDto): Promise { - if (!this.integrationEnabled) return; - - if (!data.enabled) { - data.events = []; - } else { - if (0 === data.events.length) { - data.events = this.events; - } - } - - try { - await this.get(instanceName); - - return this.prisma.rabbitmq.update({ - where: { - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - data, - }); - } catch (err) { - return this.prisma.rabbitmq.create({ - data: { - enabled: data.enabled, - events: data.events, - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - }); - } - } - - public async get(instanceName: string): Promise { - if (!this.integrationEnabled) return; - - if (undefined === this.monitor.waInstances[instanceName]) { - throw new NotFoundException('Instance not found'); - } - - const data = await this.prisma.rabbitmq.findUnique({ - where: { - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - }); - - if (!data) { - throw new NotFoundException('Instance rabbitmq not found'); - } - - return data; - } - public async emit({ instanceName, origin, @@ -122,7 +73,9 @@ export class RabbitmqController extends EventController implements EventControll sender, apiKey, }: EmitData): Promise { - if (!this.integrationEnabled) return; + if (!this.status) { + return; + } const instanceRabbitmq = await this.get(instanceName); const rabbitmqLocal = instanceRabbitmq?.events; @@ -178,6 +131,7 @@ export class RabbitmqController extends EventController implements EventControll this.logger.log(logData); } + break; } catch (error) { retry++; @@ -231,10 +185,12 @@ export class RabbitmqController extends EventController implements EventControll private async initGlobalQueues(): Promise { this.logger.info('Initializing global queues'); + const events = configService.get('RABBITMQ').EVENTS; if (!events) { this.logger.warn('No events to initialize on AMQP'); + return; } diff --git a/src/api/integrations/event/rabbitmq/routes/rabbitmq.router.ts b/src/api/integrations/event/rabbitmq/rabbitmq.router.ts similarity index 62% rename from src/api/integrations/event/rabbitmq/routes/rabbitmq.router.ts rename to src/api/integrations/event/rabbitmq/rabbitmq.router.ts index 62d4db8b..997e1ca2 100644 --- a/src/api/integrations/event/rabbitmq/routes/rabbitmq.router.ts +++ b/src/api/integrations/event/rabbitmq/rabbitmq.router.ts @@ -1,9 +1,9 @@ import { RouterBroker } from '@api/abstract/abstract.router'; import { InstanceDto } from '@api/dto/instance.dto'; -import { RabbitmqDto } from '@api/integrations/event/rabbitmq/dto/rabbitmq.dto'; -import { rabbitmqController } from '@api/server.module'; +import { EventDto } from '@api/integrations/event/event.dto'; import { HttpStatus } from '@api/routes/index.router'; -import { instanceSchema, rabbitmqSchema } from '@validate/validate.schema'; +import { eventManager } from '@api/server.module'; +import { eventSchema, instanceSchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; export class RabbitmqRouter extends RouterBroker { @@ -11,11 +11,11 @@ export class RabbitmqRouter extends RouterBroker { super(); this.router .post(this.routerPath('set'), ...guards, async (req, res) => { - const response = await this.dataValidate({ + const response = await this.dataValidate({ request: req, - schema: rabbitmqSchema, - ClassRef: RabbitmqDto, - execute: (instance, data) => rabbitmqController.set(instance.instanceName, data), + schema: eventSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.rabbitmq.set(instance.instanceName, data), }); res.status(HttpStatus.CREATED).json(response); @@ -25,7 +25,7 @@ export class RabbitmqRouter extends RouterBroker { request: req, schema: instanceSchema, ClassRef: InstanceDto, - execute: (instance) => rabbitmqController.get(instance.instanceName), + execute: (instance) => eventManager.rabbitmq.get(instance.instanceName), }); res.status(HttpStatus.OK).json(response); diff --git a/src/api/integrations/event/rabbitmq/validate/rabbitmq.schema.ts b/src/api/integrations/event/rabbitmq/validate/rabbitmq.schema.ts deleted file mode 100644 index 1fedf607..00000000 --- a/src/api/integrations/event/rabbitmq/validate/rabbitmq.schema.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const rabbitmqSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_EDITED', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - ], - }, - }, - }, - required: ['enabled'], - ...isNotEmpty('enabled'), -}; diff --git a/src/api/integrations/event/sqs/dto/sqs.dto.ts b/src/api/integrations/event/sqs/dto/sqs.dto.ts deleted file mode 100644 index 8a2cfd9e..00000000 --- a/src/api/integrations/event/sqs/dto/sqs.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Constructor } from '@api/integrations/integration.dto'; - -export class SqsDto { - enabled: boolean; - events?: string[]; -} - -export function SQSInstanceMixin(Base: TBase) { - return class extends Base { - sqsEnabled?: boolean; - sqsEvents?: string[]; - }; -} diff --git a/src/api/integrations/event/sqs/controllers/sqs.controller.ts b/src/api/integrations/event/sqs/sqs.controller.ts similarity index 74% rename from src/api/integrations/event/sqs/controllers/sqs.controller.ts rename to src/api/integrations/event/sqs/sqs.controller.ts index d9d5a1fd..5256c63c 100644 --- a/src/api/integrations/event/sqs/controllers/sqs.controller.ts +++ b/src/api/integrations/event/sqs/sqs.controller.ts @@ -1,29 +1,27 @@ -import { SqsDto } from '@api/integrations/event/sqs/dto/sqs.dto'; import { PrismaRepository } from '@api/repository/repository.service'; import { WAMonitoringService } from '@api/services/monitor.service'; -import { wa } from '@api/types/wa.types'; import { SQS } from '@aws-sdk/client-sqs'; import { configService, Log, Sqs } from '@config/env.config'; import { Logger } from '@config/logger.config'; -import { NotFoundException } from '@exceptions'; -import { EmitData, EventController, EventControllerInterface } from '../../event.controller'; +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; export class SqsController extends EventController implements EventControllerInterface { private sqs: SQS; private readonly logger = new Logger(SqsController.name); - integrationEnabled = configService.get('SQS')?.ENABLED; constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { - super(prismaRepository, waMonitor); + super(prismaRepository, waMonitor, configService.get('SQS')?.ENABLED, 'sqs'); } public init(): void { - if (!this.integrationEnabled) return; + if (!this.status) { + return; + } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - new Promise((resolve, reject) => { + new Promise((resolve) => { const awsConfig = configService.get('SQS'); + this.sqs = new SQS({ credentials: { accessKeyId: awsConfig.ACCESS_KEY_ID, @@ -34,6 +32,7 @@ export class SqsController extends EventController implements EventControllerInt }); this.logger.info('SQS initialized'); + resolve(); }); } @@ -46,57 +45,6 @@ export class SqsController extends EventController implements EventControllerInt return this.sqs; } - public async set(instanceName: string, data: SqsDto): Promise { - if (!this.integrationEnabled) return; - - if (!data.enabled) { - data.events = []; - } else { - if (0 === data.events.length) { - data.events = this.events; - } - } - - try { - await this.get(instanceName); - - return this.prisma.sqs.update({ - where: { - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - data, - }); - } catch (err) { - return this.prisma.sqs.create({ - data: { - enabled: data.enabled, - events: data.events, - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - }); - } - } - - public async get(instanceName: string): Promise { - if (!this.integrationEnabled) return; - - if (undefined === this.monitor.waInstances[instanceName]) { - throw new NotFoundException('Instance not found'); - } - - const data = await this.prisma.sqs.findUnique({ - where: { - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - }); - - if (!data) { - throw new NotFoundException('Instance SQS not found'); - } - - return data; - } - public async emit({ instanceName, origin, @@ -107,7 +55,9 @@ export class SqsController extends EventController implements EventControllerInt sender, apiKey, }: EmitData): Promise { - if (!this.integrationEnabled) return; + if (!this.status) { + return; + } const instanceSqs = await this.get(instanceName); const sqsLocal = instanceSqs?.events; @@ -117,11 +67,8 @@ export class SqsController extends EventController implements EventControllerInt if (this.sqs) { if (Array.isArray(sqsLocal) && sqsLocal.includes(we)) { const eventFormatted = `${event.replace('.', '_').toLowerCase()}`; - const queueName = `${instanceName}_${eventFormatted}.fifo`; - const sqsConfig = configService.get('SQS'); - const sqsUrl = `https://sqs.${sqsConfig.REGION}.amazonaws.com/${sqsConfig.ACCOUNT_ID}/${queueName}`; const message = { diff --git a/src/api/integrations/event/sqs/routes/sqs.router.ts b/src/api/integrations/event/sqs/sqs.router.ts similarity index 64% rename from src/api/integrations/event/sqs/routes/sqs.router.ts rename to src/api/integrations/event/sqs/sqs.router.ts index 48e745f9..23f63f85 100644 --- a/src/api/integrations/event/sqs/routes/sqs.router.ts +++ b/src/api/integrations/event/sqs/sqs.router.ts @@ -1,9 +1,9 @@ import { RouterBroker } from '@api/abstract/abstract.router'; import { InstanceDto } from '@api/dto/instance.dto'; -import { SqsDto } from '@api/integrations/event/sqs/dto/sqs.dto'; -import { sqsController } from '@api/server.module'; +import { EventDto } from '@api/integrations/event/event.dto'; import { HttpStatus } from '@api/routes/index.router'; -import { instanceSchema, sqsSchema } from '@validate/validate.schema'; +import { eventManager } from '@api/server.module'; +import { eventSchema, instanceSchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; export class SqsRouter extends RouterBroker { @@ -11,11 +11,11 @@ export class SqsRouter extends RouterBroker { super(); this.router .post(this.routerPath('set'), ...guards, async (req, res) => { - const response = await this.dataValidate({ + const response = await this.dataValidate({ request: req, - schema: sqsSchema, - ClassRef: SqsDto, - execute: (instance, data) => sqsController.set(instance.instanceName, data), + schema: eventSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.sqs.set(instance.instanceName, data), }); res.status(HttpStatus.CREATED).json(response); @@ -25,7 +25,7 @@ export class SqsRouter extends RouterBroker { request: req, schema: instanceSchema, ClassRef: InstanceDto, - execute: (instance) => sqsController.get(instance.instanceName), + execute: (instance) => eventManager.sqs.get(instance.instanceName), }); res.status(HttpStatus.OK).json(response); diff --git a/src/api/integrations/event/sqs/validate/sqs.schema.ts b/src/api/integrations/event/sqs/validate/sqs.schema.ts deleted file mode 100644 index 4bea583c..00000000 --- a/src/api/integrations/event/sqs/validate/sqs.schema.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const sqsSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_EDITED', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - ], - }, - }, - }, - required: ['enabled'], - ...isNotEmpty('enabled'), -}; diff --git a/src/api/integrations/event/webhook/dto/webhook.dto.ts b/src/api/integrations/event/webhook/dto/webhook.dto.ts deleted file mode 100644 index be95e364..00000000 --- a/src/api/integrations/event/webhook/dto/webhook.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Constructor } from '@api/integrations/integration.dto'; - -export class WebhookDto { - enabled?: boolean; - url?: string; - events?: string[]; - webhookByEvents?: boolean; - webhookBase64?: boolean; -} - -export function WebhookInstanceMixin(Base: TBase) { - return class extends Base { - webhookUrl?: string; - webhookByEvents?: boolean; - webhookBase64?: boolean; - webhookEvents?: string[]; - }; -} diff --git a/src/api/integrations/event/webhook/controllers/webhook.controller.ts b/src/api/integrations/event/webhook/webhook.controller.ts similarity index 70% rename from src/api/integrations/event/webhook/controllers/webhook.controller.ts rename to src/api/integrations/event/webhook/webhook.controller.ts index 2f9699bb..0ce1b31c 100644 --- a/src/api/integrations/event/webhook/controllers/webhook.controller.ts +++ b/src/api/integrations/event/webhook/webhook.controller.ts @@ -1,74 +1,53 @@ +import { EventDto } from '@api/integrations/event/event.dto'; import { PrismaRepository } from '@api/repository/repository.service'; import { WAMonitoringService } from '@api/services/monitor.service'; import { wa } from '@api/types/wa.types'; import { configService, Log, Webhook } from '@config/env.config'; import { Logger } from '@config/logger.config'; -import { BadRequestException, NotFoundException } from '@exceptions'; +import { BadRequestException } from '@exceptions'; import axios from 'axios'; import { isURL } from 'class-validator'; -import { EmitData, EventController, EventControllerInterface } from '../../event.controller'; -import { WebhookDto } from '../dto/webhook.dto'; +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; export class WebhookController extends EventController implements EventControllerInterface { private readonly logger = new Logger(WebhookController.name); constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { - super(prismaRepository, waMonitor); + super(prismaRepository, waMonitor, true, 'webhook'); } - integrationEnabled: boolean; - public async set(instanceName: string, data: WebhookDto): Promise { - if (!isURL(data.url, { require_tld: false })) { + override async set(instanceName: string, data: EventDto): Promise { + if (!isURL(data.webhook.url, { require_tld: false })) { throw new BadRequestException('Invalid "url" property'); } - if (!data.enabled) { - data.events = []; + if (!data.webhook.enabled) { + data.webhook.events = []; } else { - if (0 === data.events.length) { - data.events = this.events; + if (0 === data.webhook.events.length) { + data.webhook.events = this.events; } } - await this.get(instanceName); - return this.prisma.webhook.upsert({ where: { instanceId: this.monitor.waInstances[instanceName].instanceId, }, update: { - ...data, + ...data.webhook, }, create: { - enabled: data.enabled, - events: data.events, + enabled: data.webhook.enabled, + events: data.webhook.events, instanceId: this.monitor.waInstances[instanceName].instanceId, - url: data.url, - webhookBase64: data.webhookBase64, - webhookByEvents: data.webhookByEvents, + url: data.webhook.url, + webhookBase64: data.webhook.base64, + webhookByEvents: data.webhook.byEvents, }, }); } - public async get(instanceName: string): Promise { - if (undefined === this.monitor.waInstances[instanceName]) { - throw new NotFoundException('Instance not found'); - } - - const data = await this.prisma.webhook.findUnique({ - where: { - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - }); - - if (!data) { - throw new NotFoundException('Instance webhook not found'); - } - - return data; - } - public async emit({ instanceName, origin, @@ -80,13 +59,14 @@ export class WebhookController extends EventController implements EventControlle apiKey, local, }: EmitData): Promise { - const instanceWebhook = await this.get(instanceName); - if (!instanceWebhook || !instanceWebhook.enabled) { + const instance = (await this.get(instanceName)) as EventDto; + + if (!instance || !instance.webhook.enabled) { return; } const webhookConfig = configService.get('WEBHOOK'); - const webhookLocal = instanceWebhook?.events; + const webhookLocal = instance.webhook?.events; const we = event.replace(/[.-]/gm, '_').toUpperCase(); const transformedWe = we.replace(/_/gm, '-').toLowerCase(); const enabledLog = configService.get('LOG').LEVEL.includes('WEBHOOKS'); @@ -95,7 +75,7 @@ export class WebhookController extends EventController implements EventControlle event, instance: instanceName, data, - destination: instanceWebhook?.url, + destination: instance.webhook?.url, date_time: dateTime, sender, server_url: serverUrl, @@ -106,10 +86,10 @@ export class WebhookController extends EventController implements EventControlle if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) { let baseURL: string; - if (instanceWebhook?.webhookByEvents) { - baseURL = `${instanceWebhook?.url}/${transformedWe}`; + if (instance.webhook?.byEvents) { + baseURL = `${instance.webhook?.url}/${transformedWe}`; } else { - baseURL = instanceWebhook?.url; + baseURL = instance.webhook?.url; } if (enabledLog) { @@ -123,7 +103,7 @@ export class WebhookController extends EventController implements EventControlle } try { - if (instanceWebhook?.enabled && isURL(instanceWebhook.url, { require_tld: false })) { + if (instance.webhook?.enabled && isURL(instance.webhook.url, { require_tld: false })) { const httpService = axios.create({ baseURL }); await httpService.post('', webhookData); @@ -190,12 +170,13 @@ export class WebhookController extends EventController implements EventControlle public async receiveWebhook(data: any) { if (data.object === 'whatsapp_business_account') { if (data.entry[0]?.changes[0]?.field === 'message_template_status_update') { - const template = await this.prismaRepository.template.findFirst({ + const template = await this.prisma.template.findFirst({ where: { templateId: `${data.entry[0].changes[0].value.message_template_id}` }, }); if (!template) { console.log('template not found'); + return; } @@ -209,29 +190,27 @@ export class WebhookController extends EventController implements EventControlle return; } - data.entry?.forEach(async (entry: any) => { + for (const entry of data.entry) { const numberId = entry.changes[0].value.metadata.phone_number_id; if (!numberId) { this.logger.error('WebhookService -> receiveWebhook -> numberId not found'); - return; + + continue; } - const instance = await this.prismaRepository.instance.findFirst({ + const instance = await this.prisma.instance.findFirst({ where: { number: numberId }, }); if (!instance) { this.logger.error('WebhookService -> receiveWebhook -> instance not found'); - return; + + continue; } - await this.waMonitor.waInstances[instance.name].connectToWhatsapp(data); - - return; - }); + await this.monitor.waInstances[instance.name].connectToWhatsapp(data); + } } - - return; } } diff --git a/src/api/integrations/event/webhook/routes/webhook.router.ts b/src/api/integrations/event/webhook/webhook.router.ts similarity index 76% rename from src/api/integrations/event/webhook/routes/webhook.router.ts rename to src/api/integrations/event/webhook/webhook.router.ts index af46d11d..dac00487 100644 --- a/src/api/integrations/event/webhook/routes/webhook.router.ts +++ b/src/api/integrations/event/webhook/webhook.router.ts @@ -1,23 +1,22 @@ import { RouterBroker } from '@api/abstract/abstract.router'; import { InstanceDto } from '@api/dto/instance.dto'; +import { EventDto } from '@api/integrations/event/event.dto'; import { HttpStatus } from '@api/routes/index.router'; -import { webhookController } from '@api/server.module'; +import { eventManager } from '@api/server.module'; import { ConfigService, WaBusiness } from '@config/env.config'; import { instanceSchema, webhookSchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; -import { WebhookDto } from '../dto/webhook.dto'; - export class WebhookRouter extends RouterBroker { constructor(readonly configService: ConfigService, ...guards: RequestHandler[]) { super(); this.router .post(this.routerPath('set'), ...guards, async (req, res) => { - const response = await this.dataValidate({ + const response = await this.dataValidate({ request: req, schema: webhookSchema, - ClassRef: WebhookDto, - execute: (instance, data) => webhookController.set(instance.instanceName, data), + ClassRef: EventDto, + execute: (instance, data) => eventManager.webhook.set(instance.instanceName, data), }); res.status(HttpStatus.CREATED).json(response); @@ -27,7 +26,7 @@ export class WebhookRouter extends RouterBroker { request: req, schema: instanceSchema, ClassRef: InstanceDto, - execute: (instance) => webhookController.get(instance.instanceName), + execute: (instance) => eventManager.webhook.get(instance.instanceName), }); res.status(HttpStatus.OK).json(response); @@ -39,7 +38,7 @@ export class WebhookRouter extends RouterBroker { }) .post('meta', async (req, res) => { const { body } = req; - const response = await webhookController.receiveWebhook(body); + const response = await eventManager.webhook.receiveWebhook(body); return res.status(200).json(response); }); diff --git a/src/api/integrations/event/webhook/validate/webhook.schema.ts b/src/api/integrations/event/webhook/webhook.schema.ts similarity index 100% rename from src/api/integrations/event/webhook/validate/webhook.schema.ts rename to src/api/integrations/event/webhook/webhook.schema.ts diff --git a/src/api/integrations/event/websocket/dto/websocket.dto.ts b/src/api/integrations/event/websocket/dto/websocket.dto.ts deleted file mode 100644 index 947c8fd3..00000000 --- a/src/api/integrations/event/websocket/dto/websocket.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Constructor } from '@api/integrations/integration.dto'; - -export class WebsocketDto { - enabled: boolean; - events?: string[]; -} - -export function WebsocketInstanceMixin(Base: TBase) { - return class extends Base { - websocketEnabled?: boolean; - websocketEvents?: string[]; - }; -} diff --git a/src/api/integrations/event/websocket/validate/websocket.schema.ts b/src/api/integrations/event/websocket/validate/websocket.schema.ts deleted file mode 100644 index 8a7678c1..00000000 --- a/src/api/integrations/event/websocket/validate/websocket.schema.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { JSONSchema7 } from 'json-schema'; -import { v4 } from 'uuid'; - -const isNotEmpty = (...propertyNames: string[]): JSONSchema7 => { - const properties = {}; - propertyNames.forEach( - (property) => - (properties[property] = { - minLength: 1, - description: `The "${property}" cannot be empty`, - }), - ); - return { - if: { - propertyNames: { - enum: [...propertyNames], - }, - }, - then: { properties }, - }; -}; - -export const websocketSchema: JSONSchema7 = { - $id: v4(), - type: 'object', - properties: { - enabled: { type: 'boolean', enum: [true, false] }, - events: { - type: 'array', - minItems: 0, - items: { - type: 'string', - enum: [ - 'APPLICATION_STARTUP', - 'QRCODE_UPDATED', - 'MESSAGES_SET', - 'MESSAGES_UPSERT', - 'MESSAGES_EDITED', - 'MESSAGES_UPDATE', - 'MESSAGES_DELETE', - 'SEND_MESSAGE', - 'CONTACTS_SET', - 'CONTACTS_UPSERT', - 'CONTACTS_UPDATE', - 'PRESENCE_UPDATE', - 'CHATS_SET', - 'CHATS_UPSERT', - 'CHATS_UPDATE', - 'CHATS_DELETE', - 'GROUPS_UPSERT', - 'GROUP_UPDATE', - 'GROUP_PARTICIPANTS_UPDATE', - 'CONNECTION_UPDATE', - 'LABELS_EDIT', - 'LABELS_ASSOCIATION', - 'CALL', - 'TYPEBOT_START', - 'TYPEBOT_CHANGE_STATUS', - ], - }, - }, - }, - required: ['enabled'], - ...isNotEmpty('enabled'), -}; diff --git a/src/api/integrations/event/websocket/controllers/websocket.controller.ts b/src/api/integrations/event/websocket/websocket.controller.ts similarity index 58% rename from src/api/integrations/event/websocket/controllers/websocket.controller.ts rename to src/api/integrations/event/websocket/websocket.controller.ts index 19c0977f..dd4a62c1 100644 --- a/src/api/integrations/event/websocket/controllers/websocket.controller.ts +++ b/src/api/integrations/event/websocket/websocket.controller.ts @@ -1,28 +1,28 @@ -import { WebsocketDto } from '@api/integrations/event/websocket/dto/websocket.dto'; +import { EventDto } from '@api/integrations/event/event.dto'; import { PrismaRepository } from '@api/repository/repository.service'; import { WAMonitoringService } from '@api/services/monitor.service'; -import { wa } from '@api/types/wa.types'; import { configService, Cors, Log, Websocket } from '@config/env.config'; import { Logger } from '@config/logger.config'; -import { NotFoundException } from '@exceptions'; import { Server } from 'http'; import { Server as SocketIO } from 'socket.io'; -import { EmitData, EventController, EventControllerInterface } from '../../event.controller'; +import { EmitData, EventController, EventControllerInterface } from '../event.controller'; export class WebsocketController extends EventController implements EventControllerInterface { private io: SocketIO; private corsConfig: Array; private readonly logger = new Logger(WebsocketController.name); - integrationEnabled = configService.get('WEBSOCKET')?.ENABLED; constructor(prismaRepository: PrismaRepository, waMonitor: WAMonitoringService) { - super(prismaRepository, waMonitor); + super(prismaRepository, waMonitor, configService.get('WEBSOCKET')?.ENABLED, 'websocket'); + this.cors = configService.get('CORS').ORIGIN; } public init(httpServer: Server): void { - if (!this.integrationEnabled) return; + if (!this.status) { + return; + } this.socket = new SocketIO(httpServer, { cors: { @@ -57,57 +57,6 @@ export class WebsocketController extends EventController implements EventControl return this.io; } - public async set(instanceName: string, data: WebsocketDto): Promise { - if (!this.integrationEnabled) return; - - if (!data.enabled) { - data.events = []; - } else { - if (0 === data.events.length) { - data.events = this.events; - } - } - - try { - await this.get(instanceName); - - return this.prisma.websocket.update({ - where: { - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - data, - }); - } catch (err) { - return this.prisma.websocket.create({ - data: { - enabled: data.enabled, - events: data.events, - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - }); - } - } - - public async get(instanceName: string): Promise { - if (!this.integrationEnabled) return; - - if (undefined === this.monitor.waInstances[instanceName]) { - throw new NotFoundException('Instance not found'); - } - - const data = await this.prisma.websocket.findUnique({ - where: { - instanceId: this.monitor.waInstances[instanceName].instanceId, - }, - }); - - if (!data) { - throw new NotFoundException('Instance websocket not found'); - } - - return data; - } - public async emit({ instanceName, origin, @@ -118,7 +67,9 @@ export class WebsocketController extends EventController implements EventControl sender, apiKey, }: EmitData): Promise { - if (!this.integrationEnabled) return; + if (!this.status) { + return; + } const configEv = event.replace(/[.-]/gm, '_').toUpperCase(); const logEnabled = configService.get('LOG').LEVEL.includes('WEBSOCKET'); @@ -144,13 +95,13 @@ export class WebsocketController extends EventController implements EventControl } try { - const instanceSocket = await this.get(instanceName); + const instance = (await this.get(instanceName)) as EventDto; - if (!instanceSocket?.enabled) { + if (!instance?.websocket.enabled) { return; } - if (Array.isArray(instanceSocket?.events) && instanceSocket?.events.includes(configEv)) { + if (Array.isArray(instance?.websocket.events) && instance?.websocket.events.includes(configEv)) { this.socket.of(`/${instanceName}`).emit(event, message); if (logEnabled) { diff --git a/src/api/integrations/event/websocket/routes/websocket.router.ts b/src/api/integrations/event/websocket/websocket.router.ts similarity index 62% rename from src/api/integrations/event/websocket/routes/websocket.router.ts rename to src/api/integrations/event/websocket/websocket.router.ts index f1a48281..4271245f 100644 --- a/src/api/integrations/event/websocket/routes/websocket.router.ts +++ b/src/api/integrations/event/websocket/websocket.router.ts @@ -1,9 +1,9 @@ import { RouterBroker } from '@api/abstract/abstract.router'; import { InstanceDto } from '@api/dto/instance.dto'; -import { WebsocketDto } from '@api/integrations/event/websocket/dto/websocket.dto'; -import { websocketController } from '@api/server.module'; +import { EventDto } from '@api/integrations/event/event.dto'; import { HttpStatus } from '@api/routes/index.router'; -import { instanceSchema, websocketSchema } from '@validate/validate.schema'; +import { eventManager } from '@api/server.module'; +import { eventSchema, instanceSchema } from '@validate/validate.schema'; import { RequestHandler, Router } from 'express'; export class WebsocketRouter extends RouterBroker { @@ -11,11 +11,11 @@ export class WebsocketRouter extends RouterBroker { super(); this.router .post(this.routerPath('set'), ...guards, async (req, res) => { - const response = await this.dataValidate({ + const response = await this.dataValidate({ request: req, - schema: websocketSchema, - ClassRef: WebsocketDto, - execute: (instance, data) => websocketController.set(instance.instanceName, data), + schema: eventSchema, + ClassRef: EventDto, + execute: (instance, data) => eventManager.websocket.set(instance.instanceName, data), }); res.status(HttpStatus.CREATED).json(response); @@ -25,7 +25,7 @@ export class WebsocketRouter extends RouterBroker { request: req, schema: instanceSchema, ClassRef: InstanceDto, - execute: (instance) => websocketController.get(instance.instanceName), + execute: (instance) => eventManager.websocket.get(instance.instanceName), }); res.status(HttpStatus.OK).json(response); diff --git a/src/api/integrations/integration.dto.ts b/src/api/integrations/integration.dto.ts index 6ccf9671..743364c5 100644 --- a/src/api/integrations/integration.dto.ts +++ b/src/api/integrations/integration.dto.ts @@ -1,11 +1,6 @@ import { ChatwootInstanceMixin } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto'; -import { RabbitMQInstanceMixin } from '@api/integrations/event/rabbitmq/dto/rabbitmq.dto'; -import { SQSInstanceMixin } from '@api/integrations/event/sqs/dto/sqs.dto'; -import { WebhookInstanceMixin } from '@api/integrations/event/webhook/dto/webhook.dto'; -import { WebsocketInstanceMixin } from '@api/integrations/event/websocket/dto/websocket.dto'; +import { EventInstanceMixin } from '@api/integrations/event/event.dto'; export type Constructor = new (...args: any[]) => T; -export class IntegrationDto extends WebhookInstanceMixin( - WebsocketInstanceMixin(RabbitMQInstanceMixin(SQSInstanceMixin(ChatwootInstanceMixin(class {})))), -) {} +export class IntegrationDto extends EventInstanceMixin(ChatwootInstanceMixin(class {})) {} diff --git a/src/api/server.module.ts b/src/api/server.module.ts index f42c6364..fd434746 100644 --- a/src/api/server.module.ts +++ b/src/api/server.module.ts @@ -23,11 +23,7 @@ import { OpenaiController } from './integrations/chatbot/openai/controllers/open import { OpenaiService } from './integrations/chatbot/openai/services/openai.service'; import { TypebotController } from './integrations/chatbot/typebot/controllers/typebot.controller'; import { TypebotService } from './integrations/chatbot/typebot/services/typebot.service'; -import { EventController } from './integrations/event/event.controller'; -import { RabbitmqController } from './integrations/event/rabbitmq/controllers/rabbitmq.controller'; -import { SqsController } from './integrations/event/sqs/controllers/sqs.controller'; -import { WebhookController } from './integrations/event/webhook/controllers/webhook.controller'; -import { WebsocketController } from './integrations/event/websocket/controllers/websocket.controller'; +import { EventManager } from './integrations/event/event.manager'; import { S3Controller } from './integrations/storage/s3/controllers/s3.controller'; import { S3Service } from './integrations/storage/s3/services/s3.service'; import { ProviderFiles } from './provider/sessions'; @@ -98,16 +94,10 @@ export const chatController = new ChatController(waMonitor); export const groupController = new GroupController(waMonitor); export const labelController = new LabelController(waMonitor); -export const eventController = new EventController(prismaRepository, waMonitor); +export const eventManager = new EventManager(prismaRepository, waMonitor); export const chatbotController = new ChatbotController(prismaRepository, waMonitor); export const channelController = new ChannelController(); -// events -export const websocketController = new WebsocketController(prismaRepository, waMonitor); -export const rabbitmqController = new RabbitmqController(prismaRepository, waMonitor); -export const sqsController = new SqsController(prismaRepository, waMonitor); -export const webhookController = new WebhookController(prismaRepository, waMonitor); - // chatbots const typebotService = new TypebotService(waMonitor, configService, prismaRepository); export const typebotController = new TypebotController(typebotService, prismaRepository, waMonitor); diff --git a/src/api/services/channel.service.ts b/src/api/services/channel.service.ts index 26e9253f..1227b25b 100644 --- a/src/api/services/channel.service.ts +++ b/src/api/services/channel.service.ts @@ -7,7 +7,7 @@ import { DifyService } from '@api/integrations/chatbot/dify/services/dify.servic import { OpenaiService } from '@api/integrations/chatbot/openai/services/openai.service'; import { TypebotService } from '@api/integrations/chatbot/typebot/services/typebot.service'; import { PrismaRepository, Query } from '@api/repository/repository.service'; -import { eventController, waMonitor } from '@api/server.module'; +import { eventManager, waMonitor } from '@api/server.module'; import { Events, wa } from '@api/types/wa.types'; import { Auth, Chatwoot, ConfigService, HttpServer } from '@config/env.config'; import { Logger } from '@config/logger.config'; @@ -392,7 +392,7 @@ export class ChannelStartupService { const instanceApikey = this.token || 'Apikey not found'; - await eventController.emit({ + await eventManager.emit({ instanceName: this.instance.name, origin: ChannelStartupService.name, event, diff --git a/src/api/types/wa.types.ts b/src/api/types/wa.types.ts index 7004592f..9a6ed7a3 100644 --- a/src/api/types/wa.types.ts +++ b/src/api/types/wa.types.ts @@ -60,14 +60,6 @@ export declare namespace wa { businessId?: string; }; - export type LocalWebHook = { - enabled?: boolean; - url?: string; - events?: JsonValue; - webhookByEvents?: boolean; - webhookBase64?: boolean; - }; - export type LocalChatwoot = { enabled?: boolean; accountId?: string; @@ -95,19 +87,15 @@ export declare namespace wa { syncFullHistory?: boolean; }; - export type LocalWebsocket = { + export type LocalEvent = { enabled?: boolean; events?: JsonValue; }; - export type LocalRabbitmq = { - enabled?: boolean; - events?: JsonValue; - }; - - export type LocalSqs = { - enabled?: boolean; - events?: JsonValue; + export type LocalWebHook = LocalEvent & { + url?: string; + webhookByEvents?: boolean; + webhookBase64?: boolean; }; type Session = { diff --git a/src/main.ts b/src/main.ts index 62346983..a63325f1 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,7 @@ import { ProviderFiles } from '@api/provider/sessions'; import { PrismaRepository } from '@api/repository/repository.service'; import { HttpStatus, router } from '@api/routes/index.router'; -import { eventController, waMonitor } from '@api/server.module'; +import { eventManager, waMonitor } from '@api/server.module'; import { Auth, configService, Cors, HttpServer, ProviderSession, Webhook } from '@config/env.config'; import { onUnexpectedError } from '@config/error.config'; import { Logger } from '@config/logger.config'; @@ -139,7 +139,7 @@ async function bootstrap() { ServerUP.app = app; const server = ServerUP[httpServer.TYPE]; - eventController.init(server); + eventManager.init(server); server.listen(httpServer.PORT, () => logger.log(httpServer.TYPE.toUpperCase() + ' - ON: ' + httpServer.PORT));