From e58f1d778e9db3d81fd2d5e3182102e6df08ce9e Mon Sep 17 00:00:00 2001 From: Diego Vieira Date: Tue, 19 Mar 2024 00:58:45 +0000 Subject: [PATCH 1/3] feat(endpoint): add setPresence endpoint --- src/validate/validate.schema.ts | 12 ++++++++++++ src/whatsapp/controllers/chat.controller.ts | 6 ++++++ src/whatsapp/dto/chat.dto.ts | 4 ++++ src/whatsapp/routers/chat.router.ts | 18 ++++++++++++++++++ .../services/whatsapp.baileys.service.ts | 13 ++++++++++++- .../services/whatsapp.business.service.ts | 3 +++ 6 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/validate/validate.schema.ts b/src/validate/validate.schema.ts index faaf2fa1..82bb8902 100644 --- a/src/validate/validate.schema.ts +++ b/src/validate/validate.schema.ts @@ -161,6 +161,18 @@ export const presenceSchema: JSONSchema7 = { required: ['options', 'number'], }; +export const presenceOnlySchema: JSONSchema7 = { + $id: v4(), + type: 'object', + properties: { + presence: { + type: 'string', + enum: ['unavailable', 'available', 'composing', 'recording', 'paused'], + }, + }, + required: ['presence'], +}; + export const pollMessageSchema: JSONSchema7 = { $id: v4(), type: 'object', diff --git a/src/whatsapp/controllers/chat.controller.ts b/src/whatsapp/controllers/chat.controller.ts index 1c16260d..64a9cc82 100644 --- a/src/whatsapp/controllers/chat.controller.ts +++ b/src/whatsapp/controllers/chat.controller.ts @@ -11,6 +11,7 @@ import { ProfileStatusDto, ReadMessageDto, SendPresenceDto, + SetPresenceDto, UpdateMessageDto, WhatsAppNumberDto, } from '../dto/chat.dto'; @@ -85,6 +86,11 @@ export class ChatController { return await this.waMonitor.waInstances[instanceName].sendPresence(data); } + public async setPresence({ instanceName }: InstanceDto, data: SetPresenceDto) { + logger.verbose('requested sendPresence from ' + instanceName + ' instance'); + return await this.waMonitor.waInstances[instanceName].setPresence(data); + } + public async fetchPrivacySettings({ instanceName }: InstanceDto) { logger.verbose('requested fetchPrivacySettings from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings(); diff --git a/src/whatsapp/dto/chat.dto.ts b/src/whatsapp/dto/chat.dto.ts index 24f04847..c97e1ae5 100644 --- a/src/whatsapp/dto/chat.dto.ts +++ b/src/whatsapp/dto/chat.dto.ts @@ -110,6 +110,10 @@ export class SendPresenceDto extends Metadata { }; } +export class SetPresenceDto { + presence: WAPresence; +} + export class UpdateMessageDto extends Metadata { number: string; key: proto.IMessageKey; diff --git a/src/whatsapp/routers/chat.router.ts b/src/whatsapp/routers/chat.router.ts index a0ce3216..8a1585a3 100644 --- a/src/whatsapp/routers/chat.router.ts +++ b/src/whatsapp/routers/chat.router.ts @@ -9,6 +9,7 @@ import { messageUpSchema, messageValidateSchema, presenceSchema, + presenceOnlySchema, privacySettingsSchema, profileNameSchema, profilePictureSchema, @@ -31,6 +32,7 @@ import { ProfileStatusDto, ReadMessageDto, SendPresenceDto, + SetPresenceDto, UpdateMessageDto, WhatsAppNumberDto, } from '../dto/chat.dto'; @@ -250,6 +252,22 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) + .post(this.routerPath('setPresence'), ...guards, async (req, res) => { + logger.verbose('request received in setPresence'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: presenceOnlySchema, + ClassRef: SetPresenceDto, + execute: (instance, data) => chatController.setPresence(instance, data), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) // Profile routes .get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => { logger.verbose('request received in fetchPrivacySettings'); diff --git a/src/whatsapp/services/whatsapp.baileys.service.ts b/src/whatsapp/services/whatsapp.baileys.service.ts index a081b5b7..f7a50013 100644 --- a/src/whatsapp/services/whatsapp.baileys.service.ts +++ b/src/whatsapp/services/whatsapp.baileys.service.ts @@ -72,6 +72,7 @@ import { PrivacySettingDto, ReadMessageDto, SendPresenceDto, + SetPresenceDto, UpdateMessageDto, WhatsAppNumberDto, } from '../dto/chat.dto'; @@ -1830,7 +1831,6 @@ export class BaileysStartupService extends WAStartupService { } // Instance Controller - public async sendPresence(data: SendPresenceDto) { try { const { number } = data; @@ -1863,6 +1863,17 @@ export class BaileysStartupService extends WAStartupService { } } + // Presence Controller + public async setPresence(data: SetPresenceDto) { + try { + await this.client.sendPresenceUpdate(data.presence); + this.logger.verbose('Sending presence update: ' + data.presence); + } catch (error) { + this.logger.error(error); + throw new BadRequestException(error.toString()); + } + } + // Send Message Controller public async textMessage(data: SendTextDto, isChatwoot = false) { this.logger.verbose('Sending text message'); diff --git a/src/whatsapp/services/whatsapp.business.service.ts b/src/whatsapp/services/whatsapp.business.service.ts index 0d4f723c..874e75dc 100644 --- a/src/whatsapp/services/whatsapp.business.service.ts +++ b/src/whatsapp/services/whatsapp.business.service.ts @@ -1185,6 +1185,9 @@ export class BusinessStartupService extends WAStartupService { public async sendPresence() { throw new BadRequestException('Method not available on WhatsApp Business API'); } + public async setPresence() { + throw new BadRequestException('Method not available on WhatsApp Business API'); + } public async fetchPrivacySettings() { throw new BadRequestException('Method not available on WhatsApp Business API'); } From 5400f31acb7ac3209da695322a5242c673928924 Mon Sep 17 00:00:00 2001 From: Diego Vieira Date: Tue, 19 Mar 2024 08:31:53 +0000 Subject: [PATCH 2/3] feat(endpoint): move setPresence endpoint to instance --- src/whatsapp/controllers/chat.controller.ts | 6 ------ .../controllers/instance.controller.ts | 7 ++++++- src/whatsapp/dto/chat.dto.ts | 4 ---- src/whatsapp/dto/instance.dto.ts | 6 ++++++ src/whatsapp/routers/chat.router.ts | 17 ---------------- src/whatsapp/routers/instance.router.ts | 20 +++++++++++++++++-- .../services/whatsapp.baileys.service.ts | 3 +-- 7 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/whatsapp/controllers/chat.controller.ts b/src/whatsapp/controllers/chat.controller.ts index 64a9cc82..1c16260d 100644 --- a/src/whatsapp/controllers/chat.controller.ts +++ b/src/whatsapp/controllers/chat.controller.ts @@ -11,7 +11,6 @@ import { ProfileStatusDto, ReadMessageDto, SendPresenceDto, - SetPresenceDto, UpdateMessageDto, WhatsAppNumberDto, } from '../dto/chat.dto'; @@ -86,11 +85,6 @@ export class ChatController { return await this.waMonitor.waInstances[instanceName].sendPresence(data); } - public async setPresence({ instanceName }: InstanceDto, data: SetPresenceDto) { - logger.verbose('requested sendPresence from ' + instanceName + ' instance'); - return await this.waMonitor.waInstances[instanceName].setPresence(data); - } - public async fetchPrivacySettings({ instanceName }: InstanceDto) { logger.verbose('requested fetchPrivacySettings from ' + instanceName + ' instance'); return await this.waMonitor.waInstances[instanceName].fetchPrivacySettings(); diff --git a/src/whatsapp/controllers/instance.controller.ts b/src/whatsapp/controllers/instance.controller.ts index e106aca7..91103e33 100644 --- a/src/whatsapp/controllers/instance.controller.ts +++ b/src/whatsapp/controllers/instance.controller.ts @@ -7,7 +7,7 @@ import { ConfigService, HttpServer, WaBusiness } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { BadRequestException, InternalServerErrorException } from '../../exceptions'; import { RedisCache } from '../../libs/redis.client'; -import { InstanceDto } from '../dto/instance.dto'; +import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; import { RepositoryBroker } from '../repository/repository.manager'; import { AuthService, OldToken } from '../services/auth.service'; import { CacheService } from '../services/cache.service'; @@ -656,6 +656,11 @@ export class InstanceController { return this.waMonitor.instanceInfo(); } + public async setPresence({ instanceName }: InstanceDto, data: SetPresenceDto) { + this.logger.verbose('requested sendPresence from ' + instanceName + ' instance'); + return await this.waMonitor.waInstances[instanceName].setPresence(data); + } + public async logout({ instanceName }: InstanceDto) { this.logger.verbose('requested logout from ' + instanceName + ' instance'); const { instance } = await this.connectionState({ instanceName }); diff --git a/src/whatsapp/dto/chat.dto.ts b/src/whatsapp/dto/chat.dto.ts index c97e1ae5..24f04847 100644 --- a/src/whatsapp/dto/chat.dto.ts +++ b/src/whatsapp/dto/chat.dto.ts @@ -110,10 +110,6 @@ export class SendPresenceDto extends Metadata { }; } -export class SetPresenceDto { - presence: WAPresence; -} - export class UpdateMessageDto extends Metadata { number: string; key: proto.IMessageKey; diff --git a/src/whatsapp/dto/instance.dto.ts b/src/whatsapp/dto/instance.dto.ts index f03f4c8e..eaf21aab 100644 --- a/src/whatsapp/dto/instance.dto.ts +++ b/src/whatsapp/dto/instance.dto.ts @@ -1,3 +1,5 @@ +import { WAPresence } from "@whiskeysockets/baileys"; + export class InstanceDto { instanceName: string; instanceId?: string; @@ -40,3 +42,7 @@ export class InstanceDto { typebot_listening_from_me?: boolean; proxy?: string; } + +export class SetPresenceDto { + presence: WAPresence; +} diff --git a/src/whatsapp/routers/chat.router.ts b/src/whatsapp/routers/chat.router.ts index 8a1585a3..d8096c79 100644 --- a/src/whatsapp/routers/chat.router.ts +++ b/src/whatsapp/routers/chat.router.ts @@ -32,7 +32,6 @@ import { ProfileStatusDto, ReadMessageDto, SendPresenceDto, - SetPresenceDto, UpdateMessageDto, WhatsAppNumberDto, } from '../dto/chat.dto'; @@ -252,22 +251,6 @@ export class ChatRouter extends RouterBroker { return res.status(HttpStatus.CREATED).json(response); }) - .post(this.routerPath('setPresence'), ...guards, async (req, res) => { - logger.verbose('request received in setPresence'); - logger.verbose('request body: '); - logger.verbose(req.body); - - logger.verbose('request query: '); - logger.verbose(req.query); - const response = await this.dataValidate({ - request: req, - schema: presenceOnlySchema, - ClassRef: SetPresenceDto, - execute: (instance, data) => chatController.setPresence(instance, data), - }); - - return res.status(HttpStatus.CREATED).json(response); - }) // Profile routes .get(this.routerPath('fetchPrivacySettings'), ...guards, async (req, res) => { logger.verbose('request received in fetchPrivacySettings'); diff --git a/src/whatsapp/routers/instance.router.ts b/src/whatsapp/routers/instance.router.ts index 96a1a5da..6d4727e2 100644 --- a/src/whatsapp/routers/instance.router.ts +++ b/src/whatsapp/routers/instance.router.ts @@ -3,9 +3,9 @@ import { RequestHandler, Router } from 'express'; import { Auth, ConfigService, Database } from '../../config/env.config'; import { Logger } from '../../config/logger.config'; import { dbserver } from '../../libs/db.connect'; -import { instanceNameSchema, oldTokenSchema } from '../../validate/validate.schema'; +import {instanceNameSchema, oldTokenSchema, presenceOnlySchema} from '../../validate/validate.schema'; import { RouterBroker } from '../abstract/abstract.router'; -import { InstanceDto } from '../dto/instance.dto'; +import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; import { OldToken } from '../services/auth.service'; import { instanceController } from '../whatsapp.module'; import { HttpStatus } from './index.router'; @@ -98,6 +98,22 @@ export class InstanceRouter extends RouterBroker { return res.status(HttpStatus.OK).json(response); }) + .post(this.routerPath('setPresence'), ...guards, async (req, res) => { + logger.verbose('request received in setPresence'); + logger.verbose('request body: '); + logger.verbose(req.body); + + logger.verbose('request query: '); + logger.verbose(req.query); + const response = await this.dataValidate({ + request: req, + schema: presenceOnlySchema, + ClassRef: SetPresenceDto, + execute: (instance, data) => instanceController.setPresence(instance, data), + }); + + return res.status(HttpStatus.CREATED).json(response); + }) .delete(this.routerPath('logout'), ...guards, async (req, res) => { logger.verbose('request received in logoutInstances'); logger.verbose('request body: '); diff --git a/src/whatsapp/services/whatsapp.baileys.service.ts b/src/whatsapp/services/whatsapp.baileys.service.ts index f7a50013..e9e7147a 100644 --- a/src/whatsapp/services/whatsapp.baileys.service.ts +++ b/src/whatsapp/services/whatsapp.baileys.service.ts @@ -72,7 +72,6 @@ import { PrivacySettingDto, ReadMessageDto, SendPresenceDto, - SetPresenceDto, UpdateMessageDto, WhatsAppNumberDto, } from '../dto/chat.dto'; @@ -90,7 +89,7 @@ import { GroupUpdateParticipantDto, GroupUpdateSettingDto, } from '../dto/group.dto'; -import { InstanceDto } from '../dto/instance.dto'; +import { InstanceDto, SetPresenceDto } from '../dto/instance.dto'; import { HandleLabelDto, LabelDto } from '../dto/label.dto'; import { ContactMessage, From 950803b2aa97cd9020245f0137e906cf9cfbba24 Mon Sep 17 00:00:00 2001 From: Davidson Gomes Date: Wed, 27 Mar 2024 09:54:05 -0300 Subject: [PATCH 3/3] rabbitmq --- package.json | 2 +- src/libs/amqp.server.ts | 7 +++---- src/whatsapp/services/whatsapp.service.ts | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 0907228d..705138ca 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "cross-env": "^7.0.3", "dayjs": "^1.11.7", "eventemitter2": "^6.4.9", - "evolution-manager": "^0.4.11", + "evolution-manager": "^0.4.13", "exiftool-vendored": "^22.0.0", "express": "^4.18.2", "express-async-errors": "^3.1.1", diff --git a/src/libs/amqp.server.ts b/src/libs/amqp.server.ts index fc95b33c..b76d2d10 100644 --- a/src/libs/amqp.server.ts +++ b/src/libs/amqp.server.ts @@ -10,6 +10,7 @@ let amqpChannel: amqp.Channel | null = null; export const initAMQP = () => { return new Promise((resolve, reject) => { const uri = configService.get('RABBITMQ').URI; + const exchangeName = configService.get('RABBITMQ').EXCHANGE_NAME ?? 'evolution_exchange'; amqp.connect(uri, (error, connection) => { if (error) { reject(error); @@ -22,8 +23,6 @@ export const initAMQP = () => { return; } - const exchangeName = 'evolution_exchange'; - channel.assertExchange(exchangeName, 'topic', { durable: true, autoDelete: false, @@ -51,7 +50,7 @@ export const initQueues = (instanceName: string, events: string[]) => { queues.forEach((event) => { const amqp = getAMQP(); - const exchangeName = instanceName ?? 'evolution_exchange'; + const exchangeName = configService.get('RABBITMQ').EXCHANGE_NAME ?? instanceName; amqp.assertExchange(exchangeName, 'topic', { durable: true, @@ -81,7 +80,7 @@ export const removeQueues = (instanceName: string, events: string[]) => { return `${event.replace(/_/g, '.').toLowerCase()}`; }); - const exchangeName = instanceName ?? 'evolution_exchange'; + const exchangeName = configService.get('RABBITMQ').EXCHANGE_NAME ?? instanceName; queues.forEach((event) => { const amqp = getAMQP(); diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index 29c58f6c..f861df2d 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -13,6 +13,7 @@ import { Database, HttpServer, Log, + Rabbitmq, Sqs, Webhook, Websocket, @@ -685,7 +686,7 @@ export class WAStartupService { if (amqp) { if (Array.isArray(rabbitmqLocal) && rabbitmqLocal.includes(we)) { - const exchangeName = this.instanceName ?? 'evolution_exchange'; + const exchangeName = this.configService.get('RABBITMQ').EXCHANGE_NAME ?? this.instanceName; amqp.assertExchange(exchangeName, 'topic', { durable: true,