whatsapp-api-nodejs icon indicating copy to clipboard operation
whatsapp-api-nodejs copied to clipboard

Waiting for this message

Open mnsise opened this issue 2 years ago • 28 comments

When i send message to new number first time messages not showing ...Show only "Waiting for this message. This may take a while" screenshot attatched 168733368-770f2fac-c54e-4d5f-8af4-a3478d22fde8

mnsise avatar Jun 26 '22 11:06 mnsise

not an issue with this library

dv336699 avatar Jun 28 '22 13:06 dv336699

@salman0ansari simply superb..I found your api while browsing internet and am impressed. is there any way to contact you. my email is [email protected]. I am from India . Mob: 7004635353. I would love to get connected with you.

rajuaryan21 avatar Jun 29 '22 12:06 rajuaryan21

btw, this issue can be solved with using the msgRetryHandler that baileys provides.

rajuaryan21 avatar Jun 29 '22 12:06 rajuaryan21

@salman0ansari simply superb..I found your api while browsing internet and am impressed. is there any way to contact you. my email is [email protected]. I am from India . Mob: 7004635353. I would love to get connected with you.

Msg me on telegram @salman0ansari

salman0ansari avatar Jun 29 '22 14:06 salman0ansari

not an issue with this library please check link https://github.com/adiwajshing/Baileys/issues/1631

mnsise avatar Jun 30 '22 07:06 mnsise

same here, for temp solution please read https://github.com/adiwajshing/Baileys/issues/1631#issuecomment-1130930782

mnsise avatar Jul 05 '22 18:07 mnsise

I have written this script, check it out. Now works well in my API

import { proto } from "@adiwajshing/baileys";

export const makeRetryHandler = () => {
 const messagesMap: Record<
   string,
   {
     ts: number;
     message: proto.IMessage;
   }
 > = {};

 const addMessage = async (message: proto.IWebMessageInfo) => {
   const id = message.key.id ?? "";

   messagesMap[id] = {
     message: cleanMessage(message),
     ts: Date.now(),
   };

   return message;
 };

 const getMessage = (msgKey: string): proto.IMessage => {
   return messagesMap[msgKey].message;
 };

 const removeMessage = (msgKey: string) => {
   delete messagesMap[msgKey];
 };

 const getMessageKeys = (): string[] => {
   return Object.keys(messagesMap);
 };

 const cleanMessage = (message: proto.IWebMessageInfo): proto.IMessage => {
   const msg = message.message ?? {};
   return msg;
 };

 const clearObseleteMessages = () => {
   // Check if the message is older than 60 seconds
   const keys = Object.keys(messagesMap);
   keys.forEach((key) => {
     const ts = messagesMap[key].ts;
     if (Date.now() - ts > 60_000) {
       removeMessage(key);
     }
   });
 };

 return {
   addMessage,
   getMessage,
   removeMessage,
   getMessageKeys,
   cleanMessage,
   clearObseleteMessages,
   getHandler: (message: proto.IMessageKey) => {
     const msg = getMessage(message.id ?? "");
     console.log("Retrying message", msg);
     return msg;
   },
 };
};

Then use it as follows :


const handler = makeRetryHandler();

socket = makeWASocket({
	...yourConfig,
	getMessage: handler.getHandler
});

// Sending message
await socket?.sendMessage(jid, {
            text : "Hello",
       })
          .then(handler.addMessage);

This does the following things :

  • [x] Handle failed message
  • [x] Handle all types of messages
  • [x] Exposes method to delete older used messages
  • [x] Exposes method to get the failed message
  • [x] Adds failed message to store as well

Manjit2003 avatar Jul 07 '22 17:07 Manjit2003

btw, this issue can be solved with using the msgRetryHandler that baileys provides.

can you provide this solution for us? thanks

silvalucas9031 avatar Jul 08 '22 22:07 silvalucas9031

This is the solution. The maintainer just has to implement it

Manjit2003 avatar Jul 09 '22 00:07 Manjit2003

I have written this script

// file store.js

const { proto } = require('@adiwajshing/baileys')

class makeRetryHandler {
    messagesMap = { }

    // Add Message
    async addMessage(message) {
       const id = message.key.id ?? "";
       this.messagesMap[id] = {
         message: this.cleanMessage(message),
         ts: Date.now(),
       };
       return message;
    }    

    // Add getMessage
    async getMessage(msgKey) {
       return this.messagesMap[msgKey];
    }    

    // removeMessage
    async removeMessage(msgKey) {
       delete this.messagesMap[msgKey];
    }    

    // getMessageKeys
    async getMessageKeys() {
       return Object.keys(this.messagesMap);
    }    

    // cleanMessage
    async cleanMessage(message) {
       const msg = message.message ?? {};
       return msg;
    }    

    // clearObseleteMessages
    async clearObseleteMessages() {
       // Check if the message is older than 60 seconds
       const keys = Object.keys(this.messagesMap);
       keys.forEach((key) => {
         const ts = this.messagesMap[key].ts;
         if (Date.now() - ts > 60_000) {
           this.removeMessage(key);
         }
       });
    }    

    // getHandler
    async getHandler(message) {
       const msg = this.getMessage(message);
       console.log("Retrying message", msg);
       return msg;
    }
}

exports.makeRetryHandler = makeRetryHandler

// instance.js

const { makeRetryHandler } = require('./store')
const handler = new makeRetryHandler()

socket = makeWASocket({
	...yourConfig,
        getMessage: async (key) => {
           const msg = handler.getHandler(key.id);
           console.log("Retrying message", msg);
           return msg;
        },
});

// Sending message
await socket?.sendMessage(jid, {
            text : "Hello",
       }).then(function (response) {
            handler.addMessage(response)
        })

mnsise avatar Jul 11 '22 10:07 mnsise

I have written this script

// file store.js

const { proto } = require('@adiwajshing/baileys')

class makeRetryHandler {
    messagesMap = { }

    // Add Message
    async addMessage(message) {
       const id = message.key.id ?? "";
       this.messagesMap[id] = {
         message: this.cleanMessage(message),
         ts: Date.now(),
       };
       return message;
    }    

    // Add getMessage
    async getMessage(msgKey) {
       return this.messagesMap[msgKey].message;
    }    

    // removeMessage
    async removeMessage(msgKey) {
       delete this.messagesMap[msgKey];
    }    

    // getMessageKeys
    async getMessageKeys() {
       return Object.keys(this.messagesMap);
    }    

    // cleanMessage
    async cleanMessage(message) {
       const msg = message.message ?? {};
       return msg;
    }    

    // clearObseleteMessages
    async clearObseleteMessages() {
       // Check if the message is older than 60 seconds
       const keys = Object.keys(this.messagesMap);
       keys.forEach((key) => {
         const ts = this.messagesMap[key].ts;
         if (Date.now() - ts > 60_000) {
           this.removeMessage(key);
         }
       });
    }    

    // getHandler
    async getHandler(message) {
       const msg = this.getMessage(message);
       console.log("Retrying message", msg);
       return msg;
    }
}

exports.makeRetryHandler = makeRetryHandler

// instance.js

const { makeRetryHandler } = require('./store')
const handler = new makeRetryHandler()

socket = makeWASocket({
	...yourConfig,
        getMessage: async (key) => {
           const msg = handler.getHandler(key.id);
           console.log("Retrying message", msg);
           return msg;
        },
});

// Sending message
await socket?.sendMessage(jid, {
            text : "Hello",
       }).then(function (response) {
            handler.addMessage(response)
        })

Thanks for helping us with the explanation.

Apologies for my ignorance... Do you mean

  1. We need to create a file named store.js and add the code
  2. We need to add the code mentioned by you to instance.js, which is located in src/api/class directory. If yes, where do we place in the file.

Thanks Sreek

sreekanthmr avatar Jul 11 '22 13:07 sreekanthmr

  1. create file store.js add code src/api/class directory place file
const { proto } = require('@adiwajshing/baileys')

class makeRetryHandler {
    messagesMap = { }

    // Add Message
    async addMessage(message) {
       const id = message.key.id ?? "";
       this.messagesMap[id] = {
         message: this.cleanMessage(message),
         ts: Date.now(),
       };
       return message;
    }    

    // Add getMessage
    async getMessage(msgKey) {
       return this.messagesMap[msgKey];
    }    

    // removeMessage
    async removeMessage(msgKey) {
       delete this.messagesMap[msgKey];
    }    

    // getMessageKeys
    async getMessageKeys() {
       return Object.keys(this.messagesMap);
    }    

    // cleanMessage
    async cleanMessage(message) {
       const msg = message.message ?? {};
       return msg;
    }    

    // clearObseleteMessages
    async clearObseleteMessages() {
       // Check if the message is older than 60 seconds
       const keys = Object.keys(this.messagesMap);
       keys.forEach((key) => {
         const ts = this.messagesMap[key].ts;
         if (Date.now() - ts > 60_000) {
           this.removeMessage(key);
         }
       });
    }    

    // getHandler
    async getHandler(message) {
       const msg = this.getMessage(message);
       console.log("Retrying message", msg);
       return msg;
    }
}

exports.makeRetryHandler = makeRetryHandler

  1. update file instance.js
const { makeRetryHandler } = require('./store')
const handler = new makeRetryHandler()

socket = makeWASocket({
	...yourConfig,
        getMessage: async (key) => {
           const msg = handler.getHandler(key.id);
           console.log("Retrying message", msg);
           return msg;
        },
});

      // Sending message
        const data = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            { 
                text: message 
            }
        ).then(function (response) {
            handler.addMessage(response)
        })

mnsise avatar Jul 11 '22 13:07 mnsise

  1. create file store.js add code src/api/class directory place file
const { proto } = require('@adiwajshing/baileys')

class makeRetryHandler {
    messagesMap = { }

    // Add Message
    async addMessage(message) {
       const id = message.key.id ?? "";
       this.messagesMap[id] = {
         message: this.cleanMessage(message),
         ts: Date.now(),
       };
       return message;
    }    

    // Add getMessage
    async getMessage(msgKey) {
       return this.messagesMap[msgKey];
    }    

    // removeMessage
    async removeMessage(msgKey) {
       delete this.messagesMap[msgKey];
    }    

    // getMessageKeys
    async getMessageKeys() {
       return Object.keys(this.messagesMap);
    }    

    // cleanMessage
    async cleanMessage(message) {
       const msg = message.message ?? {};
       return msg;
    }    

    // clearObseleteMessages
    async clearObseleteMessages() {
       // Check if the message is older than 60 seconds
       const keys = Object.keys(this.messagesMap);
       keys.forEach((key) => {
         const ts = this.messagesMap[key].ts;
         if (Date.now() - ts > 60_000) {
           this.removeMessage(key);
         }
       });
    }    

    // getHandler
    async getHandler(message) {
       const msg = this.getMessage(message);
       console.log("Retrying message", msg);
       return msg;
    }
}

exports.makeRetryHandler = makeRetryHandler
  1. update file instance.js
const { makeRetryHandler } = require('./store')
const handler = new makeRetryHandler()

socket = makeWASocket({
	...yourConfig,
        getMessage: async (key) => {
           const msg = handler.getHandler(key.id);
           console.log("Retrying message", msg);
           return msg;
        },
});

      // Sending message
        const data = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            { 
                text: message 
            }
        ).then(function (response) {
            handler.addMessage(response)
        })

Where exactly do I add the code to instance.js? After adding the code, I get errors in instance.js.

Unexpected identifier at const handler = new makeRetryHandler()

Thanks

sreekanthmr avatar Jul 11 '22 14:07 sreekanthmr

  1. create file store.js add code src/api/class directory place file
const { proto } = require('@adiwajshing/baileys')

class makeRetryHandler {
    messagesMap = { }

    // Add Message
    async addMessage(message) {
       const id = message.key.id ?? "";
       this.messagesMap[id] = {
         message: this.cleanMessage(message),
         ts: Date.now(),
       };
       return message;
    }    

    // Add getMessage
    async getMessage(msgKey) {
       return this.messagesMap[msgKey];
    }    

    // removeMessage
    async removeMessage(msgKey) {
       delete this.messagesMap[msgKey];
    }    

    // getMessageKeys
    async getMessageKeys() {
       return Object.keys(this.messagesMap);
    }    

    // cleanMessage
    async cleanMessage(message) {
       const msg = message.message ?? {};
       return msg;
    }    

    // clearObseleteMessages
    async clearObseleteMessages() {
       // Check if the message is older than 60 seconds
       const keys = Object.keys(this.messagesMap);
       keys.forEach((key) => {
         const ts = this.messagesMap[key].ts;
         if (Date.now() - ts > 60_000) {
           this.removeMessage(key);
         }
       });
    }    

    // getHandler
    async getHandler(message) {
       const msg = this.getMessage(message);
       console.log("Retrying message", msg);
       return msg;
    }
}

exports.makeRetryHandler = makeRetryHandler
  1. update file instance.js
const { makeRetryHandler } = require('./store')
const handler = new makeRetryHandler()

socket = makeWASocket({
	...yourConfig,
        getMessage: async (key) => {
           const msg = handler.getHandler(key.id);
           console.log("Retrying message", msg);
           return msg;
        },
});

      // Sending message
        const data = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            { 
                text: message 
            }
        ).then(function (response) {
            handler.addMessage(response)
        })

Where exactly do I add the code to instance.js? After adding the code, I get errors in instance.js.

Unexpected identifier at const handler = new makeRetryHandler()

Thanks

  1. Created store.js file and added code
  2. Did following changes in instance.js
  3. Added const { makeRetryHandler } = require('./store') and const handler = new makeRetryHandler() lines at line 19 & 20.
  4. Modified the code at line 68 this.instance.sock = makeWASocket(this.socketConfig) with the code mentioned in this thread
  5. Modified SendTextMessage function at line 304 to 310.

Result: Still issue is continuing "Waiting for this message..."

Thank you for your help Sreek

sreekanthmr avatar Jul 12 '22 04:07 sreekanthmr

@salman0ansari Thanks for starting this repo. This has been really helpful for many like me.

@mnsise what is the ideal socketConfig specific for this issue? I have implemented the fixes mentioned by you but I have not seen a change in the behavior so far. No errors but still the message doesn't get delivered to new contacts.

This thread has been alive with so many contributions and thankful for everyone's contribution

Thanks Sreek

sreekanthmr avatar Jul 14 '22 08:07 sreekanthmr

It's fixed in the new version 4.3.0, try upgrading Baileys.

mnsise avatar Jul 21 '22 02:07 mnsise

@mnsise Thanks a mil for this update.

I confirm that this is working.

Should we retain whatever temp fixes that we did earlier? Personally I added store.js class and modifed instance class. Shall I retain that?

Thanks

sreekanthmr avatar Jul 21 '22 04:07 sreekanthmr

Hello @sreekanthmr

How do you only update the baileys lib, without updating the salman api?

Raf1401 avatar Jul 26 '22 21:07 Raf1401

Hello @sreekanthmr

How do you only update the baileys lib, without updating the salman api?

#190

salman0ansari avatar Jul 27 '22 05:07 salman0ansari

I updated using a specific release (4.3.0). yarn add adiwajshing/[email protected]

sreekanthmr avatar Jul 27 '22 07:07 sreekanthmr

@sreekanthmr, thanks!

Raf1401 avatar Jul 27 '22 11:07 Raf1401

I updated the Baileys lib and here the problem continues.

In the tests I did I noticed the following: The first message always gives that whatsapp message. But if you send another one, the other one will appear normally. The way I found then, to use the solution like this, was to trigger two messages.

Another test I did was, add the contact number that I was going to fire on the device. I fired and the target device received the message, even though the target device did not have the sender's number in the phonebook.

I don't know if there is a way to modify this, but it would be nice if someone could solve this detail.

Anyone else with the same problem?

Raf1401 avatar Jul 27 '22 12:07 Raf1401

@sreekanthmr

Can you send the complete code that was the file Instance.js?

Raf1401 avatar Jul 27 '22 13:07 Raf1401

@Raf1401 As mentioned here (https://github.com/salman0ansari/whatsapp-api-nodejs/issues/155#issuecomment-1181301278) I created store.js

Here is my instance.js
const QRCode = require('qrcode')

const pino = require('pino')
const {
    default: makeWASocket,
    DisconnectReason, AnyMessageContent, delay, fetchLatestBaileysVersion, makeInMemoryStore, MessageRetryMap, useSingleFileAuthState
} = require('@adiwajshing/baileys')
const { unlinkSync } = require('fs')
const { v4: uuidv4 } = require('uuid')
const path = require('path')
const processButton = require('../helper/processbtn')
const generateVC = require('../helper/genVc')
const Chat = require('../models/chat.model')
const axios = require('axios')
const config = require('../../config/config')
const downloadMessage = require('../helper/downloadMsg')
const logger = require('pino')()
const useMongoDBAuthState = require('../helper/mongoAuthState')
const { makeRetryHandler } = require('./store')
const handler = new makeRetryHandler()

// external map to store retry counts of messages when decryption/encryption fails
// keep this out of the socket itself, so as to prevent a message decryption/encryption loop across socket restarts 

class WhatsAppInstance {
    async delay(delayInms) {
     return new Promise(resolve => {
       setTimeout(() => {
         resolve(2);
       }, delayInms);
     });
   }
    socketConfig = {
        defaultQueryTimeoutMs: undefined,
	printQRInTerminal: false,
        logger: pino({
            level: config.log.level,
        }),
             getMessage: async (key) => {
                delayres: this.delay(1000);
               const msg = handler.getHandler(key.id);
               return msg;
            },
    }
    key = ''
    authState
    allowWebhook = false
    instance = {
        key: this.key,
        chats: [],
        qr: '',
        messages: [],
        qrRetry: 0,
    }

    axiosInstance = axios.create({
        baseURL: config.webhookUrl,
    })

    constructor(key, allowWebhook, webhook) {
        this.key = key ? key : uuidv4()
        this.instance.customWebhook = this.webhook ? this.webhook : webhook
        this.allowWebhook = config.allowWebhook
            ? config.allowWebhook
            : allowWebhook
        if (this.allowWebhook && this.instance.customWebhook !== null) {
            this.allowWebhook = true
            this.instance.customWebhook = webhook
            this.axiosInstance = axios.create({
                baseURL: webhook,
            })
        }
    }

    async SendWebhook(type, body) {
        if (!this.allowWebhook) return
        this.axiosInstance
            .post('', {
                type,
                body,
		instance: this.instance,
            })
            .catch(() => {})
    }


    
    async init() {
        this.collection = mongoClient.db('whatsapp-api').collection(this.key)
        const { state, saveCreds } = await useMongoDBAuthState(this.collection)
        this.authState = { state: state, saveCreds: saveCreds }
        this.socketConfig.auth = this.authState.state
        this.socketConfig.browser = Object.values(config.browser)
        //console.log("socketConfig: ", this.socketConfig);
        this.instance.sock = makeWASocket(this.socketConfig)
        this.setHandler()
        return this
    }

    setHandler() {
        const sock = this.instance.sock
        // on credentials update save state
        sock?.ev.on('creds.update', this.authState.saveCreds)

        // on socket closed, opened, connecting
        sock?.ev.on('connection.update', async (update) => {
            const { connection, lastDisconnect, qr } = update

            if (connection === 'connecting') return

            if (connection === 'close') {
                // reconnect if not logged out
                if (
                    lastDisconnect?.error?.output?.statusCode !==
                    DisconnectReason.loggedOut
                ) {
                    await this.init()
                } else {
                    await this.collection.drop().then((r) => {
                        logger.info('STATE: Droped collection')
                    })
                    this.instance.online = false
                }
            } else if (connection === 'open') {
                if (config.mongoose.enabled) {
                    let alreadyThere = await Chat.findOne({
                        key: this.key,
                    }).exec()
                    if (!alreadyThere) {
                        const saveChat = new Chat({ key: this.key })
                        await saveChat.save()
                    }
                }
                this.instance.online = true
		        logger.info('STATE: Device connected successfully')
                await this.SendWebhook('Device connected', this.key)
            }

            if (qr) {
                QRCode.toDataURL(qr).then((url) => {
                    this.instance.qr = url
                    this.instance.qrRetry++
                    if (this.instance.qrRetry >= config.instance.maxRetryQr) {
                        // close WebSocket connection
                        this.instance.sock.ws.close()
                        // remove all events
                        this.instance.sock.ev.removeAllListeners()
                        this.instance.qr = ' '
                        logger.info('socket connection terminated')
                    }
                })
            }
        })

        // on receive all chats
        sock?.ev.on('chats.set', async ({ chats }) => {
            const recivedChats = chats.map((chat) => {
                return {
                    ...chat,
                    messages: [],
                }
            })
            this.instance.chats.push(...recivedChats)
            await this.updateDb(this.instance.chats)
        })

        // on recive new chat
        sock?.ev.on('chats.upsert', (newChat) => {
            // console.log(newChat)
            // console.log("Received new chat")
            const chats = newChat.map((chat) => {
                return {
                    ...chat,
                    messages: [],
                }
            })
            this.instance.chats.push(...chats)
        })

        // on chat change
        sock?.ev.on('chats.update', (changedChat) => {
            changedChat.map((chat) => {
                const index = this.instance.chats.findIndex(
                    (pc) => pc.id === chat.id
                )
                const PrevChat = this.instance.chats[index]
                this.instance.chats[index] = {
                    ...PrevChat,
                    ...chat,
                }
            })
        })

        // on chat delete
        sock?.ev.on('chats.delete', (deletedChats) => {
            deletedChats.map((chat) => {
                const index = this.instance.chats.findIndex(
                    (c) => c.id === chat
                )
                this.instance.chats.splice(index, 1)
            })
        })

        // on new mssage
        sock?.ev.on('messages.upsert', (m) => {
            //console.log(m)
            if (m.type === 'prepend')
                this.instance.messages.unshift(...m.messages)
            if (m.type !== 'notify') return

            this.instance.messages.unshift(...m.messages)

            m.messages.map(async (msg) => {
                if (!msg.message) return

                const messageType = Object.keys(msg.message)[0]
                if (
                    [
                        'protocolMessage',
                        'senderKeyDistributionMessage',
                    ].includes(messageType)
                )
                    return

                const webhookData = {
                    key: this.key,
                    ...msg,
                }

                if (messageType === 'conversation') {
                    webhookData['text'] = m
                }
                if (config.webhookBase64) {
                    switch (messageType) {
                        case 'imageMessage':
                            webhookData['msgContent'] = await downloadMessage(
                                msg.message.imageMessage,
                                'image'
                            )
                            break
                        case 'videoMessage':
                            webhookData['msgContent'] = await downloadMessage(
                                msg.message.videoMessage,
                                'video'
                            )
                            break
                        case 'audioMessage':
                            webhookData['msgContent'] = await downloadMessage(
                                msg.message.audioMessage,
                                'audio'
                            )
                            break
                        default:
                            webhookData['msgContent'] = ''
                            break
                    }
                }

                await this.SendWebhook('message', webhookData)
            })
        })

        sock?.ev.on('messages.update', async (messages) => {
          for (const message of messages) {
           let  is_delivered = message?.update?.status === 3;
            let is_seen = message?.update?.status === 4;
	    if (message.key.remoteJid !== "status@broadcast"){
            console.log("Message updated: ", message)
	        await this.SendWebhook('message', message)
	     }
          }
	//await this.SendWebhook('message', messages)
        })

        sock?.ws.on('CB:call', async (data) => {
            if (data.content) {
                if (data.content.find((e) => e.tag === 'offer')) {
                    const content = data.content.find((e) => e.tag === 'offer')

                    await this.SendWebhook('call_offer', {
                        id: content.attrs['call-id'],
                        timestamp: parseInt(data.attrs.t),
                        user: {
                            id: data.attrs.from,
                            platform: data.attrs.platform,
                            platform_version: data.attrs.version,
                        },
                    })
                } else if (data.content.find((e) => e.tag === 'terminate')) {
                    const content = data.content.find(
                        (e) => e.tag === 'terminate'
                    )

                    await this.SendWebhook('call_terminate', {
                        id: content.attrs['call-id'],
                        user: {
                            id: data.attrs.from,
                        },
                        timestamp: parseInt(data.attrs.t),
                        reason: data.content[0].attrs.reason,
                    })
                }
            }
        })

        sock?.ev.on('groups.upsert', async (newChat) => {
            //console.log(newChat)
            this.createGroupByApp(newChat)
        })

        sock?.ev.on('groups.update', async (newChat) => {
            //console.log(newChat)
            this.updateGroupByApp(newChat)
        })

    }

    async getInstanceDetail(key) {
        return {
            instance_key: key,
            phone_connected: this.instance?.online,
            user: this.instance?.online ? this.instance.sock?.user : {},
            webhookUrl: this.instance?.customWebhook,
        }
    }

    getWhatsAppId(id) {
        if (id.includes('@g.us') || id.includes('@s.whatsapp.net')) return id
        return id.includes('-') ? `${id}@g.us` : `${id}@s.whatsapp.net`
    }

    async verifyId(id) {
        if (id.includes('@g.us')) return true
        const [result] = await this.instance.sock?.onWhatsApp(id)
        if (result?.exists) return true
        throw new Error('no account exists')
    }

    async sendTextMessage(to, message) {
        await this.verifyId(this.getWhatsAppId(to))
        const data = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            { text: message }
        ).then(function (response) {
            return handler.addMessage(response)
        })
        return data
    }

    async sendMediaFile(to, file, type, caption = '', filename) {
        await this.verifyId(this.getWhatsAppId(to))
        const data = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            {
                mimetype: file.mimetype,
                [type]: file.buffer,
                caption: caption,
                ptt: type === 'audio' ? true : false,
                fileName: filename ? filename : file.originalname,
            }
        ).then(function (response) {
            return handler.addMessage(response)
        })
        return data
    }

    async sendUrlMediaFile(to, url, type, mimeType, caption = '') {
        await this.verifyId(this.getWhatsAppId(to))

        const data = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            {
                [type]: {
                    url: url,
                },
                caption: caption,
                mimetype: mimeType,
            }
        ).then(function (response) {
            return handler.addMessage(response)
        })
        return data
    }

    async DownloadProfile(of) {
        await this.verifyId(this.getWhatsAppId(of))
        const ppUrl = await this.instance.sock?.profilePictureUrl(
            this.getWhatsAppId(of),
            'image'
        )
        return ppUrl
    }

    async getUserStatus(of) {
        await this.verifyId(this.getWhatsAppId(of))
        const status = await this.instance.sock?.fetchStatus(
            this.getWhatsAppId(of)
        )
        return status
    }

    async blockUnblock(to, data) {
        await this.verifyId(this.getWhatsAppId(to))
        const status = await this.instance.sock?.updateBlockStatus(
            this.getWhatsAppId(to),
            data
        )
        return status
    }

    async sendButtonMessage(to, data) {
        await this.verifyId(this.getWhatsAppId(to))
        const result = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            {
                templateButtons: processButton(data.buttons),
                text: data.text ?? '',
                footer: data.footerText ?? '',
            }
        ).then(function (response) {
            return handler.addMessage(response)
        })
        return result
    }

    async sendContactMessage(to, data) {
        await this.verifyId(this.getWhatsAppId(to))
        const vcard = generateVC(data)
        const result = await this.instance.sock?.sendMessage(
            await this.getWhatsAppId(to),
            {
                contacts: {
                    displayName: data.fullName,
                    contacts: [{ displayName: data.fullName, vcard }],
                },
            }
        ).then(function (response) {
            return handler.addMessage(response)
        })
        return result
    }

    async sendListMessage(to, data) {
        await this.verifyId(this.getWhatsAppId(to))
        const result = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            {
                text: data.text,
                sections: data.sections,
                buttonText: data.buttonText,
                footer: data.description,
                title: data.title,
            }
        ).then(function (response) {
            return handler.addMessage(response)
        })
        return result
    }

    async sendMediaButtonMessage(to, data) {
        await this.verifyId(this.getWhatsAppId(to))

        const result = await this.instance.sock?.sendMessage(
            this.getWhatsAppId(to),
            {
                [data.mediaType]: {
                    url: data.image,
                },
                footer: data.footerText ?? '',
                caption: data.text,
                templateButtons: processButton(data.buttons),
                mimetype: data.mimeType,
            }
        ).then(function (response) {
            return handler.addMessage(response)
        })
        return result
    }

    async setStatus(status, to) {
        await this.verifyId(this.getWhatsAppId(to))

        const result = await this.instance.sock?.sendPresenceUpdate(status, to)
        return result
    }

    // Group Methods
    parseParticipants(users) {
        return users.map((users) => this.getWhatsAppId(users))
    }

    async createNewGroup(name, users) {
        const group = await this.instance.sock?.groupCreate(
            name,
            users.map(this.getWhatsAppId)
        )
        return group
    }

    async addNewParticipant(id, users) {
        try {
            const res = await this.instance.sock?.groupAdd(
                this.getWhatsAppId(id),
                this.parseParticipants(users)
            )
            return res
        } catch {
            return {
                error: true,
                message:
                    'Unable to add participant, you must be an admin in this group',
            }
        }
    }

    async makeAdmin(id, users) {
        try {
            const res = await this.instance.sock?.groupMakeAdmin(
                this.getWhatsAppId(id),
                this.parseParticipants(users)
            )
            return res
        } catch {
            return {
                error: true,
                message:
                    'unable to promote some participants, check if you are admin in group or participants exists',
            }
        }
    }

    async demoteAdmin(id, users) {
        try {
            const res = await this.instance.sock?.groupDemoteAdmin(
                this.getWhatsAppId(id),
                this.parseParticipants(users)
            )
            return res
        } catch {
            return {
                error: true,
                message:
                    'unable to demote some participants, check if you are admin in group or participants exists',
            }
        }
    }

    async getAllGroups() {
        let Chats = await this.getChat()
        return Chats.filter((c) => c.id.includes('@g.us')).map((data, i) => {
            return {
                index: i,
                name: data.name,
                jid: data.id,
                participant: data.participant,
            }
        })
    }

    async leaveGroup(id) {
        let Chats = await this.getChat()
        const group = Chats.find((c) => c.id === id)
        if (!group) throw new Error('no group exists')
        return await this.instance.sock?.groupLeave(id)
    }

    async getInviteCodeGroup(id) {
        let Chats = await this.getChat()
        const group = Chats.find((c) => c.id === id)
        if (!group)
            throw new Error(
                'unable to get invite code, check if the group exists'
            )
        return await this.instance.sock?.groupInviteCode(id)
    }

    // get Chat object from db
    async getChat(key = this.key) {
        let dbResult = await Chat.findOne({ key: key }).exec()
        let ChatObj = dbResult.chat
        return ChatObj
    }

    // create new group by application
    async createGroupByApp(newChat) {
        let Chats = await this.getChat()
        let group = {
            id: newChat[0].id,
            name: newChat[0].subject,
            participant: newChat[0].participants,
            messages: [],
        }
        Chats.push(group)
        try {
            await this.updateDb(Chats)
        } catch (e) {
            logger.error('Error updating document failed')
        }
    }

    async updateGroupByApp(newChat) {
        let Chats = await this.getChat()
        Chats.find((c) => c.id === newChat[0].id).name = newChat[0].subject
        try {
            await this.updateDb(Chats)
        } catch (e) {
            logger.error('Error updating document failed')
        }
    }

    async groupFetchAllParticipating() {
        const result = await this.instance.sock?.groupFetchAllParticipating()
        return result
    }

    // update db document -> chat
    async updateDb(object) {
        try {
            await Chat.updateOne({ key: this.key }, { chat: object })
        } catch (e) {
            logger.error('Error updating document failed')
        }
    }

    async readMessage(msg){
        if(!msg.key.fromMe && doReplies) {
            console.log('replying to', msg.key.remoteJid)
            await sock.sendReadReceipt(msg.key.remoteJid, msg.key.participant, [msg.key.id])
            await sendMessageWTyping({ text: 'Hello there!' }, msg.key.remoteJid)
        }
    }
}

