From 5aa64f2c3967a89d22ae41c9db0c654e9a394da7 Mon Sep 17 00:00:00 2001 From: Adhiraj Singh Date: Wed, 6 Apr 2022 09:30:32 +0530 Subject: [PATCH] feat: add readMessages function --- README.md | 19 +++++++++++-------- src/Socket/messages-send.ts | 13 +++++++++++-- src/Utils/messages.ts | 22 ++++++++++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e1907c6..28fffaa 100644 --- a/README.md +++ b/README.md @@ -521,16 +521,19 @@ await sock.sendMessage('1234@s.whatsapp.net', { forward: msg }) // WA forward th ## Reading Messages -A set of message IDs must be explicitly marked read now. -Cannot mark an entire "chat" read as it were with Baileys Web. +A set of message keys must be explicitly marked read now. +In multi-device, you cannot mark an entire "chat" read as it were with Baileys Web. This does mean you have to keep track of unread messages. -``` ts -const id = '1234-123@g.us' -const messageID = 'AHASHH123123AHGA' // id of the message you want to read -const participant = '912121232@s.whatsapp.net' // the ID of the user that sent the message (undefined for individual chats) - -await sock.sendReadReceipt(id, participant, [messageID]) +``` ts +const key = { + remoteJid: '1234-123@g.us', + id: 'AHASHH123123AHGA', // id of the message you want to read + participant: '912121232@s.whatsapp.net' // the ID of the user that sent the message (undefined for individual chats) +} +// pass to readMessages function +// can pass multiple keys to read multiple messages as well +await sock.readMessages([key]) ``` The message ID is the unique identifier of the message that you are marking as read. On a `WAMessage`, the `messageID` can be accessed using ```messageID = message.key.id```. diff --git a/src/Socket/messages-send.ts b/src/Socket/messages-send.ts index 77dd074..d1c8b1b 100644 --- a/src/Socket/messages-send.ts +++ b/src/Socket/messages-send.ts @@ -2,8 +2,8 @@ import NodeCache from 'node-cache' import { proto } from '../../WAProto' import { WA_DEFAULT_EPHEMERAL } from '../Defaults' -import { AnyMessageContent, MediaConnInfo, MessageReceiptType, MessageRelayOptions, MiscMessageGenerationOptions, SocketConfig } from '../Types' -import { encodeWAMessage, encryptSenderKeyMsgSignalProto, encryptSignalProto, extractDeviceJids, generateMessageID, generateWAMessage, getWAUploadToServer, jidToSignalProtocolAddress, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils' +import { AnyMessageContent, MediaConnInfo, MessageReceiptType, MessageRelayOptions, MiscMessageGenerationOptions, SocketConfig, WAMessageKey } from '../Types' +import { aggregateMessageKeysNotFromMe, encodeWAMessage, encryptSenderKeyMsgSignalProto, encryptSignalProto, extractDeviceJids, generateMessageID, generateWAMessage, getWAUploadToServer, jidToSignalProtocolAddress, parseAndInjectE2ESessions, unixTimestampSeconds } from '../Utils' import { BinaryNode, BinaryNodeAttributes, getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, isJidUser, jidDecode, jidEncode, jidNormalizedUser, JidWithDevice, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary' import { makeGroupsSocket } from './groups' @@ -131,6 +131,14 @@ export const makeMessagesSocket = (config: SocketConfig) => { return sendReceipt(jid, participant, messageIds, readType) } + /** Bulk read messages. Keys can be from different chats & participants */ + const readMessages = async(keys: WAMessageKey[]) => { + const recps = aggregateMessageKeysNotFromMe(keys) + for(const { jid, participant, messageIds } of recps) { + await sendReadReceipt(jid, participant, messageIds) + } + } + const getUSyncDevices = async(jids: string[], ignoreZeroDevices: boolean) => { const deviceResults: JidWithDevice[] = [] @@ -447,6 +455,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { relayMessage, sendReceipt, sendReadReceipt, + readMessages, refreshMediaConn, waUploadToServer, fetchPrivacySettings, diff --git a/src/Utils/messages.ts b/src/Utils/messages.ts index 65e8480..772ee75 100644 --- a/src/Utils/messages.ts +++ b/src/Utils/messages.ts @@ -526,6 +526,7 @@ export const getDevice = (id: string) => { return deviceType } +/** Upserts a receipt in the message */ export const updateMessageWithReceipt = (msg: WAMessage, receipt: MessageUserReceipt) => { msg.userReceipt = msg.userReceipt || [] const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid) @@ -536,6 +537,27 @@ export const updateMessageWithReceipt = (msg: WAMessage, receipt: MessageUserRec } } +/** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */ +export const aggregateMessageKeysNotFromMe = (keys: proto.IMessageKey[]) => { + const keyMap: { [id: string]: { jid: string, participant: string | undefined, messageIds: string[] } } = { } + for(const { remoteJid, id, participant, fromMe } of keys) { + if(!fromMe) { + const uqKey = `${remoteJid}:${participant || ''}` + if(!keyMap[uqKey]) { + keyMap[uqKey] = { + jid: remoteJid, + participant, + messageIds: [] + } + } + + keyMap[uqKey].messageIds.push(id) + } + } + + return Object.values(keyMap) +} + /** * Downloads the given message. Throws an error if it's not a media message */