mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-14 09:51:24 -06:00
feat: chatwoot integration completed
This commit is contained in:
parent
514fb56209
commit
052303cc93
@ -45,4 +45,11 @@ export class ChatwootController {
|
|||||||
logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance');
|
logger.verbose('requested findChatwoot from ' + instance.instanceName + ' instance');
|
||||||
return this.chatwootService.find(instance);
|
return this.chatwootService.find(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async receiveWebhook(instance: InstanceDto, data: any) {
|
||||||
|
logger.verbose(
|
||||||
|
'requested receiveWebhook from ' + instance.instanceName + ' instance',
|
||||||
|
);
|
||||||
|
return this.chatwootService.receiveWebhook(instance, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { dbserver } from '../../db/db.connect';
|
|||||||
|
|
||||||
export class ChatwootRaw {
|
export class ChatwootRaw {
|
||||||
_id?: string;
|
_id?: string;
|
||||||
|
enabled?: boolean;
|
||||||
account_id?: string;
|
account_id?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
@ -11,6 +12,7 @@ export class ChatwootRaw {
|
|||||||
|
|
||||||
const chatwootSchema = new Schema<ChatwootRaw>({
|
const chatwootSchema = new Schema<ChatwootRaw>({
|
||||||
_id: { type: String, _id: true },
|
_id: { type: String, _id: true },
|
||||||
|
enabled: { type: Boolean, required: true },
|
||||||
account_id: { type: String, required: true },
|
account_id: { type: String, required: true },
|
||||||
token: { type: String, required: true },
|
token: { type: String, required: true },
|
||||||
url: { type: String, required: true },
|
url: { type: String, required: true },
|
||||||
|
@ -46,11 +46,21 @@ export class ChatwootRouter extends RouterBroker {
|
|||||||
|
|
||||||
res.status(HttpStatus.OK).json(response);
|
res.status(HttpStatus.OK).json(response);
|
||||||
})
|
})
|
||||||
.post(this.routerPath('webhook'), ...guards, async (req, res) => {
|
.post(this.routerPath('webhook'), async (req, res) => {
|
||||||
const { body } = req;
|
logger.verbose('request received in findChatwoot');
|
||||||
const { instance } = req.query;
|
logger.verbose('request body: ');
|
||||||
|
logger.verbose(req.body);
|
||||||
|
|
||||||
res.status(HttpStatus.OK).json({ message: 'bot' });
|
logger.verbose('request query: ');
|
||||||
|
logger.verbose(req.query);
|
||||||
|
const response = await this.dataValidate<InstanceDto>({
|
||||||
|
request: req,
|
||||||
|
schema: instanceNameSchema,
|
||||||
|
ClassRef: InstanceDto,
|
||||||
|
execute: (instance, data) => chatwootController.receiveWebhook(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(HttpStatus.OK).json(response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import { InstanceDto } from '../dto/instance.dto';
|
import { InstanceDto } from '../dto/instance.dto';
|
||||||
|
import path from 'path';
|
||||||
import { ChatwootDto } from '../dto/chatwoot.dto';
|
import { ChatwootDto } from '../dto/chatwoot.dto';
|
||||||
import { WAMonitoringService } from './monitor.service';
|
import { WAMonitoringService } from './monitor.service';
|
||||||
import { Logger } from '../../config/logger.config';
|
import { Logger } from '../../config/logger.config';
|
||||||
import ChatwootClient from '@figuro/chatwoot-sdk';
|
import ChatwootClient from '@figuro/chatwoot-sdk';
|
||||||
import { createReadStream, unlinkSync } from 'fs';
|
import { createReadStream, unlinkSync, writeFileSync } from 'fs';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
|
import { SendTextDto } from '../dto/sendMessage.dto';
|
||||||
|
import mimeTypes from 'mime-types';
|
||||||
|
import { SendAudioDto } from '../dto/sendMessage.dto';
|
||||||
|
import { SendMediaDto } from '../dto/sendMessage.dto';
|
||||||
|
|
||||||
export class ChatwootService {
|
export class ChatwootService {
|
||||||
constructor(private readonly waMonitor: WAMonitoringService) {}
|
constructor(private readonly waMonitor: WAMonitoringService) {}
|
||||||
@ -71,7 +76,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contact = await client.contact.getContactable({
|
const contact = await client.contact.getContactable({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
id,
|
id,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -92,7 +97,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contact = await client.contacts.create({
|
const contact = await client.contacts.create({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
data: {
|
data: {
|
||||||
inbox_id: inboxId,
|
inbox_id: inboxId,
|
||||||
name: name || phoneNumber,
|
name: name || phoneNumber,
|
||||||
@ -115,7 +120,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contact = await client.contacts.update({
|
const contact = await client.contacts.update({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
id,
|
id,
|
||||||
data,
|
data,
|
||||||
});
|
});
|
||||||
@ -131,7 +136,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const contact = await client.contacts.search({
|
const contact = await client.contacts.search({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
q: `+${phoneNumber}`,
|
q: `+${phoneNumber}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -145,8 +150,8 @@ export class ChatwootService {
|
|||||||
throw new Error('client not found');
|
throw new Error('client not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatId = body.data.key.remoteJid.split('@')[0];
|
const chatId = body.key.remoteJid.split('@')[0];
|
||||||
const nameContact = !body.data.key.fromMe ? body.data.pushName : chatId;
|
const nameContact = !body.key.fromMe ? body.pushName : chatId;
|
||||||
|
|
||||||
const filterInbox = await this.getInbox(instance);
|
const filterInbox = await this.getInbox(instance);
|
||||||
|
|
||||||
@ -156,14 +161,14 @@ export class ChatwootService {
|
|||||||
|
|
||||||
const contactId = contact.id || contact.payload.contact.id;
|
const contactId = contact.id || contact.payload.contact.id;
|
||||||
|
|
||||||
if (!body.data.key.fromMe && contact.name === chatId && nameContact !== chatId) {
|
if (!body.key.fromMe && contact.name === chatId && nameContact !== chatId) {
|
||||||
await this.updateContact(instance, contactId, {
|
await this.updateContact(instance, contactId, {
|
||||||
name: nameContact,
|
name: nameContact,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const contactConversations = (await client.contacts.listConversations({
|
const contactConversations = (await client.contacts.listConversations({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
id: contactId,
|
id: contactId,
|
||||||
})) as any;
|
})) as any;
|
||||||
|
|
||||||
@ -178,7 +183,7 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const conversation = await client.conversations.create({
|
const conversation = await client.conversations.create({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
data: {
|
data: {
|
||||||
contact_id: `${contactId}`,
|
contact_id: `${contactId}`,
|
||||||
inbox_id: `${filterInbox.id}`,
|
inbox_id: `${filterInbox.id}`,
|
||||||
@ -196,9 +201,12 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const inbox = (await client.inboxes.list({
|
const inbox = (await client.inboxes.list({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
})) as any;
|
})) as any;
|
||||||
const findByName = inbox.payload.find((inbox) => inbox.name === instance);
|
|
||||||
|
const findByName = inbox.payload.find(
|
||||||
|
(inbox) => inbox.name === instance.instanceName,
|
||||||
|
);
|
||||||
return findByName;
|
return findByName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +224,7 @@ export class ChatwootService {
|
|||||||
const client = await this.clientCw(instance);
|
const client = await this.clientCw(instance);
|
||||||
|
|
||||||
const message = await client.messages.create({
|
const message = await client.messages.create({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
conversationId: conversationId,
|
conversationId: conversationId,
|
||||||
data: {
|
data: {
|
||||||
content: content,
|
content: content,
|
||||||
@ -245,16 +253,17 @@ export class ChatwootService {
|
|||||||
const filterInbox = await this.getInbox(instance);
|
const filterInbox = await this.getInbox(instance);
|
||||||
|
|
||||||
const findConversation = await client.conversations.list({
|
const findConversation = await client.conversations.list({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
inboxId: filterInbox.id,
|
inboxId: filterInbox.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const conversation = findConversation.data.payload.find(
|
const conversation = findConversation.data.payload.find(
|
||||||
(conversation) =>
|
(conversation) =>
|
||||||
conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
conversation?.meta?.sender?.id === contact.id && conversation.status === 'open',
|
||||||
);
|
);
|
||||||
|
|
||||||
const message = await client.messages.create({
|
const message = await client.messages.create({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
conversationId: conversation.id,
|
conversationId: conversation.id,
|
||||||
data: {
|
data: {
|
||||||
content: content,
|
content: content,
|
||||||
@ -285,7 +294,7 @@ export class ChatwootService {
|
|||||||
const config = {
|
const config = {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
maxBodyLength: Infinity,
|
maxBodyLength: Infinity,
|
||||||
url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${conversationId}/messages`,
|
url: `${this.provider.url}/api/v1/accounts/${this.provider.account_id}/conversations/${conversationId}/messages`,
|
||||||
headers: {
|
headers: {
|
||||||
api_access_token: this.provider.token,
|
api_access_token: this.provider.token,
|
||||||
...data.getHeaders(),
|
...data.getHeaders(),
|
||||||
@ -315,7 +324,7 @@ export class ChatwootService {
|
|||||||
const filterInbox = await this.getInbox(instance);
|
const filterInbox = await this.getInbox(instance);
|
||||||
|
|
||||||
const findConversation = await client.conversations.list({
|
const findConversation = await client.conversations.list({
|
||||||
accountId: this.provider.accountId,
|
accountId: this.provider.account_id,
|
||||||
inboxId: filterInbox.id,
|
inboxId: filterInbox.id,
|
||||||
});
|
});
|
||||||
const conversation = findConversation.data.payload.find(
|
const conversation = findConversation.data.payload.find(
|
||||||
@ -338,7 +347,7 @@ export class ChatwootService {
|
|||||||
const config = {
|
const config = {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
maxBodyLength: Infinity,
|
maxBodyLength: Infinity,
|
||||||
url: `${this.provider.url}/api/v1/accounts/${this.provider.accountId}/conversations/${conversation.id}/messages`,
|
url: `${this.provider.url}/api/v1/accounts/${this.provider.account_id}/conversations/${conversation.id}/messages`,
|
||||||
headers: {
|
headers: {
|
||||||
api_access_token: this.provider.token,
|
api_access_token: this.provider.token,
|
||||||
...data.getHeaders(),
|
...data.getHeaders(),
|
||||||
@ -355,7 +364,360 @@ export class ChatwootService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async chatwootWebhook(instance: InstanceDto, body: any) {
|
public async sendAttachment(
|
||||||
return true;
|
waInstance: any,
|
||||||
|
number: string,
|
||||||
|
media: any,
|
||||||
|
caption?: string,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const parts = media.split('/');
|
||||||
|
const fileName = decodeURIComponent(parts[parts.length - 1]);
|
||||||
|
|
||||||
|
const mimeType = mimeTypes.lookup(fileName).toString();
|
||||||
|
|
||||||
|
let type = 'document';
|
||||||
|
|
||||||
|
switch (mimeType.split('/')[0]) {
|
||||||
|
case 'image':
|
||||||
|
type = 'image';
|
||||||
|
break;
|
||||||
|
case 'video':
|
||||||
|
type = 'video';
|
||||||
|
break;
|
||||||
|
case 'audio':
|
||||||
|
type = 'audio';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type = 'document';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'audio') {
|
||||||
|
const data: SendAudioDto = {
|
||||||
|
number: number,
|
||||||
|
audioMessage: {
|
||||||
|
audio: media,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
delay: 1200,
|
||||||
|
presence: 'recording',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await waInstance?.audioWhatsapp(data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: SendMediaDto = {
|
||||||
|
number: number,
|
||||||
|
mediaMessage: {
|
||||||
|
mediatype: type as any,
|
||||||
|
fileName: fileName,
|
||||||
|
media: media,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
delay: 1200,
|
||||||
|
presence: 'composing',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (caption && type !== 'audio') {
|
||||||
|
data.mediaMessage.caption = caption;
|
||||||
|
}
|
||||||
|
|
||||||
|
await waInstance?.mediaMessage(data);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async receiveWebhook(instance: InstanceDto, body: any) {
|
||||||
|
try {
|
||||||
|
if (!body?.conversation || body.private) return { message: 'bot' };
|
||||||
|
|
||||||
|
const chatId = body.conversation.meta.sender.phone_number.replace('+', '');
|
||||||
|
const messageReceived = body.content;
|
||||||
|
const senderName = body?.sender?.name;
|
||||||
|
const accountId = body.account.id as number;
|
||||||
|
const waInstance = this.waMonitor.waInstances[instance.instanceName];
|
||||||
|
|
||||||
|
if (chatId === '123456' && body.message_type === 'outgoing') {
|
||||||
|
const command = messageReceived.replace('/', '');
|
||||||
|
|
||||||
|
if (command === 'iniciar') {
|
||||||
|
const state = waInstance?.connectionStatus?.state;
|
||||||
|
|
||||||
|
if (state !== 'open') {
|
||||||
|
await waInstance.connectToWhatsapp();
|
||||||
|
} else {
|
||||||
|
await this.createBotMessage(
|
||||||
|
instance,
|
||||||
|
`🚨 Instância ${body.inbox.name} já está conectada.`,
|
||||||
|
'incoming',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command === 'status') {
|
||||||
|
const state = waInstance?.connectionStatus?.state;
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
await this.createBotMessage(
|
||||||
|
instance,
|
||||||
|
`⚠️ Instância ${body.inbox.name} não existe.`,
|
||||||
|
'incoming',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
await this.createBotMessage(
|
||||||
|
instance,
|
||||||
|
`⚠️ Status da instância ${body.inbox.name}: *${state}*`,
|
||||||
|
'incoming',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command === 'desconectar') {
|
||||||
|
const msgLogout = `🚨 Desconectando Whatsapp da caixa de entrada *${body.inbox.name}*: `;
|
||||||
|
|
||||||
|
await this.createBotMessage(instance, msgLogout, 'incoming');
|
||||||
|
await waInstance?.client?.logout('Log out instance: ' + instance.instanceName);
|
||||||
|
await waInstance?.client?.ws?.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
body.message_type === 'outgoing' &&
|
||||||
|
body?.conversation?.messages?.length &&
|
||||||
|
chatId !== '123456'
|
||||||
|
) {
|
||||||
|
// if (IMPORT_MESSAGES_SENT && messages_sent.includes(body.id)) {
|
||||||
|
// console.log(`🚨 Não importar mensagens enviadas, ficaria duplicado.`);
|
||||||
|
|
||||||
|
// const indexMessage = messages_sent.indexOf(body.id);
|
||||||
|
// messages_sent.splice(indexMessage, 1);
|
||||||
|
|
||||||
|
// return { message: 'bot' };
|
||||||
|
// }
|
||||||
|
|
||||||
|
let formatText: string;
|
||||||
|
if (senderName === null || senderName === undefined) {
|
||||||
|
formatText = messageReceived;
|
||||||
|
} else {
|
||||||
|
// formatText = TOSIGN ? `*${senderName}*: ${messageReceived}` : messageReceived;
|
||||||
|
formatText = `*${senderName}*: ${messageReceived}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const message of body.conversation.messages) {
|
||||||
|
if (message.attachments && message.attachments.length > 0) {
|
||||||
|
for (const attachment of message.attachments) {
|
||||||
|
console.log(attachment);
|
||||||
|
if (!messageReceived) {
|
||||||
|
formatText = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.sendAttachment(
|
||||||
|
waInstance,
|
||||||
|
chatId,
|
||||||
|
attachment.data_url,
|
||||||
|
formatText,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const data: SendTextDto = {
|
||||||
|
number: chatId,
|
||||||
|
textMessage: {
|
||||||
|
text: formatText,
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
delay: 1200,
|
||||||
|
presence: 'composing',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await waInstance?.textMessage(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { message: 'bot' };
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
return { message: 'bot' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isMediaMessage(message: any) {
|
||||||
|
const media = [
|
||||||
|
'imageMessage',
|
||||||
|
'documentMessage',
|
||||||
|
'audioMessage',
|
||||||
|
'videoMessage',
|
||||||
|
'stickerMessage',
|
||||||
|
];
|
||||||
|
|
||||||
|
const messageKeys = Object.keys(message);
|
||||||
|
return messageKeys.some((key) => media.includes(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTypeMessage(msg: any) {
|
||||||
|
const types = {
|
||||||
|
conversation: msg.conversation,
|
||||||
|
imageMessage: msg.imageMessage?.caption,
|
||||||
|
videoMessage: msg.videoMessage?.caption,
|
||||||
|
extendedTextMessage: msg.extendedTextMessage?.text,
|
||||||
|
messageContextInfo: msg.messageContextInfo?.stanzaId,
|
||||||
|
stickerMessage: msg.stickerMessage?.fileSha256.toString('base64'),
|
||||||
|
documentMessage: msg.documentMessage?.caption,
|
||||||
|
audioMessage: msg.audioMessage?.caption,
|
||||||
|
};
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMessageContent(types: any) {
|
||||||
|
const typeKey = Object.keys(types).find((key) => types[key] !== undefined);
|
||||||
|
return typeKey ? types[typeKey] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getConversationMessage(msg: any) {
|
||||||
|
const types = this.getTypeMessage(msg);
|
||||||
|
|
||||||
|
const messageContent = this.getMessageContent(types);
|
||||||
|
|
||||||
|
return messageContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async eventWhatsapp(event: string, instance: InstanceDto, body: any) {
|
||||||
|
try {
|
||||||
|
const client = await this.clientCw(instance);
|
||||||
|
|
||||||
|
if (!client) {
|
||||||
|
throw new Error('client not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const waInstance = this.waMonitor.waInstances[instance.instanceName];
|
||||||
|
|
||||||
|
if (event === 'messages.upsert') {
|
||||||
|
// if (body.key.fromMe && !IMPORT_MESSAGES_SENT) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (body.key.remoteJid === 'status@broadcast') {
|
||||||
|
console.log(`🚨 Ignorando status do whatsapp.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getConversion = await this.createConversation(instance, body);
|
||||||
|
const messageType = body.key.fromMe ? 'outgoing' : 'incoming';
|
||||||
|
|
||||||
|
if (!getConversion) {
|
||||||
|
console.log('🚨 Erro ao criar conversa');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMedia = this.isMediaMessage(body.message);
|
||||||
|
|
||||||
|
const bodyMessage = await this.getConversationMessage(body.message);
|
||||||
|
|
||||||
|
if (isMedia) {
|
||||||
|
const downloadBase64 = await waInstance?.getBase64FromMediaMessage({
|
||||||
|
message: {
|
||||||
|
...body,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const random = Math.random().toString(36).substring(7);
|
||||||
|
const nameFile = `${random}.${mimeTypes.extension(downloadBase64.mimetype)}`;
|
||||||
|
|
||||||
|
const fileData = Buffer.from(downloadBase64.base64, 'base64');
|
||||||
|
|
||||||
|
const fileName = `${path.join(waInstance?.storePath, 'temp', `${nameFile}`)}`;
|
||||||
|
|
||||||
|
writeFileSync(fileName, fileData, 'utf8');
|
||||||
|
|
||||||
|
return await this.sendData(getConversion, fileName, messageType, bodyMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const send = await this.createMessage(
|
||||||
|
instance,
|
||||||
|
getConversion,
|
||||||
|
bodyMessage,
|
||||||
|
messageType,
|
||||||
|
);
|
||||||
|
|
||||||
|
return send;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event === 'status.instance') {
|
||||||
|
const data = body;
|
||||||
|
const inbox = await this.getInbox(instance);
|
||||||
|
const msgStatus = `⚡️ Status da instância ${inbox.name}: ${data.status}`;
|
||||||
|
await this.createBotMessage(instance, msgStatus, 'incoming');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event === 'connection.update') {
|
||||||
|
if (body.state === 'open') {
|
||||||
|
const msgConnection = `🚀 Conexão realizada com sucesso!`;
|
||||||
|
await this.createBotMessage(instance, msgConnection, 'incoming');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event === 'contacts.update') {
|
||||||
|
const data = body;
|
||||||
|
|
||||||
|
if (data.length) {
|
||||||
|
for (const item of data) {
|
||||||
|
const number = item.id.split('@')[0];
|
||||||
|
const photo = item.profilePictureUrl || null;
|
||||||
|
const find = await this.findContact(instance, number);
|
||||||
|
|
||||||
|
if (find) {
|
||||||
|
await this.updateContact(instance, find.id, {
|
||||||
|
avatar_url: photo,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event === 'qrcode.updated') {
|
||||||
|
if (body.statusCode === 500) {
|
||||||
|
const erroQRcode = `🚨 Limite de geração de QRCode atingido, para gerar um novo QRCode, envie a mensagem /iniciar novamente.`;
|
||||||
|
return await this.createBotMessage(instance, erroQRcode, 'incoming');
|
||||||
|
} else {
|
||||||
|
const fileData = Buffer.from(
|
||||||
|
body?.qrcode.base64.replace('data:image/png;base64,', ''),
|
||||||
|
'base64',
|
||||||
|
);
|
||||||
|
|
||||||
|
const fileName = `${path.join(
|
||||||
|
waInstance?.storePath,
|
||||||
|
'temp',
|
||||||
|
`${`${instance}.png`}`,
|
||||||
|
)}`;
|
||||||
|
|
||||||
|
writeFileSync(fileName, fileData, 'utf8');
|
||||||
|
|
||||||
|
await this.createBotQr(
|
||||||
|
instance,
|
||||||
|
'QRCode gerado com sucesso!',
|
||||||
|
'incoming',
|
||||||
|
fileName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const msgQrCode = `⚡️ QRCode gerado com sucesso!\n\nDigitalize este código QR nos próximos 40 segundos:`;
|
||||||
|
await this.createBotMessage(instance, msgQrCode, 'incoming');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,6 +122,8 @@ import sharp from 'sharp';
|
|||||||
import { RedisCache } from '../../db/redis.client';
|
import { RedisCache } from '../../db/redis.client';
|
||||||
import { Log } from '../../config/env.config';
|
import { Log } from '../../config/env.config';
|
||||||
import ProxyAgent from 'proxy-agent';
|
import ProxyAgent from 'proxy-agent';
|
||||||
|
import { ChatwootService } from './chatwoot.service';
|
||||||
|
import { waMonitor } from '../whatsapp.module';
|
||||||
|
|
||||||
export class WAStartupService {
|
export class WAStartupService {
|
||||||
constructor(
|
constructor(
|
||||||
@ -141,12 +143,14 @@ export class WAStartupService {
|
|||||||
private readonly localWebhook: wa.LocalWebHook = {};
|
private readonly localWebhook: wa.LocalWebHook = {};
|
||||||
private readonly localChatwoot: wa.LocalChatwoot = {};
|
private readonly localChatwoot: wa.LocalChatwoot = {};
|
||||||
private stateConnection: wa.StateConnection = { state: 'close' };
|
private stateConnection: wa.StateConnection = { state: 'close' };
|
||||||
private readonly storePath = join(ROOT_DIR, 'store');
|
public readonly storePath = join(ROOT_DIR, 'store');
|
||||||
private readonly msgRetryCounterCache: CacheStore = new NodeCache();
|
private readonly msgRetryCounterCache: CacheStore = new NodeCache();
|
||||||
private readonly userDevicesCache: CacheStore = new NodeCache();
|
private readonly userDevicesCache: CacheStore = new NodeCache();
|
||||||
private endSession = false;
|
private endSession = false;
|
||||||
private logBaileys = this.configService.get<Log>('LOG').BAILEYS;
|
private logBaileys = this.configService.get<Log>('LOG').BAILEYS;
|
||||||
|
|
||||||
|
private chatwootService = new ChatwootService(waMonitor);
|
||||||
|
|
||||||
public set instanceName(name: string) {
|
public set instanceName(name: string) {
|
||||||
this.logger.verbose(`Initializing instance '${name}'`);
|
this.logger.verbose(`Initializing instance '${name}'`);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
@ -161,6 +165,17 @@ export class WAStartupService {
|
|||||||
instance: this.instance.name,
|
instance: this.instance.name,
|
||||||
status: 'created',
|
status: 'created',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
this.chatwootService.eventWhatsapp(
|
||||||
|
Events.STATUS_INSTANCE,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
{
|
||||||
|
instance: this.instance.name,
|
||||||
|
status: 'created',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public get instanceName() {
|
public get instanceName() {
|
||||||
@ -270,6 +285,24 @@ export class WAStartupService {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async loadChatwoot() {
|
||||||
|
this.logger.verbose('Loading chatwoot');
|
||||||
|
const data = await this.repository.chatwoot.find(this.instanceName);
|
||||||
|
this.localChatwoot.enabled = data?.enabled;
|
||||||
|
this.logger.verbose(`Chatwoot enabled: ${this.localChatwoot.enabled}`);
|
||||||
|
|
||||||
|
this.localChatwoot.account_id = data?.account_id;
|
||||||
|
this.logger.verbose(`Chatwoot account id: ${this.localChatwoot.account_id}`);
|
||||||
|
|
||||||
|
this.localChatwoot.token = data?.token;
|
||||||
|
this.logger.verbose(`Chatwoot token: ${this.localChatwoot.token}`);
|
||||||
|
|
||||||
|
this.localChatwoot.url = data?.url;
|
||||||
|
this.logger.verbose(`Chatwoot url: ${this.localChatwoot.url}`);
|
||||||
|
|
||||||
|
this.logger.verbose('Chatwoot loaded');
|
||||||
|
}
|
||||||
|
|
||||||
public async setChatwoot(data: ChatwootRaw) {
|
public async setChatwoot(data: ChatwootRaw) {
|
||||||
this.logger.verbose('Setting chatwoot');
|
this.logger.verbose('Setting chatwoot');
|
||||||
await this.repository.chatwoot.create(data, this.instanceName);
|
await this.repository.chatwoot.create(data, this.instanceName);
|
||||||
@ -429,6 +462,17 @@ export class WAStartupService {
|
|||||||
statusCode: DisconnectReason.badSession,
|
statusCode: DisconnectReason.badSession,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
this.chatwootService.eventWhatsapp(
|
||||||
|
Events.QRCODE_UPDATED,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
{
|
||||||
|
message: 'QR code limit reached, please login again',
|
||||||
|
statusCode: DisconnectReason.badSession,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.verbose('Sending data to webhook in event CONNECTION_UPDATE');
|
this.logger.verbose('Sending data to webhook in event CONNECTION_UPDATE');
|
||||||
this.sendDataWebhook(Events.CONNECTION_UPDATE, {
|
this.sendDataWebhook(Events.CONNECTION_UPDATE, {
|
||||||
instance: this.instance.name,
|
instance: this.instance.name,
|
||||||
@ -442,6 +486,17 @@ export class WAStartupService {
|
|||||||
status: 'removed',
|
status: 'removed',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
this.chatwootService.eventWhatsapp(
|
||||||
|
Events.STATUS_INSTANCE,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
{
|
||||||
|
instance: this.instance.name,
|
||||||
|
status: 'removed',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.verbose('endSession defined as true');
|
this.logger.verbose('endSession defined as true');
|
||||||
this.endSession = true;
|
this.endSession = true;
|
||||||
|
|
||||||
@ -472,6 +527,16 @@ export class WAStartupService {
|
|||||||
this.sendDataWebhook(Events.QRCODE_UPDATED, {
|
this.sendDataWebhook(Events.QRCODE_UPDATED, {
|
||||||
qrcode: { instance: this.instance.name, code: qr, base64 },
|
qrcode: { instance: this.instance.name, code: qr, base64 },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
this.chatwootService.eventWhatsapp(
|
||||||
|
Events.QRCODE_UPDATED,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
{
|
||||||
|
qrcode: { instance: this.instance.name, code: qr, base64 },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.verbose('Generating QR code in terminal');
|
this.logger.verbose('Generating QR code in terminal');
|
||||||
@ -512,6 +577,17 @@ export class WAStartupService {
|
|||||||
status: 'removed',
|
status: 'removed',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
this.chatwootService.eventWhatsapp(
|
||||||
|
Events.STATUS_INSTANCE,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
{
|
||||||
|
instance: this.instance.name,
|
||||||
|
status: 'removed',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.verbose('Emittin event logout.instance');
|
this.logger.verbose('Emittin event logout.instance');
|
||||||
this.eventEmitter.emit('logout.instance', this.instance.name, 'inner');
|
this.eventEmitter.emit('logout.instance', this.instance.name, 'inner');
|
||||||
this.client?.ws?.close();
|
this.client?.ws?.close();
|
||||||
@ -626,6 +702,7 @@ export class WAStartupService {
|
|||||||
this.logger.verbose('Connecting to whatsapp');
|
this.logger.verbose('Connecting to whatsapp');
|
||||||
try {
|
try {
|
||||||
this.loadWebhook();
|
this.loadWebhook();
|
||||||
|
this.loadChatwoot();
|
||||||
|
|
||||||
this.instance.authState = await this.defineAuthState();
|
this.instance.authState = await this.defineAuthState();
|
||||||
|
|
||||||
@ -817,6 +894,14 @@ export class WAStartupService {
|
|||||||
this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE');
|
this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE');
|
||||||
await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw);
|
await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactsRaw);
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
await this.chatwootService.eventWhatsapp(
|
||||||
|
Events.CONTACTS_UPDATE,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
contactsRaw,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.verbose('Updating contacts in database');
|
this.logger.verbose('Updating contacts in database');
|
||||||
await this.repository.contact.update(
|
await this.repository.contact.update(
|
||||||
contactsRaw,
|
contactsRaw,
|
||||||
@ -940,6 +1025,14 @@ export class WAStartupService {
|
|||||||
this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT');
|
this.logger.verbose('Sending data to webhook in event MESSAGES_UPSERT');
|
||||||
await this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw);
|
await this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw);
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
await this.chatwootService.eventWhatsapp(
|
||||||
|
Events.MESSAGES_UPSERT,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
messageRaw,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.verbose('Inserting message in database');
|
this.logger.verbose('Inserting message in database');
|
||||||
await this.repository.message.insert(
|
await this.repository.message.insert(
|
||||||
[messageRaw],
|
[messageRaw],
|
||||||
@ -978,6 +1071,14 @@ export class WAStartupService {
|
|||||||
this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE');
|
this.logger.verbose('Sending data to webhook in event CONTACTS_UPDATE');
|
||||||
await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw);
|
await this.sendDataWebhook(Events.CONTACTS_UPDATE, contactRaw);
|
||||||
|
|
||||||
|
if (this.localChatwoot.enabled) {
|
||||||
|
await this.chatwootService.eventWhatsapp(
|
||||||
|
Events.CONTACTS_UPDATE,
|
||||||
|
{ instanceName: this.instance.name },
|
||||||
|
contactRaw,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.logger.verbose('Updating contact in database');
|
this.logger.verbose('Updating contact in database');
|
||||||
await this.repository.contact.update(
|
await this.repository.contact.update(
|
||||||
[contactRaw],
|
[contactRaw],
|
||||||
|
Loading…
Reference in New Issue
Block a user