Skip to content

Commit 9b73252

Browse files
Merge branch 'develop' into fix/saveOnWhatsappCache-remoteJid-failed-constraint
2 parents 8d1151d + 71322cd commit 9b73252

File tree

16 files changed

+655
-604
lines changed

16 files changed

+655
-604
lines changed

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ body:
5959
value: |
6060
- OS: [e.g. Ubuntu 20.04, Windows 10, macOS 12.0]
6161
- Node.js version: [e.g. 18.17.0]
62-
- Evolution API version: [e.g. 2.3.6]
62+
- Evolution API version: [e.g. 2.3.7]
6363
- Database: [e.g. PostgreSQL 14, MySQL 8.0]
6464
- Connection type: [e.g. Baileys, WhatsApp Business API]
6565
validations:

Docker/swarm/evolution_api_v2.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ version: "3.7"
22

33
services:
44
evolution_v2:
5-
image: evoapicloud/evolution-api:v2.3.6
5+
image: evoapicloud/evolution-api:v2.3.7
66
volumes:
77
- evolution_instances:/evolution/instances
88
networks:

package-lock.json

Lines changed: 457 additions & 456 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "evolution-api",
3-
"version": "2.3.6",
3+
"version": "2.3.7",
44
"description": "Rest api for communication with WhatsApp",
55
"main": "./dist/main.js",
66
"type": "commonjs",
@@ -96,6 +96,7 @@
9696
"jsonschema": "^1.4.1",
9797
"jsonwebtoken": "^9.0.2",
9898
"kafkajs": "^2.2.4",
99+
"libphonenumber-js": "^1.12.25",
99100
"link-preview-js": "^3.0.13",
100101
"long": "^5.2.3",
101102
"mediainfo.js": "^0.3.4",

src/api/controllers/instance.controller.ts

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,15 @@ export class InstanceController {
9292
instanceId: instanceId,
9393
});
9494

