Skip to content

[BUG] #2353

Description

@devrhapp

1 Conexao com whatsapp sendo encerrada e o status do ticket fica como o valor opening e no celular conectado
trace=Error: Connection Terminated at WebSocketClient. (file:///app/whaticket/backend/node_modules/baileys/src/Socket/socket.ts:835:27) at WebSocketClient.emit (node:events:531:35) at WebSocket. (file:///app/whaticket/backend/node_modules/baileys/src/Socket/Client/websocket.ts:39:52) at WebSocket.emit (node:events:519:28) at WebSocket.emitClose (/app/whaticket/backend/node_modules/ws/lib/websocket.js:273:10) at TLSSocket.socketOnClose (/app/whaticket/backend/node_modules/ws/lib/websocket.js:1346:15) at TLSSocket.emit (node:events:531:35) at node:net:346:12 at TCP.done (node:_tls_wrap:667:7) msg=connection errored
<Buffer 22 74 61 62 6c 65 5f 6e 61 6d 65 22 3b 22 73 65 71 75 65 6e 63 65 5f 6e 61 6d 65 22 0a 41 64 64 72 65 73 73 43 6f 6d 70 61 6e 69 65 73 3b 41 64 64 72 ... 1439 more bytes>

Ja tenho. a version baileys mais recente atualizada mas mesmo assim, nao conecta para criar o qrcod, o status opening o que pode ser ?
`import makeWASocket, {
Browsers,
CacheStore,
DisconnectReason,
fetchLatestBaileysVersion,
isJidBroadcast,
makeCacheableSignalKeyStore,
proto,
WASocket
} from "baileys";

import { Boom } from "@hapi/boom";
import MAIN_LOGGER from "baileys/lib/Utils/logger.js";
import NodeCache from "node-cache";
import AppError from "../errors/AppError.js";
import authState from "../helpers/authState.js";
import Whatsapp from "../models/Whatsapp.js";
import DeleteBaileysService from "../services/BaileysServices/DeleteBaileysService.js";
import { StartWhatsAppSession } from "../services/WbotServices/StartWhatsAppSession.js";
import { logger } from "../utils/logger.js";
import { getIO } from "./socket.js";
import { Store as ExternalStore } from "./store.js";

const loggerBaileys = MAIN_LOGGER.child({});
loggerBaileys.level = "trace"; // Mostra apenas warnings e erros

type Session = WASocket & {
id?: number;
companyId?: number;
store?: ExternalStore;
};

type Store = {
messages: Map<string, proto.IWebMessageInfo[]>;
bind: (ev: WASocket["ev"]) => void;
};

const sessions: Session[] = [];

const retriesQrCodeMap = new Map<number, number>();

// Controle de reconexão para evitar loops
const reconnectionAttempts = new Map<number, { count: number; lastAttempt: number }>();

const canReconnect = (whatsappId: number): boolean => {
const now = Date.now();
const attempts = reconnectionAttempts.get(whatsappId);

if (!attempts) {
reconnectionAttempts.set(whatsappId, { count: 1, lastAttempt: now });
return true;
}

// Se passou mais de 5 minutos, reseta contador
if (now - attempts.lastAttempt > 300000) {
reconnectionAttempts.set(whatsappId, { count: 1, lastAttempt: now });
return true;
}

// Máximo 5 tentativas por 5 minutos
if (attempts.count >= 5) {
logger.warn({
message: "Too many reconnection attempts, skipping",
whatsappId,
attempts: attempts.count,
lastAttempt: new Date(attempts.lastAttempt)
});
return false;
}

attempts.count++;
attempts.lastAttempt = now;
return true;
};

export const getWbot = (whatsappId: number): Session => {
const sessionIndex = sessions.findIndex(s => s.id === whatsappId);

if (sessionIndex === -1) {
logger.error({
ERR_WAPP_NOT_INITIALIZED: "ERR_WAPP_NOT_INITIALIZED",
whatsappId: whatsappId
});
throw new AppError("ERR_WAPP_NOT_INITIALIZED");
}
return sessions[sessionIndex];
};

export function createInMemoryStore(): Store {
const messages = new Map<string, proto.IWebMessageInfo[]>();

const bind = (ev: WASocket["ev"]) => {
ev.on("messages.upsert", ({ messages: newMessages }) => {
for (const msg of newMessages) {
const jid = msg.key.remoteJid!;
if (!messages.has(jid)) messages.set(jid, []);
messages.get(jid)!.push(msg);
}

  logger.warn({ 
    "💾 Mensagens armazenadas": messages.size,
    "📨 Última mensagem": newMessages.length > 0 ? newMessages[0].key.id : 'N/A',
    "🕒 Timestamp": new Date().toISOString()
   });
});

};

return { messages, bind };
}

export const removeWbot = async (
whatsappId: number,
isLogout = true
): Promise => {
try {
const sessionIndex = sessions.findIndex(s => s.id === whatsappId);

if (sessionIndex !== -1) {
  const session = sessions[sessionIndex];
  
  if (isLogout && session) {
    try {
      // Cleanup mais seguro
      session.ev.removeAllListeners("connection.update");
      session.ev.removeAllListeners("creds.update");
      session.ev.removeAllListeners("messages.upsert");
      session.ev.removeAllListeners("messages.update");
      if (session.ws) {
        session.ws.close();
      }
      await session.logout();
    } catch (logoutError) {
      console.log(logoutError);
      
      logger.warn({
        message: "Error during logout, continuing with cleanup",
        error: logoutError,
        whatsappId
      });
    }
  }

  loggerBaileys.debug({
    message: "WHATSAPP_DISCONNECTED",
    level: "debug",
    extra: {
      whatsappId
    }
  });

  sessions.splice(sessionIndex, 1);
  
  logger.info({
    message: "Session removed successfully",
    whatsappId,
    remainingSessions: sessions.length
  });
}

} catch (err) {
console.log(err);
logger.error({ error: err, message: "Error removing wbot", whatsappId });
}
};

export const initWASocket = async (whatsapp: Whatsapp): Promise => {
return new Promise(async (resolve, reject) => {
try {
(async () => {
const io = getIO();

    const whatsappUpdate = await Whatsapp.findOne({
      where: { id: whatsapp.id }
    });

    if (!whatsappUpdate) return;
    const { id, name, provider } = whatsappUpdate;

    const { version, isLatest } = await fetchLatestBaileysVersion();
    const isLegacy = provider === "stable" ? true : false;

    logger.trace(`using WA v${version.join(".")}, isLatest: ${isLatest}`);
    logger.trace(`isLegacy: ${isLegacy}`);
    logger.trace(`Starting session ${name}`);
    let retriesQrCode = 0;

    let wsocket: Session = null;
    let store = createInMemoryStore()

    const { state, saveState } = await authState(whatsapp);

    const msgRetryCounterCache = new NodeCache();
    const userDevicesCache: CacheStore = new NodeCache({
      stdTTL: 600, // 10 minutos de cache para dispositivos
      checkperiod: 120, // Verificação de limpeza a cada 2 minutos
      useClones: false, // Melhor performance
      maxKeys: 10000, // Máximo 10k contatos em cache
      deleteOnExpire: true // Auto-limpeza de entradas expiradas
    });

    wsocket = makeWASocket({
      logger: loggerBaileys,
      printQRInTerminal: false,
      browser: Browsers.appropriate("Desktop"),
      auth: {
        creds: state.creds,
        keys: makeCacheableSignalKeyStore(state.keys, logger)
      },
      version,
      keepAliveIntervalMs: 1000 * 30 , 
      connectTimeoutMs: 60_000, // 60 segundos timeout
      defaultQueryTimeoutMs: 60_000, // 60 segundos para queries
      msgRetryCounterCache,
      userDevicesCache, // Adiciona o cache que você criou
      shouldIgnoreJid: jid => isJidBroadcast(jid),
      // Configurações para melhorar estabilidade com LID
      generateHighQualityLinkPreview: false,
      syncFullHistory: false,
      markOnlineOnConnect: true,
      // Configurações de retry
      retryRequestDelayMs: 5000,
      maxMsgRetryCount: 5
    });

    // Tratamento específico para erros de WebSocket
    wsocket.ws.on('error', (error) => {
      console.log(error);
      
      logger.error({
        message: "WebSocket error detected",
        error: error.message,
        companyId: whatsapp.companyId,
        sessionName: name,
        timestamp: new Date().toISOString()
      });
    });

    wsocket.ws.on('close', (code, reason) => {
      logger.warn({
        message: "WebSocket closed",
        code,
        reason: reason?.toString(),
        companyId: whatsapp.companyId,
        sessionName: name,
        timestamp: new Date().toISOString()
      });
    });

    wsocket.ws.on('unexpected-response', (request, response) => {
      console.log(response);
      
      logger.error({
        message: "WebSocket unexpected response",
        statusCode: response.statusCode,
        statusMessage: response.statusMessage,
        companyId: whatsapp.companyId,
        sessionName: name
      });
    });


    wsocket.ev.on(
      "connection.update",
      async ({ connection, lastDisconnect, qr }) => {
        logger.info(
          `Socket ${name} Connection Update ${connection || ""} ${
            lastDisconnect || ""
          }`
        );

        // Log específico para erro de Connection Terminated
        if (connection === "close" && lastDisconnect?.error) {
          const errorMessage = lastDisconnect.error.message;
          const statusCode = (lastDisconnect?.error as Boom)?.output?.statusCode;
          
          logger.warn({
            message: "Connection closed with error",
            companyId: whatsapp.companyId,
            errorMessage,
            statusCode,
            sessionName: name
          });

          // Se for Connection Terminated, tenta reconectar mais rapidamente
          if (errorMessage?.includes("Connection Terminated")) {
            if (!canReconnect(whatsapp.id)) {
              logger.warn({
                message: "Connection Terminated - reconnection rate limited",
                companyId: whatsapp.companyId,
                sessionName: name
              });
              return;
            }
            
            logger.warn({
              message: "Connection Terminated detected - initiating automatic reconnect",
              companyId: whatsapp.companyId,
              sessionName: name,
              reconnectDelay: "1000ms"
            });
            
            removeWbot(id, false);
            setTimeout(
              () => StartWhatsAppSession(whatsapp, whatsapp.companyId),
              10000 // Reconecta em 1 segundo para Connection Terminated
            );
            return;
          }
        }

        if (connection === "close") {
          logger.warn(
            { message: "Connection closed", companyId: whatsapp.companyId },
            `Connection closed ${name}`
          );
          if ((lastDisconnect?.error as Boom)?.output?.statusCode === 403) {
            logger.error(
              {
                message: "Connection closed. 403 - Forbidden",
                companyId: whatsapp.companyId
              },
              `Connection closed. 403 ${name}`
            );
            await whatsapp.update({ status: "PENDING", session: "" });
            await DeleteBaileysService(whatsapp.id);
            io.to(`company-${whatsapp.companyId}-mainchannel`).emit(
              `company-${whatsapp.companyId}-whatsappSession`,
              {
                action: "update",
                session: whatsapp
              }
            );
            removeWbot(id, false);
          }
          else if (
            (lastDisconnect?.error as Boom)?.output?.statusCode !==
            DisconnectReason.loggedOut
          ) {
            removeWbot(id, false);
            setTimeout(
              () => StartWhatsAppSession(whatsapp, whatsapp.companyId),
              10000 // Aumentei para 10 segundos para dar tempo de limpar a sessão
            );
          } else {
            await whatsapp.update({ status: "PENDING", session: "" });
            logger.error(
              {
                message: "Connection closed. Logged out",
                companyId: whatsapp.companyId
              },
              `Connection closed. Logged out ${name}`
            );
            await DeleteBaileysService(whatsapp.id);
            io.to(`company-${whatsapp.companyId}-mainchannel`).emit(
              `company-${whatsapp.companyId}-whatsappSession`,
              {
                action: "update",
                session: whatsapp
              }
            );
            removeWbot(id, false);
            setTimeout(
              () => StartWhatsAppSession(whatsapp, whatsapp.companyId),
              10000
            );
          }
        }

        if (connection === "open") {
          // Limpa contador de reconexão quando conexão é bem-sucedida
          reconnectionAttempts.delete(whatsapp.id);
          
          // Log específico para verificar LID mapping  
          try {
            // Acesso ao LID mapping via signalRepository (Baileys v7)
            const lidMappingStore = wsocket.signalRepository?.lidMapping;
            const hasLidMapping = !!lidMappingStore;
            
            logger.info({
              message: "🆔 LID Mapping Status",
              companyId: whatsapp.companyId,
              sessionName: name,
              hasLidMapping: hasLidMapping,
              hasSignalRepository: !!wsocket.signalRepository,
              authStateType: typeof wsocket.authState,
              baileyVersion: "v7.x",
              timestamp: new Date().toISOString()
            });
            
            // Se tiver acesso ao store, log algumas informações úteis
            if (lidMappingStore) {
              logger.info({
                message: "✅ LID Mapping Store Available",
                companyId: whatsapp.companyId,
                sessionName: name,
                storeMethods: Object.getOwnPropertyNames(Object.getPrototypeOf(lidMappingStore))
              });
            }
          } catch (error) {
            console.log(error);
            
            logger.warn({
              message: "Could not access LID mapping store",
              error: error.message,
              companyId: whatsapp.companyId
            });
          }
          
          logger.info(
            { 
              message: "Connection successfully established", 
              companyId: whatsapp.companyId,
              sessionName: name,
              status: "CONNECTED"
            },
            `Connection open ${name}`
          );
          await whatsapp.update({
            status: "CONNECTED",
            qrcode: "",
            retries: 0
          });

          io.to(`company-${whatsapp.companyId}-mainchannel`).emit(
            `company-${whatsapp.companyId}-whatsappSession`,
            {
              action: "update",
              session: whatsapp
            }
          );

          const sessionIndex = sessions.findIndex(
            s => s.id === whatsapp.id
          );
          if (sessionIndex === -1) {
            wsocket.id = whatsapp.id;
            wsocket.companyId = whatsapp.companyId;
            sessions.push(wsocket);
          }

          resolve(wsocket);
        }

        if (qr !== undefined) {
          logger.trace(
            { message: "Session QRCode", companyId: whatsapp.companyId },
            `Session QRCode ${name}`
          );
          if (retriesQrCodeMap.get(id) && retriesQrCodeMap.get(id) >= 3) {
            await whatsappUpdate.update({
              status: "DISCONNECTED",
              qrcode: ""
            });
            await DeleteBaileysService(whatsappUpdate.id);
            io.to(`company-${whatsapp.companyId}-mainchannel`).emit(
              "whatsappSession",
              {
                action: "update",
                session: whatsappUpdate
              }
            );
            wsocket.ev.removeAllListeners("connection.update");
            wsocket.ws.close();
            wsocket = null;
            retriesQrCodeMap.delete(id);
          } else {
            logger.trace(
              {
                message: "Session QRCode Generate",
                companyId: whatsapp.companyId
              },
              `Session QRCode Generate ${name}`
            );
            retriesQrCodeMap.set(id, (retriesQrCode += 1));

            await whatsapp.update({
              qrcode: qr,
              status: "qrcode",
              retries: 0
            });
            const sessionIndex = sessions.findIndex(
              s => s.id === whatsapp.id
            );

            if (sessionIndex === -1) {
              wsocket.id = whatsapp.id;
              wsocket.companyId = whatsapp.companyId;
              sessions.push(wsocket);
            }

            io.to(`company-${whatsapp.companyId}-mainchannel`).emit(
              `company-${whatsapp.companyId}-whatsappSession`,
              {
                action: "update",
                session: whatsapp
              }
            );
          }
        }
      }
    );
    
    // Listener específico para LID mapping updates (Baileys v7)
    wsocket.ev.on('lid-mapping.update', (update) => {
      logger.info({
        message: "🆔 LID Mapping Update Received",
        companyId: whatsapp.companyId,
        sessionName: name,
        updateKeys: update ? Object.keys(update) : [],
        timestamp: new Date().toISOString()
      });
      
      // Log específico para cada mapeamento LID/PN atualizado
      if (update && typeof update === 'object') {
        Object.entries(update).forEach(([key, value]) => {
          logger.info({
            message: "📱 New LID/PN Mapping",
            companyId: whatsapp.companyId,
            mappingKey: key,
            mappingValue: value,
            isLid: key.includes('@lid'),
            isPN: key.includes('@s.whatsapp.net')
          });
        });
      }
    });
    
    wsocket.ev.on("creds.update", saveState);

    store.bind(wsocket.ev);
  })();
} catch (error) {
  console.log(error);
  logger.error({ error: error, message: "Error initializing wbot" });
  reject(error);
}

});
};
`
Houve alguma atualizacao para o impacto ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions