-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Merge solutions #1770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merge solutions #1770
Changes from all commits
2c78008
c5121ac
edb1dcf
20b5066
7960f0d
f58e792
abe25d2
fe1a93d
811e369
9969727
49b174d
fe93353
cd09ed1
205ea81
d32d6a5
c313f5b
3fa9d10
7df26ea
e430d9e
9c7bf23
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| -- AlterTable | ||
| ALTER TABLE `OpenaiSetting` MODIFY COLUMN `speechToText` BOOLEAN NULL DEFAULT true; | ||
|
|
||
| -- Update existing records to use the new default | ||
| UPDATE `OpenaiSetting` SET `speechToText` = true WHERE `speechToText` IS NULL OR `speechToText` = false; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| -- AlterTable | ||
| ALTER TABLE "OpenaiSetting" ALTER COLUMN "speechToText" SET DEFAULT true; | ||
|
|
||
| -- Update existing records to use the new default | ||
| UPDATE "OpenaiSetting" SET "speechToText" = true WHERE "speechToText" IS NULL OR "speechToText" = false; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { getCollectionsDto } from '@api/dto/business.dto'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { OfferCallDto } from '@api/dto/call.dto'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||
| ArchiveChatDto, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -139,6 +139,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| import mimeTypes from 'mime-types'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import NodeCache from 'node-cache'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import cron from 'node-cron'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import dayjs from 'dayjs'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { release } from 'os'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { join } from 'path'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| import P from 'pino'; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -153,6 +154,52 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const groupMetadataCache = new CacheService(new CacheEngine(configService, 'groups').getEngine()); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Function to normalize JID and handle LID/JID conversion | ||||||||||||||||||||||||||||||||||||||||||||||||
| function normalizeJid(jid: string): string { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!jid) return jid; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Remove LID suffix and convert to standard JID format | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (jid.includes(':lid')) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return jid.split(':')[0] + '@s.whatsapp.net'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Remove participant suffix from group messages | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (jid.includes(':') && jid.includes('@g.us')) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return jid.split(':')[0] + '@g.us'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Remove any other participant suffixes | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (jid.includes(':') && !jid.includes('@g.us')) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return jid.split(':')[0] + '@s.whatsapp.net'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return jid; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Function to clear corrupted session data | ||||||||||||||||||||||||||||||||||||||||||||||||
| async function clearCorruptedSessionData(instanceId: string, baileysCache: CacheService) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Clear all baileys cache for this instance | ||||||||||||||||||||||||||||||||||||||||||||||||
| await baileysCache.deleteAll(instanceId); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Clear session-related cache patterns | ||||||||||||||||||||||||||||||||||||||||||||||||
| const patterns = [ | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Check failure on line 186 in src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
|
||||||||||||||||||||||||||||||||||||||||||||||||
| `${instanceId}_*`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| `*${instanceId}*`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| `*session*${instanceId}*`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| `*prekey*${instanceId}*` | ||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| for (const pattern of patterns) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| await baileysCache.deleteAll(pattern); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`Cleared corrupted session data for instance: ${instanceId}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('Error clearing session data:', error); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Adicione a função getVideoDuration no início do arquivo | ||||||||||||||||||||||||||||||||||||||||||||||||
| async function getVideoDuration(input: Buffer | string | Readable): Promise<number> { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const MediaInfoFactory = (await import('mediainfo.js')).default; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -383,6 +430,11 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| state: connection, | ||||||||||||||||||||||||||||||||||||||||||||||||
| statusReason: (lastDisconnect?.error as Boom)?.output?.statusCode ?? 200, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.log(`Connection state changed to: ${connection}, instance: ${this.instance.id}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (lastDisconnect?.error) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.warn(`Connection error: ${JSON.stringify(lastDisconnect.error)}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+434
to
+437
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚨 suggestion (security): Logging sensitive error details may expose internal information. Sanitize or redact sensitive fields from lastDisconnect.error before logging, particularly in production.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (connection === 'close') { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -662,6 +714,9 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| this.endSession = false; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Clear any corrupted session data before connecting | ||||||||||||||||||||||||||||||||||||||||||||||||
| await clearCorruptedSessionData(this.instanceId, this.baileysCache); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (performance): Clearing session data on every connect may impact performance. If clearing session data isn't always required, consider making this operation conditional or rate-limited to avoid unnecessary latency, especially under high load. Suggested implementation: // Rate-limit clearing corrupted session data to avoid unnecessary latency
const SESSION_CLEAR_INTERVAL_MS = 10 * 60 * 1000; // 10 minutes
if (!this.lastSessionClear || Date.now() - this.lastSessionClear > SESSION_CLEAR_INTERVAL_MS) {
await clearCorruptedSessionData(this.instanceId, this.baileysCache);
this.lastSessionClear = Date.now();
}
this.client = makeWASocket(socketConfig);You must ensure that this.lastSessionClear = 0;If you want a different condition (e.g., a flag or a more advanced rate limiter), adjust the logic accordingly. |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| this.client = makeWASocket(socketConfig); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (this.localSettings.wavoipToken && this.localSettings.wavoipToken.length > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1124,7 +1179,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const messageKey = `${this.instance.id}_${received.key.id}`; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const normalizedJid = normalizeJid(received.key.remoteJid); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const messageKey = `${this.instance.id}_${normalizedJid}_${received.key.id}`; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const cached = await this.baileysCache.get(messageKey); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (cached && !editedMessage) { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1151,8 +1207,9 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const normalizedRemoteJid = normalizeJid(received.key.remoteJid); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const existingChat = await this.prismaRepository.chat.findFirst({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { instanceId: this.instanceId, remoteJid: received.key.remoteJid }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { instanceId: this.instanceId, remoteJid: normalizedRemoteJid }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| select: { id: true, name: true }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1231,7 +1288,8 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| const { remoteJid } = received.key; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const timestamp = msg.messageTimestamp; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const fromMe = received.key.fromMe.toString(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const messageKey = `${remoteJid}_${timestamp}_${fromMe}`; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const normalizedRemoteJid = normalizeJid(remoteJid); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const messageKey = `${normalizedRemoteJid}_${timestamp}_${fromMe}`; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const cachedTimestamp = await this.baileysCache.get(messageKey); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1336,6 +1394,41 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| this.sendDataWebhook(Events.MESSAGES_UPSERT, messageRaw); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Schedule automatic status update for PENDING sent messages | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (messageRaw.key.fromMe && messageRaw.status === 'PENDING') { | ||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const stillPendingMessage = await this.prismaRepository.message.findFirst({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { | ||||||||||||||||||||||||||||||||||||||||||||||||
| instanceId: this.instanceId, | ||||||||||||||||||||||||||||||||||||||||||||||||
| key: { path: ['id'], equals: messageRaw.key.id }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| status: 'PENDING' | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (stillPendingMessage) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.warn(`Forcing status update for PENDING message after timeout: ${messageRaw.key.id}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| await this.prismaRepository.message.update({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { id: stillPendingMessage.id }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| data: { status: 'SERVER_ACK' } | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Emit webhook for the status change | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.sendDataWebhook(Events.MESSAGES_UPDATE, { | ||||||||||||||||||||||||||||||||||||||||||||||||
| messageId: stillPendingMessage.id, | ||||||||||||||||||||||||||||||||||||||||||||||||
| keyId: messageRaw.key.id, | ||||||||||||||||||||||||||||||||||||||||||||||||
| remoteJid: messageRaw.key.remoteJid, | ||||||||||||||||||||||||||||||||||||||||||||||||
| fromMe: messageRaw.key.fromMe, | ||||||||||||||||||||||||||||||||||||||||||||||||
| status: 'SERVER_ACK', | ||||||||||||||||||||||||||||||||||||||||||||||||
| instanceId: this.instanceId | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.error(`Error updating PENDING message status: ${error.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| }, 30000); // 30 seconds timeout | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| await chatbotController.emit({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| instance: { instanceName: this.instance.name, instanceId: this.instanceId }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| remoteJid: messageRaw.key.remoteJid, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1344,13 +1437,13 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const contact = await this.prismaRepository.contact.findFirst({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { remoteJid: received.key.remoteJid, instanceId: this.instanceId }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { remoteJid: normalizedRemoteJid, instanceId: this.instanceId }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const contactRaw: { remoteJid: string; pushName: string; profilePicUrl?: string; instanceId: string } = { | ||||||||||||||||||||||||||||||||||||||||||||||||
| remoteJid: received.key.remoteJid, | ||||||||||||||||||||||||||||||||||||||||||||||||
| remoteJid: normalizedRemoteJid, | ||||||||||||||||||||||||||||||||||||||||||||||||
| pushName: received.key.fromMe ? '' : received.key.fromMe == null ? '' : received.pushName, | ||||||||||||||||||||||||||||||||||||||||||||||||
| profilePicUrl: (await this.profilePicture(received.key.remoteJid)).profilePictureUrl, | ||||||||||||||||||||||||||||||||||||||||||||||||
| profilePicUrl: (await this.profilePicture(normalizedRemoteJid)).profilePictureUrl, | ||||||||||||||||||||||||||||||||||||||||||||||||
| instanceId: this.instanceId, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1481,32 +1574,34 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (update.status !== undefined && status[update.status] !== findMessage.status) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!key.fromMe && key.remoteJid) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| readChatToUpdate[key.remoteJid] = true; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const { remoteJid } = key; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const timestamp = findMessage.messageTimestamp; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const fromMe = key.fromMe.toString(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const normalizedRemoteJid = normalizeJid(remoteJid); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const messageKey = `${normalizedRemoteJid}_${timestamp}_${fromMe}`; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const { remoteJid } = key; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const timestamp = findMessage.messageTimestamp; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const fromMe = key.fromMe.toString(); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const messageKey = `${remoteJid}_${timestamp}_${fromMe}`; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const cachedTimestamp = await this.baileysCache.get(messageKey); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const cachedTimestamp = await this.baileysCache.get(messageKey); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!cachedTimestamp) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Handle read status for received messages | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!key.fromMe && key.remoteJid && status[update.status] === status[4]) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| readChatToUpdate[key.remoteJid] = true; | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.log(`Update as read in message.update ${remoteJid} - ${timestamp}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| await this.updateMessagesReadedByTimestamp(remoteJid, timestamp); | ||||||||||||||||||||||||||||||||||||||||||||||||
| await this.baileysCache.set(messageKey, true, 5 * 60); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (!cachedTimestamp) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (status[update.status] === status[4]) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.log(`Update as read in message.update ${remoteJid} - ${timestamp}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| await this.updateMessagesReadedByTimestamp(remoteJid, timestamp); | ||||||||||||||||||||||||||||||||||||||||||||||||
| await this.baileysCache.set(messageKey, true, 5 * 60); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Update message status for all messages (sent and received) | ||||||||||||||||||||||||||||||||||||||||||||||||
| await this.prismaRepository.message.update({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { id: findMessage.id }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| data: { status: status[update.status] }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| await this.prismaRepository.message.update({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| where: { id: findMessage.id }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| data: { status: status[update.status] }, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.info( | ||||||||||||||||||||||||||||||||||||||||||||||||
| `Update readed messages duplicated ignored in message.update [avoid deadlock]: ${messageKey}`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.log(`Message status updated from ${findMessage.status} to ${status[update.status]} for message ${key.id}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.info( | ||||||||||||||||||||||||||||||||||||||||||||||||
| `Update messages duplicated ignored in message.update [avoid deadlock]: ${messageKey}`, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1935,11 +2030,19 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (message['conversation']) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return await this.client.sendMessage( | ||||||||||||||||||||||||||||||||||||||||||||||||
| sender, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { text: message['conversation'], mentions, linkPreview: linkPreview } as unknown as AnyMessageContent, | ||||||||||||||||||||||||||||||||||||||||||||||||
| option as unknown as MiscMessageGenerationOptions, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.log(`Attempting to send conversation message to ${sender}: ${message['conversation']}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const result = await this.client.sendMessage( | ||||||||||||||||||||||||||||||||||||||||||||||||
| sender, | ||||||||||||||||||||||||||||||||||||||||||||||||
| { text: message['conversation'], mentions, linkPreview: linkPreview } as unknown as AnyMessageContent, | ||||||||||||||||||||||||||||||||||||||||||||||||
| option as unknown as MiscMessageGenerationOptions, | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.log(`Message sent successfully with ID: ${result.key.id}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| return result; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.error(`Failed to send message to ${sender}: ${error.message || JSON.stringify(error)}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| throw error; | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (!message['audio'] && !message['poll'] && !message['sticker'] && sender != 'status@broadcast') { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -3217,12 +3320,35 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| const cachedNumbers = await getOnWhatsappCache(numbersToVerify); | ||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('cachedNumbers', cachedNumbers); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const filteredNumbers = numbersToVerify.filter( | ||||||||||||||||||||||||||||||||||||||||||||||||
| (jid) => !cachedNumbers.some((cached) => cached.jidOptions.includes(jid)), | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Filter numbers that are not cached OR should be re-verified | ||||||||||||||||||||||||||||||||||||||||||||||||
| const filteredNumbers = numbersToVerify.filter((jid) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const cached = cachedNumbers.find((cached) => cached.jidOptions.includes(jid)); | ||||||||||||||||||||||||||||||||||||||||||||||||
| // If not cached, we should verify | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (!cached) return true; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // For Brazilian numbers, force verification if both formats exist in cache | ||||||||||||||||||||||||||||||||||||||||||||||||
| // to ensure we're using the correct format | ||||||||||||||||||||||||||||||||||||||||||||||||
| const isBrazilian = jid.startsWith('55') && jid.includes('@s.whatsapp.net'); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (isBrazilian) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const numberPart = jid.replace('@s.whatsapp.net', ''); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const hasDigit9 = numberPart.length === 13 && numberPart.slice(4, 5) === '9'; | ||||||||||||||||||||||||||||||||||||||||||||||||
| const altFormat = hasDigit9 | ||||||||||||||||||||||||||||||||||||||||||||||||
| ? numberPart.slice(0, 4) + numberPart.slice(5) | ||||||||||||||||||||||||||||||||||||||||||||||||
| : numberPart.slice(0, 4) + '9' + numberPart.slice(4); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const altJid = altFormat + '@s.whatsapp.net'; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // If both formats exist in cache, prefer the one with 9 | ||||||||||||||||||||||||||||||||||||||||||||||||
| const altCached = cachedNumbers.find((c) => c.jidOptions.includes(altJid)); | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (cached && altCached && !hasDigit9) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return true; // Force verification to get the correct format | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return false; // Use cached result | ||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('filteredNumbers', filteredNumbers); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const verify = await this.client.onWhatsApp(...filteredNumbers); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const verify = filteredNumbers.length > 0 ? await this.client.onWhatsApp(...filteredNumbers) : []; | ||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('verify', verify); | ||||||||||||||||||||||||||||||||||||||||||||||||
| normalVerifiedUsers = await Promise.all( | ||||||||||||||||||||||||||||||||||||||||||||||||
| normalUsers.map(async (user) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -3318,7 +3444,6 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| .filter((user) => user.exists) | ||||||||||||||||||||||||||||||||||||||||||||||||
| .map((user) => ({ | ||||||||||||||||||||||||||||||||||||||||||||||||
| remoteJid: user.jid, | ||||||||||||||||||||||||||||||||||||||||||||||||
| jidOptions: user.jid.replace('+', ''), | ||||||||||||||||||||||||||||||||||||||||||||||||
| lid: user.lid, | ||||||||||||||||||||||||||||||||||||||||||||||||
| })), | ||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -4253,8 +4378,15 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| const contentType = getContentType(message.message); | ||||||||||||||||||||||||||||||||||||||||||||||||
| const contentMsg = message?.message[contentType] as any; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| // Normalize JID to handle LID/JID conversion | ||||||||||||||||||||||||||||||||||||||||||||||||
| const normalizedKey = { | ||||||||||||||||||||||||||||||||||||||||||||||||
| ...message.key, | ||||||||||||||||||||||||||||||||||||||||||||||||
| remoteJid: normalizeJid(message.key.remoteJid), | ||||||||||||||||||||||||||||||||||||||||||||||||
| participant: message.key.participant ? normalizeJid(message.key.participant) : undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| const messageRaw = { | ||||||||||||||||||||||||||||||||||||||||||||||||
| key: message.key, | ||||||||||||||||||||||||||||||||||||||||||||||||
| key: normalizedKey, | ||||||||||||||||||||||||||||||||||||||||||||||||
| pushName: | ||||||||||||||||||||||||||||||||||||||||||||||||
| message.pushName || | ||||||||||||||||||||||||||||||||||||||||||||||||
| (message.key.fromMe | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -4269,8 +4401,17 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
| source: getDevice(message.key.id), | ||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (!messageRaw.status && message.key.fromMe === false) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| messageRaw.status = status[3]; // DELIVERED MESSAGE | ||||||||||||||||||||||||||||||||||||||||||||||||
| // Log for debugging PENDING status | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (message.key.fromMe && (!message.status || message.status === 1)) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.logger.warn(`Message sent with PENDING status - ID: ${message.key.id}, Instance: ${this.instance.id}, Status: ${message.status}, RemoteJid: ${message.key.remoteJid}`); | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (!messageRaw.status) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (message.key.fromMe === false) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| messageRaw.status = status[3]; // DELIVERED MESSAGE for received messages | ||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||
| messageRaw.status = status[2]; // SERVER_ACK for sent messages without status | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+4409
to
4415
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (bug_risk): Defaulting sent message status to SERVER_ACK may mask delivery issues. Review whether SERVER_ACK is the appropriate default for all sent messages, or if stricter checks are needed to avoid hiding delivery problems.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if (messageRaw.message.extendedTextMessage) { | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): The cache clearing patterns in clearCorruptedSessionData may be overly broad.
The current cache deletion patterns may match unintended keys, risking accidental data loss. Please refine them to target only the necessary session data.
Suggested implementation: