pedroslopez / whatsapp-web.js

A WhatsApp client library for NodeJS that connects through the WhatsApp Web browser app
https://wwebjs.dev
Apache License 2.0
15.23k stars 3.64k forks source link

Get current client state #268

Closed glbatistabh closed 2 years ago

glbatistabh commented 4 years ago

After connecting to WhastAppWeb, the Client.info variable is set to with the client information (Client.info = new ClientInfo) ;

However, when there is a drop/break in the connection with WhastAppWeb (or explicitly, one of the methods destroy and logout is called) the variable Client.info remains set.

Is that correct? I believe that Client.info should be reset, correct?

image

pedroslopez commented 4 years ago

Hi, Is there a reason why you would need this cleared?

glbatistabh commented 4 years ago

it was the way I found to test if the client is authenticated/connected with whatsapp web, to prevent other methods were called (ex: getState, getContacts, etc ...).

Is there a more 'elegant/correct' way (eg, client.isConnected()) to test whether the client is connected?

see a simplified example of my code:

app.get('/contacts', middleVerifyAccess, function(req, res) {

  if (!client || !client.info) {
    return res.status(402).json({status: 'error', message: 'Unauthenticated Client'});
  }

  client.getContacts()
      .then((contacts) => {
        res.status(200).json({contacts: contacts});
      })
      .catch((error) => {
        res.status(500).json({contacts: null, status: 'error', message: error});
      });
});
pedroslopez commented 4 years ago

At the moment there's nothing that directly indicates whether the client has been initialized/is authenticated. As a workaround, something you could check is whether the underlying puppeteer page has been set or closed:

if(!client.pupPage) {
    // client has not been initialized
}

// or

if(client.pupPage.isClosed()) {
    // client has been destroyed
}

Regardless, I do think the state is something that we could/should add as part of the client itself.

glbatistabh commented 4 years ago

Thanks for the sugestion!

And yes ... two methods that are interesting to have on the client. client.isConnected () client.getInfo ()

guicuton commented 4 years ago

I've develop one method that emit a message on client if user is paired or not, based on chat list (left menu with chat list) I'll send a pull to be analyzed

pedroslopez commented 4 years ago

@guicuton I don't think an event would address the issue. @glbatistabh is looking for a way to determine if the client has been properly initialized/is currently connected. An event would tell you when this happens, but it would be up to you to store that information somewhere, which you can already do currently.

I think the proper course of action here would be to either have a property on the client that keeps track of the current state or have a function (or boolean property) that indicates whether the client is connected or not. I think having the function, as suggested by @glbatistabh that checks if it's connected would be the simplest and most straightforward solution.

guicuton commented 4 years ago

@pedroslopez i see... now i did understood his question haha For this i've used something based on your suggestion about client.pupPage


    var webReady = 0;
    client.on('qr', (qr) => {

      webReady++;
      if(webReady === 1) {
        console.log('Client is ready, Waiting qrcode')
      }

    });
salvuccicarlos commented 2 years ago

Hello @pedroslopez Any news on this? I'm using LocalAuth as authentication strategy and I need to "reuse" the connected browser in order to send new messages.

I have this code:

const clientIntializer = (client) => {

        console.log('NO SE HA INICIALIZADO EL CLIENTE');

        client = new Client({
            authStrategy: new LocalAuth(),
            puppeteer: { headless: false, args: ["--no-sandbox"] }
        });;

        console.log('ESTE ES EL client en clientIntializer(): ' + client);

        client.initialize();

        return client;
    };

But it seems that client is not reachable after the first initialization (error: Cannot read property 'sendMessage' of undefined)

client.on('ready', async () => {
            client.sendMessage('xxx@c.us', 'Iniciado');
            console.log('Mensaje de enviado a xxx')
        })

Right now each time I need to send a new message I have to restart the server and run this code:

const sendMessage = async () => {
        client = new Client({
            authStrategy: new LocalAuth()
        });

        client.on('ready', async () => {
            for (let i = 0; i < to.length; i++) {
                client.sendMessage(to[i].celular + '@c.us', message);
                console.log('Mensaje enviado a ' + to[i].celular);
                response.to = to[i].celular
            }
        });

        client.initialize();
    };

If I don't restart the server messages are not sent. I used non headless mode and the issue is that when I run again the code instead of scrapping the opened whatsapp web page, it opens an about:blank page and freezes.

How can I solve this? I've tried checking client.pupPage but it's a null variable.

Do I have any options or I should finish each session each time I want to send new messages?

ShanthiniMM commented 1 year ago

Hello @pedroslopez Any news on this? I'm using LocalAuth as authentication strategy and I need to "reuse" the connected browser in order to send new messages.

I have this code:

const clientIntializer = (client) => {

        console.log('NO SE HA INICIALIZADO EL CLIENTE');

        client = new Client({
            authStrategy: new LocalAuth(),
            puppeteer: { headless: false, args: ["--no-sandbox"] }
        });;

        console.log('ESTE ES EL client en clientIntializer(): ' + client);

        client.initialize();

        return client;
    };

But it seems that client is not reachable after the first initialization (error: Cannot read property 'sendMessage' of undefined)

client.on('ready', async () => {
            client.sendMessage('xxx@c.us', 'Iniciado');
            console.log('Mensaje de enviado a xxx')
        })

Right now each time I need to send a new message I have to restart the server and run this code:

const sendMessage = async () => {
        client = new Client({
            authStrategy: new LocalAuth()
        });

        client.on('ready', async () => {
            for (let i = 0; i < to.length; i++) {
                client.sendMessage(to[i].celular + '@c.us', message);
                console.log('Mensaje enviado a ' + to[i].celular);
                response.to = to[i].celular
            }
        });

        client.initialize();
    };

If I don't restart the server messages are not sent. I used non headless mode and the issue is that when I run again the code instead of scrapping the opened whatsapp web page, it opens an about:blank page and freezes.

How can I solve this? I've tried checking client.pupPage but it's a null variable.

Do I have any options or I should finish each session each time I want to send new messages?

Hi @salvuccicarlos, I am also facing this problem. Have you found any solution?

salvuccicarlos commented 1 year ago

Hi! No, It seems it is impossible to use the same initialized session after ir's first use. I have to kill the browser and start it again each time I need to send a message...

SannanOfficial commented 1 year ago

Hi everyone, there seems to be a client.getState() function for this now, that returns the current state of the client. You can also use the disconnected event and do what you want whenever the client disconnects for whatever reason.

SannanOfficial commented 1 year ago

Just tested out the disconnected event, it works fine, but with a few seconds of latency, similar to the ready event.

SannanOfficial commented 1 year ago

Update: The disconnect event works if the WhatsApp session is closed correctly. It seems that if the puppeteer windows are abruptly shut down (such as from process kill or the windows taskbar), then it won't detect the disconnect event, keeping you in the dark. To get through this, I think @pedroslopez solution is better:

At the moment there's nothing that directly indicates whether the client has been initialized/is authenticated. As a workaround, something you could check is whether the underlying puppeteer page has been set or closed:

if(!client.pupPage) {
    // client has not been initialized
}

// or

if(client.pupPage.isClosed()) {
    // client has been destroyed
}

Regardless, I do think the state is something that we could/should add as part of the client itself.