Skip to content

Commit 933a28d

Browse files
committed
feat(baileys): enhance logout process and connection handling
- Introduced a flag to prevent reconnection during instance deletion. - Improved logging for connection updates and errors during logout. - Added a delay before reconnection attempts to avoid rapid loops. - Enhanced webhook headers for better tracking and debugging. - Updated configuration to support manual Baileys version setting.
1 parent 6f2bef6 commit 933a28d

File tree

4 files changed

+91
-8
lines changed

4 files changed

+91
-8
lines changed

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

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ export class BaileysStartupService extends ChannelStartupService {
249249
private readonly msgRetryCounterCache: CacheStore = new NodeCache();
250250
private readonly userDevicesCache: CacheStore = new NodeCache({ stdTTL: 300000, useClones: false });
251251
private endSession = false;
252+
private isDeleting = false; // Flag to prevent reconnection during deletion
252253
private logBaileys = this.configService.get<Log>('LOG').BAILEYS;
253254
private eventProcessingQueue: Promise<void> = Promise.resolve();
254255

@@ -265,10 +266,27 @@ export class BaileysStartupService extends ChannelStartupService {
265266
}
266267

267268
public async logoutInstance() {
269+
// Mark instance as deleting to prevent reconnection attempts
270+
this.isDeleting = true;
271+
this.endSession = true;
272+
268273
this.messageProcessor.onDestroy();
269-
await this.client?.logout('Log out instance: ' + this.instanceName);
270274

271-
this.client?.ws?.close();
275+
if (this.client) {
276+
try {
277+
await this.client.logout('Log out instance: ' + this.instanceName);
278+
} catch (error) {
279+
this.logger.error({ message: 'Error during logout', error });
280+
}
281+
282+
// Improved socket cleanup
283+
try {
284+
this.client.ws?.close();
285+
this.client.end(new Error('Instance logout'));
286+
} catch (error) {
287+
this.logger.error({ message: 'Error during socket cleanup', error });
288+
}
289+
}
272290

273291
const db = this.configService.get<Database>('DATABASE');
274292
const cache = this.configService.get<CacheConf>('CACHE');
@@ -332,6 +350,18 @@ export class BaileysStartupService extends ChannelStartupService {
332350
}
333351

334352
private async connectionUpdate({ qr, connection, lastDisconnect }: Partial<ConnectionState>) {
353+
// Enhanced logging for connection updates
354+
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode;
355+
this.logger.info({
356+
message: 'Connection update received',
357+
connection,
358+
hasQr: !!qr,
359+
statusCode,
360+
instanceName: this.instance.name,
361+
isDeleting: this.isDeleting,
362+
endSession: this.endSession,
363+
});
364+
335365
if (qr) {
336366
if (this.instance.qrcode.count === this.configService.get<QrCode>('QRCODE').LIMIT) {
337367
this.sendDataWebhook(Events.QRCODE_UPDATED, {
@@ -424,11 +454,29 @@ export class BaileysStartupService extends ChannelStartupService {
424454
}
425455

426456
if (connection === 'close') {
457+
// Check if instance is being deleted or session is ending
458+
if (this.isDeleting || this.endSession) {
459+
this.logger.info('Instance is being deleted/ended, skipping reconnection attempt');
460+
return;
461+
}
462+
427463
const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode;
428464
const codesToNotReconnect = [DisconnectReason.loggedOut, DisconnectReason.forbidden, 402, 406];
429465
const shouldReconnect = !codesToNotReconnect.includes(statusCode);
466+
467+
this.logger.info({
468+
message: 'Connection closed, evaluating reconnection',
469+
statusCode,
470+
shouldReconnect,
471+
instanceName: this.instance.name,
472+
});
473+
430474
if (shouldReconnect) {
431-
await this.connectToWhatsapp(this.phoneNumber);
475+
// Add 3 second delay before reconnection to prevent rapid reconnection loops
476+
this.logger.info('Reconnecting in 3 seconds...');
477+
setTimeout(async () => {
478+
await this.connectToWhatsapp(this.phoneNumber);
479+
}, 3000);
432480
} else {
433481
this.sendDataWebhook(Events.STATUS_INSTANCE, {
434482
instance: this.instance.name,
@@ -591,18 +639,19 @@ export class BaileysStartupService extends ChannelStartupService {
591639
this.logger.info(`Browser: ${browser}`);
592640
}
593641

642+
// Fetch latest WhatsApp Web version automatically
594643
const baileysVersion = await fetchLatestWaWebVersion({});
595644
const version = baileysVersion.version;
596-
const log = `Baileys version: ${version.join('.')}`;
597645

646+
const log = `Baileys version: ${version.join('.')}`;
598647
this.logger.info(log);
599648

600649
this.logger.info(`Group Ignore: ${this.localSettings.groupsIgnore}`);
601650

602651
let options;
603652

604653
if (this.localProxy?.enabled) {
605-
this.logger.info('Proxy enabled: ' + this.localProxy?.host);
654+
this.logger.verbose('Proxy enabled');
606655

607656
if (this.localProxy?.host?.includes('proxyscrape')) {
608657
try {
@@ -611,9 +660,10 @@ export class BaileysStartupService extends ChannelStartupService {
611660
const proxyUrls = text.split('\r\n');
612661
const rand = Math.floor(Math.random() * Math.floor(proxyUrls.length));
613662
const proxyUrl = 'http://' + proxyUrls[rand];
663+
this.logger.info('Proxy url: ' + proxyUrl);
614664
options = { agent: makeProxyAgent(proxyUrl), fetchAgent: makeProxyAgentUndici(proxyUrl) };
615-
} catch {
616-
this.localProxy.enabled = false;
665+
} catch (error) {
666+
this.logger.error(error);
617667
}
618668
} else {
619669
options = {

src/api/integrations/event/webhook/webhook.controller.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,20 @@ export class WebhookController extends EventController implements EventControlle
124124

125125
try {
126126
if (instance?.enabled && regex.test(instance.url)) {
127+
// Add custom headers for better webhook tracking and debugging
128+
const enhancedHeaders = {
129+
...webhookHeaders,
130+
'Content-Type': 'application/json',
131+
'X-Instance-ID': this.monitor.waInstances[instanceName].instanceId,
132+
'X-Instance-Name': instanceName,
133+
'X-Event-Type': event,
134+
'X-Timestamp': Date.now().toString(),
135+
'User-Agent': 'EvolutionAPI-Webhook/2.3.7',
136+
};
137+
127138
const httpService = axios.create({
128139
baseURL,
129-
headers: webhookHeaders as Record<string, string> | undefined,
140+
headers: enhancedHeaders as Record<string, string>,
130141
timeout: webhookConfig.REQUEST?.TIMEOUT_MS ?? 30000,
131142
});
132143

src/config/env.config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ export type Webhook = {
313313
};
314314
export type Pusher = { ENABLED: boolean; GLOBAL?: GlobalPusher; EVENTS: EventsPusher };
315315
export type ConfigSessionPhone = { CLIENT: string; NAME: string };
316+
export type Baileys = { VERSION?: string };
316317
export type QrCode = { LIMIT: number; COLOR: string };
317318
export type Typebot = { ENABLED: boolean; API_VERSION: string; SEND_MEDIA_BASE64: boolean };
318319
export type Chatwoot = {
@@ -410,6 +411,7 @@ export interface Env {
410411
WEBHOOK: Webhook;
411412
PUSHER: Pusher;
412413
CONFIG_SESSION_PHONE: ConfigSessionPhone;
414+
BAILEYS: Baileys;
413415
QRCODE: QrCode;
414416
TYPEBOT: Typebot;
415417
CHATWOOT: Chatwoot;
@@ -800,6 +802,9 @@ export class ConfigService {
800802
CLIENT: process.env?.CONFIG_SESSION_PHONE_CLIENT || 'Evolution API',
801803
NAME: process.env?.CONFIG_SESSION_PHONE_NAME || 'Chrome',
802804
},
805+
BAILEYS: {
806+
VERSION: process.env?.CONFIG_BAILEYS_VERSION,
807+
},
803808
QRCODE: {
804809
LIMIT: Number.parseInt(process.env.QRCODE_LIMIT) || 30,
805810
COLOR: process.env.QRCODE_COLOR || '#198754',

src/utils/fetchLatestWaWebVersion.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
11
import axios, { AxiosRequestConfig } from 'axios';
22
import { fetchLatestBaileysVersion, WAVersion } from 'baileys';
33

4+
import { Baileys, configService } from '../config/env.config';
5+
46
export const fetchLatestWaWebVersion = async (options: AxiosRequestConfig<{}>) => {
7+
// Check if manual version is set via configuration
8+
const baileysConfig = configService.get<Baileys>('BAILEYS');
9+
const manualVersion = baileysConfig?.VERSION;
10+
11+
if (manualVersion) {
12+
const versionParts = manualVersion.split('.').map(Number);
13+
if (versionParts.length === 3 && !versionParts.some(isNaN)) {
14+
return {
15+
version: versionParts as WAVersion,
16+
isLatest: false,
17+
isManual: true,
18+
};
19+
}
20+
}
21+
522
try {
623
const { data } = await axios.get('https://web.whatsapp.com/sw.js', {
724
...options,

0 commit comments

Comments
 (0)