Skip to content

Commit ad8df44

Browse files
Merge pull request #2023 from Vitordotpy/fix/chatwoot-conversation-handling
fix(chatwoot): Corrige Reabertura de Conversas e Loop de Mensagem de Conexão
2 parents b62917e + c132379 commit ad8df44

File tree

1 file changed

+98
-49
lines changed

1 file changed

+98
-49
lines changed

src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts

Lines changed: 98 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import mimeTypes from 'mime-types';
3333
import path from 'path';
3434
import { Readable } from 'stream';
3535

36+
const MIN_CONNECTION_NOTIFICATION_INTERVAL_MS = 30000; // 30 seconds
37+
3638
interface ChatwootMessage {
3739
messageId?: number;
3840
inboxId?: number;
@@ -604,12 +606,7 @@ export class ChatwootService {
604606
this.logger.verbose(`--- Start createConversation ---`);
605607
this.logger.verbose(`Instance: ${JSON.stringify(instance)}`);
606608

607-
// If it already exists in the cache, return conversationId
608-
if (await this.cache.has(cacheKey)) {
609-
const conversationId = (await this.cache.get(cacheKey)) as number;
610-
this.logger.verbose(`Found conversation to: ${remoteJid}, conversation ID: ${conversationId}`);
611-
return conversationId;
612-
}
609+
// Always check Chatwoot first, cache only as fallback
613610

614611
// If lock already exists, wait until release or timeout
615612
if (await this.cache.has(lockKey)) {
@@ -621,11 +618,7 @@ export class ChatwootService {
621618
break;
622619
}
623620
await new Promise((res) => setTimeout(res, 300));
624-
if (await this.cache.has(cacheKey)) {
625-
const conversationId = (await this.cache.get(cacheKey)) as number;
626-
this.logger.verbose(`Resolves creation of: ${remoteJid}, conversation ID: ${conversationId}`);
627-
return conversationId;
628-
}
621+
// Removed cache check here to ensure we always check Chatwoot
629622
}
630623
}
631624

@@ -635,12 +628,9 @@ export class ChatwootService {
635628

636629
try {
637630
/*
638-
Double check after lock
639-
Utilizei uma nova verificação para evitar que outra thread execute entre o terminio do while e o set lock
631+
Double check after lock - REMOVED
632+
This was causing the system to use cached conversations instead of checking Chatwoot
640633
*/
641-
if (await this.cache.has(cacheKey)) {
642-
return (await this.cache.get(cacheKey)) as number;
643-
}
644634

645635
const client = await this.clientCw(instance);
646636
if (!client) return null;
@@ -747,34 +737,39 @@ export class ChatwootService {
747737
return null;
748738
}
749739

750-
let inboxConversation = contactConversations.payload.find(
751-
(conversation) => conversation.inbox_id == filterInbox.id,
752-
);
753-
if (inboxConversation) {
754-
if (this.provider.reopenConversation) {
755-
this.logger.verbose(`Found conversation in reopenConversation mode: ${JSON.stringify(inboxConversation)}`);
756-
if (inboxConversation && this.provider.conversationPending && inboxConversation.status !== 'open') {
757-
await client.conversations.toggleStatus({
758-
accountId: this.provider.accountId,
759-
conversationId: inboxConversation.id,
760-
data: {
761-
status: 'pending',
762-
},
763-
});
764-
}
740+
let inboxConversation = null;
741+
742+
if (this.provider.reopenConversation) {
743+
inboxConversation = this.findOpenConversation(contactConversations.payload, filterInbox.id);
744+
745+
if (inboxConversation) {
746+
this.logger.verbose(
747+
`Found open conversation in reopenConversation mode: ${JSON.stringify(inboxConversation)}`,
748+
);
765749
} else {
766-
inboxConversation = contactConversations.payload.find(
767-
(conversation) =>
768-
conversation && conversation.status !== 'resolved' && conversation.inbox_id == filterInbox.id,
750+
inboxConversation = await this.findAndReopenResolvedConversation(
751+
client,
752+
contactConversations.payload,
753+
filterInbox.id,
769754
);
770-
this.logger.verbose(`Found conversation: ${JSON.stringify(inboxConversation)}`);
771755
}
756+
} else {
757+
inboxConversation = this.findOpenConversation(contactConversations.payload, filterInbox.id);
758+
this.logger.verbose(`Found conversation: ${JSON.stringify(inboxConversation)}`);
759+
}
772760

773-
if (inboxConversation) {
774-
this.logger.verbose(`Returning existing conversation ID: ${inboxConversation.id}`);
775-
this.cache.set(cacheKey, inboxConversation.id);
776-
return inboxConversation.id;
777-
}
761+
if (inboxConversation) {
762+
this.logger.verbose(`Returning existing conversation ID: ${inboxConversation.id}`);
763+
this.cache.set(cacheKey, inboxConversation.id);
764+
return inboxConversation.id;
765+
}
766+
767+
if (await this.cache.has(cacheKey)) {
768+
const conversationId = (await this.cache.get(cacheKey)) as number;
769+
this.logger.warn(
770+
`No active conversations found in Chatwoot, using cached conversation ID: ${conversationId} as fallback`,
771+
);
772+
return conversationId;
778773
}
779774

780775
const data = {
@@ -817,6 +812,45 @@ export class ChatwootService {
817812
}
818813
}
819814

815+
private findOpenConversation(conversations: any[], inboxId: number): any | null {
816+
const openConversation = conversations.find(
817+
(conversation) => conversation && conversation.status !== 'resolved' && conversation.inbox_id == inboxId,
818+
);
819+
820+
if (openConversation) {
821+
this.logger.verbose(`Found open conversation: ${JSON.stringify(openConversation)}`);
822+
}
823+
824+
return openConversation || null;
825+
}
826+
827+
private async findAndReopenResolvedConversation(
828+
client: any,
829+
conversations: any[],
830+
inboxId: number,
831+
): Promise<any | null> {
832+
const resolvedConversation = conversations.find(
833+
(conversation) => conversation && conversation.status === 'resolved' && conversation.inbox_id == inboxId,
834+
);
835+
836+
if (resolvedConversation) {
837+
this.logger.verbose(`Found resolved conversation to reopen: ${JSON.stringify(resolvedConversation)}`);
838+
if (this.provider.conversationPending && resolvedConversation.status !== 'open') {
839+
await client.conversations.toggleStatus({
840+
accountId: this.provider.accountId,
841+
conversationId: resolvedConversation.id,
842+
data: {
843+
status: 'pending',
844+
},
845+
});
846+
this.logger.verbose(`Reopened resolved conversation ID: ${resolvedConversation.id}`);
847+
}
848+
return resolvedConversation;
849+
}
850+
851+
return null;
852+
}
853+
820854
public async getInbox(instance: InstanceDto): Promise<inbox | null> {
821855
const cacheKey = `${instance.instanceName}:getInbox`;
822856
if (await this.cache.has(cacheKey)) {
@@ -2405,15 +2439,30 @@ export class ChatwootService {
24052439
await this.createBotMessage(instance, msgStatus, 'incoming');
24062440
}
24072441

2408-
if (event === 'connection.update') {
2409-
if (body.status === 'open') {
2410-
// if we have qrcode count then we understand that a new connection was established
2411-
if (this.waMonitor.waInstances[instance.instanceName].qrCode.count > 0) {
2412-
const msgConnection = i18next.t('cw.inbox.connected');
2413-
await this.createBotMessage(instance, msgConnection, 'incoming');
2414-
this.waMonitor.waInstances[instance.instanceName].qrCode.count = 0;
2415-
chatwootImport.clearAll(instance);
2416-
}
2442+
if (event === 'connection.update' && body.status === 'open') {
2443+
const waInstance = this.waMonitor.waInstances[instance.instanceName];
2444+
if (!waInstance) return;
2445+
2446+
const now = Date.now();
2447+
const timeSinceLastNotification = now - (waInstance.lastConnectionNotification || 0);
2448+
2449+
// Se a conexão foi estabelecida via QR code, notifica imediatamente.
2450+
if (waInstance.qrCode && waInstance.qrCode.count > 0) {
2451+
const msgConnection = i18next.t('cw.inbox.connected');
2452+
await this.createBotMessage(instance, msgConnection, 'incoming');
2453+
waInstance.qrCode.count = 0;
2454+
waInstance.lastConnectionNotification = now;
2455+
chatwootImport.clearAll(instance);
2456+
}
2457+
// Se não foi via QR code, verifica o throttling.
2458+
else if (timeSinceLastNotification >= MIN_CONNECTION_NOTIFICATION_INTERVAL_MS) {
2459+
const msgConnection = i18next.t('cw.inbox.connected');
2460+
await this.createBotMessage(instance, msgConnection, 'incoming');
2461+
waInstance.lastConnectionNotification = now;
2462+
} else {
2463+
this.logger.warn(
2464+
`Connection notification skipped for ${instance.instanceName} - too frequent (${timeSinceLastNotification}ms since last)`,
2465+
);
24172466
}
24182467
}
24192468

0 commit comments

Comments
 (0)