Izlia
Izlia

Reputation: 352

Nodejs: How to send multiple messages with whatsapp api cloud?

I have a problem, when I send multiple messages to whatsapp through the api webhook it falls in a loop even though I am validating returning a 200 status for each message sent

I have a cycle to send the messages one by one that I store in an array of objects where each type of message that is sent to whatsapp goes. I even have a delay of 2 seconds for each message that is sent, but it falls into a loop, for each response that I send, it keeps responding without rest until I restart the server

I don't know what else to try, I even have a filter to try to avoid messages that have been received for a certain time to avoid repetitions in receiving them, but nothing. Even create a DB in Supabase to call the message that has already been sent and verify how much it does to avoid repeating the message

I ask for your help because I don't know what else to try now, I appreciate any kind of help in advance, please help

async function sendMessagesToWhatsApp(messages: any[]): Promise<void> {
    for (const msg of messages) {
        try {
            await SendMessageWhatsApp(msg);
            await delay(2000); // Wait 2 seconds between messages
        } catch (error) {
            await registerEvents(msg, 500, "Server Error Internal", String(error));
        }
    }
}

export const receiveMessage = async (req: Request, res: Response, next: NextFunction) => {

    let entry = req.body.entry[0];
    let changes = entry.changes[0];
    let value = changes.value;

    try {

        // First we record the log
        await registerEvents(req.body, 200, "Get Webhook Whatsapp Api Cloud", null);

        const messageReceived = req.body;

        if (!messageReceived) {
            // No message received but a status 200 is returned to avoid errors
            console.log('evaluating when nothing is received in the body');
            res.sendStatus(200)
        }


        let messageObject = value?.messages ?? undefined;
        const changesResult = messageReceived.entry[0].changes[0].value;

        if (changesResult?.statuses !== undefined) {

            const messageStatus = messageReceived.entry[0].changes[0].value.statuses[0].status;

            if (messageStatus === "sent") {
                res.sendStatus(200);
            }

            if (messageStatus === "delivered") {
                res.sendStatus(200);
            }

            if (messageStatus === "read") {
                res.sendStatus(200);
            }

            if (messageStatus === "failed") {
                await registerEvents(messageReceived, 500, "Webhook Events", "Message Failed");
                res.sendStatus(200);
            }

        } else {

            if (messageObject !== undefined) {

                messageObject = messageObject.filter((message) => message.timestamp > (Date.now() - 1000 * 60 * 60 * 0.2) / 1000);

                if (messageObject.length > 0) {
                    const messages: Message = messageObject[0];
                    const from = messageObject[0]?.from;

                    // Type message
                    let typeMessage = messages?.type;

                    // validate the type of messaging
                    if (typeMessage === "text") {
                        sendStatusMessage("Typing...", from);
                        const messagesToSend = await textProcess(messages, from);
                        if (Array.isArray(messagesToSend)) {
                            sendMessagesToWhatsApp(messagesToSend)
                                .then(() => {
                                    console.log("Messages sent successfully.");
                                    res.sendStatus(200);
                                })
                                .catch(error => {
                                    console.error("Error sending messages:", error);
                                    res.sendStatus(200);
                                });
                        } else {
                            SendMessageWhatsApp(messagesToSend);
                            res.sendStatus(200);
                        }
                    }

                    if (typeMessage === "audio") {
                        console.log('is audio');
                        const data = await audioProcess(messages, from);
                        SendMessageWhatsApp(data);
                        res.sendStatus(200);
                    }

                    if (typeMessage === "button") {
                        const data = await buttonProcess(messages, from);
                        SendMessageWhatsApp(data);
                        res.sendStatus(200);
                    }

                    if (typeMessage === "interactive") {
                        const data = await interactiveProcess(messages, from);
                        SendMessageWhatsApp(data);
                        res.sendStatus(200);
                    }
                } else {
                    // when resubmitted they still contain the timestamp from when they were initially sent
                    console.log('The message was filtered by the sending time');
                    res.sendStatus(200);
                }

            } else {
                res.sendStatus(200);
            }
        }


    } catch (error) {

        console.log(error);

        await registerEvents(req.body, 500, "Error Webhook Whatsapp Api Cloud", error)
        // Evitar lopp webhook
        console.log('An internal server error occurred but 200 should always be sent');
        res.sendStatus(200);
    }

}

async function textProcess(messages: Message, from: string) {

    let message = messages.text.body;
    const answer = await askOpenAI(message);

    const answertoLowerCase = answer.toLocaleLowerCase();

    if (answertoLowerCase.includes("app")) {

        const ifAnswerIsMarkdown = isMarkdownFormat(answer);

        if (ifAnswerIsMarkdown) {
            const formattedContent = parseMarkdown(answer);
            const messages_ = buildDataToWhatsapp(formattedContent, from);

            console.log('lenght msj', messages_.length);

            // for await (const msg of messages_) {
            //     SendMessageWhatsApp(msg);
            //     await delay(2000); // Espera un tiempo entre cada mensaje
            // }
            return messages_

        } else {
            console.log('no need to format the text because it is not markdown');
            const dataToSend = {
                "messaging_product": "whatsapp",
                "recipient_type": "individual",
                "to": from,
                "type": "text",
                "text": {
                    "preview_url": false,
                    "body": answer
                }
            }
            // SendMessageWhatsApp(dataToSend);
            return dataToSend
        }
    } else {
        const dataToSend = {
            "messaging_product": "whatsapp",
            "recipient_type": "individual",
            "to": from,
            "type": "text",
            "text": {
                "preview_url": false,
                "body": answer
            }
        }
        return dataToSend
    }
}

function SendMessageWhatsApp(message: any) {
    const data = JSON.stringify(message);

    const options = {
        host: "graph.facebook.com",
        path: `/v16.0/${ID_CELL}/messages`,
        method: "POST",
        body: data,
        headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TOKEN_CLOUD_API_WSP}`
        }
    };
    const req = https.request(options, res => {
        res.on("data", d => {
            process.stdout.write(d);
        });
    });

    req.on("error", error => {
        console.error(error);
        supabase.from('logs').insert([
            {
                message: error,
                status: 500,
                task: "Internal server",
                error: null
            }
        ]);
    });

    req.write(data);
    req.end();
    registerEvents(data, 200, "SendMessageWhatsApp", Date.now());
}

Upvotes: 0

Views: 1501

Answers (1)

Hafiz
Hafiz

Reputation: 256

Hm.. There are multiple places in your code where res.sendStatus(200) is being executed. Once you've sent a response, any further attempts to send another response in the same cycle will result in an error. If you're not seeing these errors, it's likely you're not entering multiple branches, but it's something to be aware of. Ensure that when you send a message via SendMessageWhatsApp, it doesn't cause another call to receiveMessage.

UPD consider implementing idempotent processing by associating a unique identifier with each message. Store this ID in your database after processing the message and before sending any response back. For every incoming message, check if this ID already exists in your database. If it does, do not process the message and just send back a 200 status.

Upvotes: 1

Related Questions