From 5cf069f86b49425ba15f57d5e1b8d8d8f68e7d1b Mon Sep 17 00:00:00 2001 From: Vilsonei Machado Date: Wed, 28 Aug 2024 17:42:23 -0300 Subject: [PATCH 1/5] =?UTF-8?q?Tratativa=20para=20resolver=20o=20problema?= =?UTF-8?q?=20de=20reconex=C3=A3o=20quando=20h=C3=A1=20perdas=20de=20conex?= =?UTF-8?q?=C3=A3o=20com=20o=20WebSocket.=20Antes=20ficavam=20v=C3=A1rios?= =?UTF-8?q?=20listeners=20escutando=20um=20client=20inexistente.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/whatsapp/services/whatsapp.service.ts | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cdaf30521..7ec25413f 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build": "tsc", "start": "ts-node --files --transpile-only ./src/main.ts", "start:prod": "bash start.sh", - "start:dev": "cls && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts", + "start:dev": "tsnd --files --transpile-only --respawn --ignore-watch node_modules ./src/main.ts", "test": "clear && tsnd --files --transpile-only --respawn --ignore-watch node_modules ./test/all.test.ts" }, "repository": { diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index 4f4566ea2..18d41a819 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -178,6 +178,7 @@ export class WAStartupService { this.configService.get('DATABASE'); private endSession = false; + private inReconnection = false; public client: WASocket; private authState: Partial = {}; private authStateProvider: AuthStateProvider; @@ -424,7 +425,7 @@ export class WAStartupService { if (connection === 'close') { const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut; - if (shouldReconnect) { + if (shouldReconnect && !this.inReconnection) { await this.connectToWhatsapp(); } else { this.sendDataWebhook('statusInstance', { @@ -552,12 +553,22 @@ export class WAStartupService { public async connectToWhatsapp(): Promise { try { this.instanceQr.count = 0; - await this.loadWebhook(); - this.client = await this.setSocket(); - this.eventHandler(); + const timeout = this.client ? 3000 : 0; + + if (!this.inReconnection) { + this.inReconnection = true; + setTimeout(async () => { + await this.loadWebhook(); + this.client = await this.setSocket(); + this.eventHandler(); + + this.inReconnection = false; + }, timeout); + } return this.client; } catch (error) { + this.inReconnection = false; this.logger.error(error); throw new InternalServerErrorException(error?.toString()); } From 32342fd18dfe3918af4e1349cc68983cb8ec60b5 Mon Sep 17 00:00:00 2001 From: Vilsonei Machado Date: Wed, 28 May 2025 08:26:49 -0300 Subject: [PATCH 2/5] =?UTF-8?q?Corre=C3=A7=C3=A3o=20da=20nova=20vers=C3=A3?= =?UTF-8?q?o=20do=20WhatsApp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.dev b/.env.dev index 4f8f11175..3a1ec0f6f 100644 --- a/.env.dev +++ b/.env.dev @@ -65,7 +65,7 @@ INSTANCE_EXPIRATION_TIME=false CONFIG_SESSION_PHONE_CLIENT=CodeChat_V1 CONFIG_SESSION_PHONE_NAME=Edge -WA_VERSION=[ 2, 3000, 1015901307 ] +WA_VERSION=[ 2, 3000, 1023047013 ] # Set qrcode display limit QRCODE_LIMIT=5 From cc6190a134bba9660276e0a5d9bb7b8baee348c5 Mon Sep 17 00:00:00 2001 From: Vilsonei Machado Date: Wed, 28 May 2025 11:15:17 -0300 Subject: [PATCH 3/5] =?UTF-8?q?-=20Atualiza=C3=A7=C3=A3o=20do=20whiskeysoc?= =?UTF-8?q?kets/baileys=20para=20vers=C3=A3o=206.7.18=20-=20Corre=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20bug=20no=20whatsapp.service=20quando=20n=C3=A3o?= =?UTF-8?q?=20encontra=20um=20chat=20no=20banco=20de=20dados=20-=20Corre?= =?UTF-8?q?=C3=A7=C3=A3o=20da=20deped=C3=AAncia=20sharp=20para=20whiskeyso?= =?UTF-8?q?ckets/baileys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 ++-- src/whatsapp/services/whatsapp.service.ts | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index cb6bf9763..9eabc1583 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@adiwajshing/keyed-db": "^0.2.4", "@hapi/boom": "^10.0.1", "@prisma/client": "^5.19.1", - "@whiskeysockets/baileys": "^6.7.12", + "@whiskeysockets/baileys": "^6.7.18", "axios": "^1.7.7", "class-validator": "^0.14.0", "cross-env": "^7.0.3", @@ -70,7 +70,7 @@ "pino-pretty": "^11.0.0", "qrcode": "^1.5.1", "qrcode-terminal": "^0.12.0", - "sharp": "^0.33.5", + "sharp": "^0.32.6", "swagger-ui-express": "^5.0.1", "ulid": "^2.3.0", "ws": "^8.18.0", diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index ffcb2f664..82864c2da 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -661,8 +661,9 @@ export class WAStartupService { remoteJid: chat.remoteJid, }, }) - .then((result) => - this.repository.chat + .then((result) =>{ + if (result) { + this.repository.chat .update({ where: { id: result.id, @@ -672,8 +673,9 @@ export class WAStartupService { updatedAt: new Date(), }, }) - .catch((err) => this.logger.error(err)), - ) + .catch((err) => this.logger.error(err)) + } + }) .catch((err) => this.logger.error(err)); }); }, From 8b10bb7626153ca80bacc0fc299266ab1456cff6 Mon Sep 17 00:00:00 2001 From: Vilsonei Machado Date: Wed, 15 Oct 2025 22:18:30 -0300 Subject: [PATCH 4/5] Bug fix for 'ghost instances' occurring when the server loses internet connection and multiple clients are created simultaneously, causing a connection event overload until the instance becomes unpaired. --- src/whatsapp/services/whatsapp.service.ts | 74 ++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/src/whatsapp/services/whatsapp.service.ts b/src/whatsapp/services/whatsapp.service.ts index 63e3fc6e2..a81e33b0f 100644 --- a/src/whatsapp/services/whatsapp.service.ts +++ b/src/whatsapp/services/whatsapp.service.ts @@ -193,6 +193,7 @@ export class WAStartupService { public client: WASocket; private authState: Partial = {}; private authStateProvider: AuthStateProvider; + private clientGeneration = 0; public async setInstanceName(name: string) { const i = await this.repository.instance.findUnique({ @@ -573,10 +574,16 @@ export class WAStartupService { public async connectToWhatsapp(): Promise { try { + // Remove listener from the old connection before creating a new one. + if (this.client) { + await this.closeBaileysSocket('reconnect'); + } + this.instanceQr.count = 0; await this.loadWebhook(); this.client = await this.setSocket(); - this.eventHandler(); + const gen = ++this.clientGeneration; + this.eventHandler(gen); return this.client; } catch (error) { @@ -1076,8 +1083,11 @@ export class WAStartupService { }, }; - private eventHandler() { + private eventHandler(gen: number) { this.client.ev.process((events) => { + // Do not process events from outdated/closed clients + if (gen !== this.clientGeneration) return; + if (!this.endSession) { if (events?.['connection.update']) { this.connectionUpdate(events['connection.update']); @@ -2527,4 +2537,64 @@ export class WAStartupService { throw new BadRequestException('Unable to leave the group', error.toString()); } } + + private registeredEvents: (keyof BaileysEventMap)[] = [ + 'connection.update', + 'creds.update', + 'messaging-history.set', + 'messages.upsert', + 'messages.update', + 'presence.update', + 'groups.upsert', + 'groups.update', + 'group-participants.update', + 'chats.upsert', + 'chats.update', + 'chats.delete', + 'contacts.upsert', + 'contacts.update', + 'call', + 'labels.association', + 'labels.edit' + ]; + + private removeAllBaileysListeners() { + for (const evName of this.registeredEvents) { + try { + this.client.ev.removeAllListeners(evName); + } catch {} + } +} + + private async closeBaileysSocket(reason = 'manual shutdown') { + if (!this.client) return; + + // 1) Stop processing events during teardown + this.endSession = true; + + // 2) Remove all listeners from the emitter + this.removeAllBaileysListeners(); + + // 3) Close the WebSocket (gracefully) + try { this.client.ws?.close(); } catch {} + + // 4) Ask Baileys to close the connection + try { this.client.end(new Error(reason)); } catch {} + + // 5) Wait for the 'close' event to ensure it has finished + await new Promise((resolve) => { + let done = false; + const finish = () => { if (!done) { done = true; resolve(); } }; + if (this.client?.ws?.once) { + this.client.ws.once('close', finish); + setTimeout(finish, 3000); // Safety timeout + } else { + finish(); + } + }); + + this.client = null as any; + this.endSession = false; + } + } From e75070b2865668b8806987691db5bc1d2f0f548d Mon Sep 17 00:00:00 2001 From: Vilsonei Machado Date: Wed, 15 Oct 2025 22:19:38 -0300 Subject: [PATCH 5/5] .env.dev removed --- .env.dev | 126 ------------------------------------------------------- 1 file changed, 126 deletions(-) delete mode 100644 .env.dev diff --git a/.env.dev b/.env.dev deleted file mode 100644 index b0e9719da..000000000 --- a/.env.dev +++ /dev/null @@ -1,126 +0,0 @@ -# ┌──────────────────────────────────────────────────────────────────────────────┐ -# │ @author jrCleber | -# │ @filename dev-env.yml │ -# │ Developed by: Cleber Wilson │ -# │ File name: dev-env.yml │ -# │ Creation date: Dez 03, 2023 │ -# │ Contact: contato@codechat.dev │ -# ├──────────────────────────────────────────────────────────────────────────────┤ -# │ @copyright © Cleber Wilson 2022. All rights reserved. │ -# │ Licensed under the Apache License, Version 2.0 │ -# │ │ -# │ @license "https://github.com/code-chat-br/whatsapp-api/blob/main/LICENSE" │ -# │ │ -# │ You may not use this file except in compliance with the License. │ -# │ You may obtain a copy of the License at │ -# │ │ -# │ http://www.apache.org/licenses/LICENSE-2.0 │ -# │ │ -# │ Unless required by applicable law or agreed to in writing, software │ -# │ distributed under the License is distributed on an "AS IS" BASIS, │ -# │ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ -# │ │ -# │ See the License for the specific language governing permissions and │ -# │ limitations under the License. │ -# ├──────────────────────────────────────────────────────────────────────────────┤ -# │ @important │ -# │ For any future changes to the code in this file, it is recommended to │ -# │ contain, together with the modification, the information of the developer │ -# │ who changed it and the date of modification. │ -# └──────────────────────────────────────────────────────────────────────────────┘ - -# ⚠️ -# ⚠️ ALL SETTINGS DEFINED IN THIS FILE ARE APPLIED TO ALL INSTANCES. -# ⚠️ - -# ⚠️ COPY THIS FILE TO .env - -SERVER_PORT=8084 -SESSION_HTTP_SECRET=W0NvZGVDaGF0XTpbU2Vzc - -LOG_LEVEL=ERROR|WARN|INFO|DEBUG|LOG -LOG_COLOR=true - -# Permanente data storage -DATABASE_URL=postgres://[USER]:[PASS]@[HOST]:[PORT]/DATABASE -DATABASE_SYNC_MESSAGES=true -DATABASE_SAVE_DATA_NEW_MESSAGE=true -DATABASE_SAVE_MESSAGE_UPDATE=true -DATABASE_SAVE_DATA_CONTACTS=true -DATABASE_SAVE_DATA_CHATS=true -DATABASE_SAVE_LOGS=true -DATABASE_SAVE_ACTIVITY_LOGS=true - -# Global Webhook -# It will notify all events of all businesses and instances. -WEBHOOK_GLOBAL_URL=url -WEBHOOK_GLOBAL_ENABLED=false - -# Determine how long the instance should be deleted from memory in case of no connection. -# Default time: 5 minutes -# If you don't even want an expiration, enter the value false -INSTANCE_EXPIRATION_TIME=false - -# Name that will be displayed on smartphone connection -CONFIG_SESSION_PHONE_CLIENT=CodeChat_V1 -CONFIG_SESSION_PHONE_NAME=Edge - -WA_VERSION=[ 2, 3000, 1025257277 ] - -# Set qrcode display limit -QRCODE_LIMIT=5 -QRCODE_EXPIRATION_TIME=20 # seconds -QRCODE_LIGHT_COLOR='#ffffff' -QRCODE_DARK_COLOR='#198754' - -# Maximun time to connect to whatsapp -CONNECTION_TIMEOUT=120 # seconds - -AUTHENTICATION_GLOBAL_AUTH_TOKEN=zYzP7ocstxh3Sscefew4FZTCu4ehnM8v4hu - -# 0 = never expires | 3600 = 1 hour | 86400 = 1 day | 604800 = 1 week -AUTHENTICATION_JWT_EXPIRES_IN=0 -AUTHENTICATION_JWT_SECRET=3RFYwe-fwf4fw4w8e-BrLZzx - -# Seesion Files Providers -# Provider responsible for managing credentials files and WhatsApp sessions. -PROVIDER_ENABLED=false -PROVIDER_HOST=127.0.0.1 -PROVIDER_PORT=5656 -PROVIDER_PREFIX=codechat - -# Proxy: (http|https|sock\d{1}) -# -# Proxy usado pelo WebSocket -WS_PROXY_URL= -# Proxy usado para upload/download de mídia -FETCH_PROXY_URL= - -# URL em que a documetação será exibida -# EX.: v1.dodmain.com -API_BACKEND= - -# https://min.io/docs/minio/linux/index.html -S3_ENABLED=false -S3_ACCESS_KEY=access_key_id -S3_SECRET_KEY=secret_access_key -S3_BUCKET=bucket_name -S3_PORT=9000 -S3_ENDPOINT=127.0.0.1 -S3_USE_SSL=false - -# AMAZON S3 - Environment variables -# S3_ENABLED=true -# S3_BUCKET=bucket_name -# S3_ACCESS_KEY=access_key_id -# S3_SECRET_KEY=secret_access_key -# S3_ENDPOINT=s3.amazonaws.com # region: s3.eu-west-3.amazonaws.com - -# MINIO Use SSL - Environment variables -# S3_ENABLED=true -# S3_ACCESS_KEY=access_key_id -# S3_SECRET_KEY=secret_access_key -# S3_BUCKET=bucket_name -# S3_PORT=443 -# S3_ENDPOINT=s3.domain.com -# S3_USE_SSL=true