95+
const instanceDto: InstanceDto = {
96+
instanceName: instance.instanceName,
97+
instanceId: instance.instanceId,
98+
connectionStatus:
99+
typeof instance.connectionStatus === 'string'
100+
? instance.connectionStatus
101+
: instance.connectionStatus?.state || 'unknown',
102+
};
103+
95104
if (instanceData.proxyHost && instanceData.proxyPort && instanceData.proxyProtocol) {
96105
const testProxy = await this.proxyService.testProxy({
97106
host: instanceData.proxyHost,
@@ -103,8 +112,7 @@ export class InstanceController {
103112
if (!testProxy) {
104113
throw new BadRequestException('Invalid proxy');
105114
}
106-
107-
await this.proxyService.createProxy(instance, {
115+
await this.proxyService.createProxy(instanceDto, {
108116
enabled: true,
109117
host: instanceData.proxyHost,
110118
port: instanceData.proxyPort,
@@ -125,7 +133,7 @@ export class InstanceController {
125133
wavoipToken: instanceData.wavoipToken || '',
126134
};
127135

128-
await this.settingsService.create(instance, settings);
136+
await this.settingsService.create(instanceDto, settings);
129137

130138
let webhookWaBusiness = null,
131139
accessTokenWaBusiness = '';
@@ -155,7 +163,10 @@ export class InstanceController {
155163
integration: instanceData.integration,
156164
webhookWaBusiness,
157165
accessTokenWaBusiness,
158-
status: instance.connectionStatus.state,
166+
status:
167+
typeof instance.connectionStatus === 'string'
168+
? instance.connectionStatus
169+
: instance.connectionStatus?.state || 'unknown',
159170
},
160171
hash,
161172
webhook: {
@@ -217,7 +228,7 @@ export class InstanceController {
217228
const urlServer = this.configService.get<HttpServer>('SERVER').URL;
218229

219230
try {
220-
this.chatwootService.create(instance, {
231+
this.chatwootService.create(instanceDto, {
221232
enabled: true,
222233
accountId: instanceData.chatwootAccountId,
223234
token: instanceData.chatwootToken,
@@ -246,7 +257,10 @@ export class InstanceController {
246257
integration: instanceData.integration,
247258
webhookWaBusiness,
248259
accessTokenWaBusiness,
249-
status: instance.connectionStatus.state,
260+
status:
261+
typeof instance.connectionStatus === 'string'
262+
? instance.connectionStatus
263+
: instance.connectionStatus?.state || 'unknown',
250264
},
251265
hash,
252266
webhook: {
@@ -338,20 +352,38 @@ export class InstanceController {
338352
throw new BadRequestException('The "' + instanceName + '" instance does not exist');
339353
}
340354

341-
if (state == 'close') {
355+
if (state === 'close') {
342356
throw new BadRequestException('The "' + instanceName + '" instance is not connected');
343-
} else if (state == 'open') {
357+
}
358+
this.logger.info(`Restarting instance: ${instanceName}`);
359+
360+
if (typeof instance.restart === 'function') {
361+
await instance.restart();
362+
// Wait a bit for the reconnection to be established
363+
await new Promise((r) => setTimeout(r, 2000));
364+
return {
365+
instance: {
366+
instanceName: instanceName,
367+
status: instance.connectionStatus?.state || 'connecting',
368+
},
369+
};
370+
}
371+
372+
// Fallback for Baileys (uses different mechanism)
373+
if (state === 'open' || state === 'connecting') {
344374
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED) instance.clearCacheChatwoot();
345-
this.logger.info('restarting instance' + instanceName);
346375

347-
instance.client?.ws?.close();
348-
instance.client?.end(new Error('restart'));
349-
return await this.connectToWhatsapp({ instanceName });
350-
} else if (state == 'connecting') {
351376
instance.client?.ws?.close();
352377
instance.client?.end(new Error('restart'));
353378
return await this.connectToWhatsapp({ instanceName });
354379
}
380+
381+
return {
382+
instance: {
383+
instanceName: instanceName,
384+
status: state,
385+
},
386+
};
355387
} catch (error) {
356388
this.logger.error(error);
357389
return { error: true, message: error.toString() };
@@ -409,7 +441,7 @@ export class InstanceController {
409441
}
410442

411443
try {
412-
this.waMonitor.waInstances[instanceName]?.logoutInstance();
444+
await this.waMonitor.waInstances[instanceName]?.logoutInstance();
413445

414446
return { status: 'SUCCESS', error: false, response: { message: 'Instance logged out' } };
415447
} catch (error) {

src/api/dto/instance.dto.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export class InstanceDto extends IntegrationDto {
1212
token?: string;
1313
status?: string;
1414
ownerJid?: string;
15+
connectionStatus?: string;
1516
profileName?: string;
1617
profilePicUrl?: string;
1718
// settings

src/api/integrations/channel/meta/whatsapp.business.service.ts

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,9 @@ export class BusinessStartupService extends ChannelStartupService {
516516
const mediaUrl = await s3Service.getObjectUrl(fullName);
517517

518518
messageRaw.message.mediaUrl = mediaUrl;
519-
messageRaw.message.base64 = buffer.data.toString('base64');
519+
if (this.localWebhook.enabled && this.localWebhook.webhookBase64) {
520+
messageRaw.message.base64 = buffer.data.toString('base64');
521+
}
520522

521523
// Processar OpenAI speech-to-text para áudio após o mediaUrl estar disponível
522524
if (this.configService.get<Openai>('OPENAI').ENABLED && mediaType === 'audio') {
@@ -554,11 +556,19 @@ export class BusinessStartupService extends ChannelStartupService {
554556
this.logger.error(['Error on upload file to minio', error?.message, error?.stack]);
555557
}
556558
} else {
557-
const buffer = await this.downloadMediaMessage(received?.messages[0]);
558-
messageRaw.message.base64 = buffer.toString('base64');
559+
if (this.localWebhook.enabled && this.localWebhook.webhookBase64) {
560+
const buffer = await this.downloadMediaMessage(received?.messages[0]);
561+
messageRaw.message.base64 = buffer.toString('base64');
562+
}
559563

560564
// Processar OpenAI speech-to-text para áudio mesmo sem S3
561565
if (this.configService.get<Openai>('OPENAI').ENABLED && message.type === 'audio') {
566+
let openAiBase64 = messageRaw.message.base64;
567+
if (!openAiBase64) {
568+
const buffer = await this.downloadMediaMessage(received?.messages[0]);
569+
openAiBase64 = buffer.toString('base64');
570+
}
571+
562572
const openAiDefaultSettings = await this.prismaRepository.openaiSetting.findFirst({
563573
where: {
564574
instanceId: this.instanceId,
@@ -574,7 +584,7 @@ export class BusinessStartupService extends ChannelStartupService {
574584
openAiDefaultSettings.OpenaiCreds,
575585
{
576586
message: {
577-
base64: messageRaw.message.base64,
587+
base64: openAiBase64,
578588
...messageRaw,
579589
},
580590
},
@@ -1016,6 +1026,7 @@ export class BusinessStartupService extends ChannelStartupService {
10161026
[message['mediaType']]: {
10171027
[message['type']]: message['id'],
10181028
...(message['mediaType'] !== 'audio' &&
1029+
message['mediaType'] !== 'video' &&
10191030
message['fileName'] &&
10201031
!isImage && { filename: message['fileName'] }),
10211032
...(message['mediaType'] !== 'audio' && message['caption'] && { caption: message['caption'] }),
@@ -1606,9 +1617,14 @@ export class BusinessStartupService extends ChannelStartupService {
16061617
const messageType = msg.messageType.includes('Message') ? msg.messageType : msg.messageType + 'Message';
16071618
const mediaMessage = msg.message[messageType];
16081619

1620+
if (!msg.message?.base64) {
1621+
const buffer = await this.downloadMediaMessage({ type: messageType, ...msg.message });
1622+
msg.message.base64 = buffer.toString('base64');
1623+
}
1624+
16091625
return {
16101626
mediaType: msg.messageType,
1611-
fileName: mediaMessage?.fileName,
1627+
fileName: mediaMessage?.fileName || mediaMessage?.filename,
16121628
caption: mediaMessage?.caption,
16131629
size: {
16141630
fileLength: mediaMessage?.fileLength,

src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ import { createId as cuid } from '@paralleldrive/cuid2';
8282
import { Instance, Message } from '@prisma/client';
8383
import { createJid } from '@utils/createJid';
8484
import { fetchLatestWaWebVersion } from '@utils/fetchLatestWaWebVersion';
85-
import {makeProxyAgent, makeProxyAgentUndici} from '@utils/makeProxyAgent';
85+
import { makeProxyAgent, makeProxyAgentUndici } from '@utils/makeProxyAgent';
8686
import { getOnWhatsappCache, saveOnWhatsappCache } from '@utils/onWhatsappCache';
8787
import { status } from '@utils/renderStatus';
8888
import { sendTelemetry } from '@utils/sendTelemetry';
@@ -569,15 +569,6 @@ export class BaileysStartupService extends ChannelStartupService {
569569
const version = baileysVersion.version;
570570
const log = `Baileys version: ${version.join('.')}`;
571571

572-
// if (session.VERSION) {
573-
// version = session.VERSION.split('.');
574-
// log = `Baileys version env: ${version}`;
575-
// } else {
576-
// const baileysVersion = await fetchLatestWaWebVersion({});
577-
// version = baileysVersion.version;
578-
// log = `Baileys version: ${version}`;
579-
// }
580-
581572
this.logger.info(log);
582573

583574
this.logger.info(`Group Ignore: ${this.localSettings.groupsIgnore}`);
@@ -1130,16 +1121,6 @@ export class BaileysStartupService extends ChannelStartupService {
11301121
}
11311122
}
11321123

1133-
const messageKey = `${this.instance.id}_${received.key.id}`;
1134-
const cached = await this.baileysCache.get(messageKey);
1135-
1136-
if (cached && !editedMessage && !requestId) {
1137-
this.logger.info(`Message duplicated ignored: ${received.key.id}`);
1138-
continue;
1139-
}
1140-
1141-
await this.baileysCache.set(messageKey, true, this.MESSAGE_CACHE_TTL_SECONDS);
1142-
11431124
if (
11441125
(type !== 'notify' && type !== 'append') ||
11451126
editedMessage ||
@@ -1349,6 +1330,10 @@ export class BaileysStartupService extends ChannelStartupService {
13491330
this.logger.verbose(messageRaw);
13501331

13511332
sendTelemetry(`received.message.${messageRaw.messageType ?? 'unknown'}`);
1333+
if (messageRaw.key.remoteJid?.includes('@lid') && messageRaw.key.remoteJidAlt) {
1334+
messageRaw.key.remoteJid = messageRaw.key.remoteJidAlt;
1335+
}
1336+
console.log(messageRaw);
13521337

13531338
this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw);
13541339

@@ -1442,7 +1427,7 @@ export class BaileysStartupService extends ChannelStartupService {
14421427
const cached = await this.baileysCache.get(updateKey);
14431428

14441429
if (cached) {
1445-
this.logger.info(`Message duplicated ignored [avoid deadlock]: ${updateKey}`);
1430+
this.logger.info(`Update Message duplicated ignored [avoid deadlock]: ${updateKey}`);
14461431
continue;
14471432
}
14481433

src/api/integrations/chatbot/chatwoot/controllers/chatwoot.controller.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { InstanceDto } from '@api/dto/instance.dto';
22
import { ChatwootDto } from '@api/integrations/chatbot/chatwoot/dto/chatwoot.dto';
33
import { ChatwootService } from '@api/integrations/chatbot/chatwoot/services/chatwoot.service';
4-
import { PrismaRepository } from '@api/repository/repository.service';
5-
import { waMonitor } from '@api/server.module';
6-
import { CacheService } from '@api/services/cache.service';
7-
import { CacheEngine } from '@cache/cacheengine';
84
import { Chatwoot, ConfigService, HttpServer } from '@config/env.config';
95
import { BadRequestException } from '@exceptions';
106
import { isURL } from 'class-validator';
@@ -13,7 +9,6 @@ export class ChatwootController {
139
constructor(
1410
private readonly chatwootService: ChatwootService,
1511
private readonly configService: ConfigService,
16-
private readonly prismaRepository: PrismaRepository,
1712
) {}
1813

1914
public async createChatwoot(instance: InstanceDto, data: ChatwootDto) {
@@ -84,9 +79,6 @@ export class ChatwootController {
8479
public async receiveWebhook(instance: InstanceDto, data: any) {
8580
if (!this.configService.get<Chatwoot>('CHATWOOT').ENABLED) throw new BadRequestException('Chatwoot is disabled');
8681

87-
const chatwootCache = new CacheService(new CacheEngine(this.configService, ChatwootService.name).getEngine());
88-
const chatwootService = new ChatwootService(waMonitor, this.configService, this.prismaRepository, chatwootCache);
89-
90-
return chatwootService.receiveWebhook(instance, data);
82+
return this.chatwootService.receiveWebhook(instance, data);
9183
}
9284
}

0 commit comments

Comments
 (0)