exports.WhatsAppInstance = WhatsAppInstance

I updated baileys lib using a specific release (4.3.0). yarn add adiwajshing/[email protected]

sreekanthmr avatar Jul 27 '22 15:07 sreekanthmr

@sreekanthmr

I would like to take a doubt with you about the API application with docker compose.

Would it be possible for me to create a container in docker for several applications at the same time along with VPN in each of them?

I question, because in the docker configuration I don't understand anything.

And by the way. Thanks for the code above.

Raf1401 avatar Jul 28 '22 19:07 Raf1401

yeah! Great!

Actually the solution to update the lib to 4.3 that the colleague @sreekanthmr talked about just above, worked too. The detail is that I had to read the QR Code again and I was trying it in the same previous session.

Problem solved.

Raf1401 avatar Jul 29 '22 12:07 Raf1401

is anyone still facing this issue?

salman0ansari avatar Aug 20 '22 18:08 salman0ansari

I updated the code and this problem happened to me again

Zarinia avatar Sep 05 '22 12:09 Zarinia

This issue is stale because it has been open 6 days with no activity. Remove the stale label or comment or this will be closed in 2 days

salman0ansari avatar Dec 27 '22 02:12 salman0ansari

Here still not working, what can i do to solve this? someone know?

lusqua avatar Jun 21 '23 00:06 lusqua