diff --git a/src/LegacySocket/messages.ts b/src/LegacySocket/messages.ts index f9b8a8d..2316ddd 100644 --- a/src/LegacySocket/messages.ts +++ b/src/LegacySocket/messages.ts @@ -1,7 +1,7 @@ import { Boom } from '@hapi/boom' import { proto } from '../../WAProto' import { WA_DEFAULT_EPHEMERAL } from '../Defaults' -import { AnyMessageContent, Chat, GroupMetadata, LegacySocketConfig, MediaConnInfo, MessageInfo, MessageInfoUpdate, MessageUpdateType, MiscMessageGenerationOptions, ParticipantAction, WAFlag, WAMessage, WAMessageCursor, WAMessageKey, WAMessageStatus, WAMessageStubType, WAMessageUpdate, WAMetric, WAUrlInfo } from '../Types' +import { AnyMessageContent, Chat, GroupMetadata, LegacySocketConfig, MediaConnInfo, MessageUpdateType, MessageUserReceipt, MessageUserReceiptUpdate, MiscMessageGenerationOptions, ParticipantAction, WAFlag, WAMessage, WAMessageCursor, WAMessageKey, WAMessageStatus, WAMessageStubType, WAMessageUpdate, WAMetric, WAUrlInfo } from '../Types' import { decryptMediaMessageBuffer, extractMessageContent, generateWAMessage, getWAUploadToServer, toNumber } from '../Utils' import { areJidsSameUser, BinaryNode, getBinaryNodeMessages, isJidGroup, jidNormalizedUser } from '../WABinary' import makeChatsSocket from './chats' @@ -353,13 +353,16 @@ const makeMessagesSocket = (config: LegacySocketConfig) => { ids = [ids] } - let updateKey: keyof MessageInfoUpdate['update'] + let updateKey: keyof MessageUserReceipt switch (attributes.ack.toString()) { case '2': - updateKey = 'deliveries' + updateKey = 'receiptTimestamp' break case '3': - updateKey = 'reads' + updateKey = 'readTimestamp' + break + case '4': + updateKey = 'playedTimestamp' break default: logger.warn({ attributes }, 'received unknown message info update') @@ -370,13 +373,17 @@ const makeMessagesSocket = (config: LegacySocketConfig) => { remoteJid: jidNormalizedUser(attributes.to), fromMe: areJidsSameUser(attributes.from, state.legacy?.user?.id || ''), } - const updates = ids.map(id => ({ + + const userJid = jidNormalizedUser(attributes.participant || attributes.to) + + const updates = ids.map(id => ({ key: { ...keyPartial, id }, - update: { - [updateKey]: { [jidNormalizedUser(attributes.participant || attributes.to)]: new Date(+attributes.t) } + receipt: { + userJid, + [updateKey]: +attributes.t } })) - ev.emit('message-info.update', updates) + ev.emit('message-receipt.update', updates) // for individual messages // it means the message is marked read/delivered if(!isJidGroup(keyPartial.remoteJid)) { @@ -384,7 +391,7 @@ const makeMessagesSocket = (config: LegacySocketConfig) => { { key: { ...keyPartial, id }, update: { - status: updateKey === 'deliveries' ? WAMessageStatus.DELIVERY_ACK : WAMessageStatus.READ + status: updateKey === 'receiptTimestamp' ? WAMessageStatus.DELIVERY_ACK : WAMessageStatus.READ } } ))) @@ -416,24 +423,28 @@ const makeMessagesSocket = (config: LegacySocketConfig) => { expect200: true, requiresPhoneConnection: true }) - const info: MessageInfo = { reads: {}, deliveries: {} } + const info: { [jid: string]: MessageUserReceipt } = { } if(Array.isArray(content)) { for(const { tag, content: innerData } of content) { const [{ attrs }] = (innerData as BinaryNode[]) + const jid = jidNormalizedUser(attrs.jid) - const date = new Date(+attrs.t * 1000) + const recp = info[jid] || { userJid: jid } + const date = +attrs.t switch (tag) { case 'read': - info.reads[jid] = date + recp.readTimestamp = date break case 'delivery': - info.deliveries[jid] = date + recp.receiptTimestamp = date break } + + info[jid] = recp } } - return info + return Object.values(info) }, downloadMediaMessage: async(message: WAMessage, type: 'buffer' | 'stream' = 'buffer') => { const downloadMediaMessage = async() => { diff --git a/src/Store/make-in-memory-store.ts b/src/Store/make-in-memory-store.ts index ef41f87..90a766d 100644 --- a/src/Store/make-in-memory-store.ts +++ b/src/Store/make-in-memory-store.ts @@ -5,7 +5,7 @@ import { proto } from '../../WAProto' import { DEFAULT_CONNECTION_CONFIG } from '../Defaults' import type makeLegacySocket from '../LegacySocket' import type makeMDSocket from '../Socket' -import type { BaileysEventEmitter, Chat, ConnectionState, Contact, GroupMetadata, MessageInfo, PresenceData, WAMessage, WAMessageCursor, WAMessageKey } from '../Types' +import type { BaileysEventEmitter, Chat, ConnectionState, Contact, GroupMetadata, PresenceData, WAMessage, WAMessageCursor, WAMessageKey } from '../Types' import { toNumber } from '../Utils' import { jidNormalizedUser } from '../WABinary' import makeOrderedDictionary from './make-ordered-dictionary' @@ -38,7 +38,6 @@ export default ( const messages: { [_: string]: ReturnType } = { } const contacts: { [_: string]: Contact } = { } const groupMetadata: { [_: string]: GroupMetadata } = { } - const messageInfos: { [id: string]: MessageInfo } = { } const presences: { [id: string]: { [participant: string]: PresenceData } } = { } const state: ConnectionState = { connection: 'close' } @@ -159,9 +158,6 @@ export default ( } ]) } - - // add message infos if required - messageInfos[msg.key.id!] = messageInfos[msg.key.id!] || { reads: {}, deliveries: {} } } } @@ -224,13 +220,17 @@ export default ( } }) - ev.on('message-info.update', updates => { - for(const { key, update } of updates) { - const obj = messageInfos[key.id!] - if(obj) { - // add reads/deliveries - for(const key in update) { - Object.assign(obj[key], update[key]) + ev.on('message-receipt.update', updates => { + for(const { key, receipt } of updates) { + const obj = messages[key.remoteJid!] + const msg = obj?.get(key.id) + if(msg) { + msg.userReceipt = msg.userReceipt || [] + const recp = msg.userReceipt.find(m => m.userJid === receipt.userJid) + if(recp) { + Object.assign(recp, receipt) + } else { + msg.userReceipt.push(receipt) } } } @@ -260,7 +260,6 @@ export default ( contacts, messages, groupMetadata, - messageInfos, state, presences, bind, @@ -348,12 +347,18 @@ export default ( return groupMetadata[jid] }, - fetchMessageInfo: async({ remoteJid, id }: WAMessageKey, sock: LegacyWASocket | undefined) => { - if(!messageInfos[id!]) { - messageInfos[id!] = await sock?.messageInfo(remoteJid, id) + fetchMessageReceipts: async({ remoteJid, id }: WAMessageKey, sock: LegacyWASocket | undefined) => { + const list = messages[remoteJid] + const msg = list?.get(id) + let receipts = msg.userReceipt + if(!receipts) { + receipts = await sock?.messageInfo(remoteJid, id) + if(msg) { + msg.userReceipt = receipts + } } - return messageInfos[id!] + return receipts }, toJSON, fromJSON, diff --git a/src/Types/Events.ts b/src/Types/Events.ts index 039416c..889040d 100644 --- a/src/Types/Events.ts +++ b/src/Types/Events.ts @@ -3,7 +3,7 @@ import { AuthenticationCreds } from './Auth' import { Chat, PresenceData } from './Chat' import { Contact } from './Contact' import { GroupMetadata, ParticipantAction } from './GroupMetadata' -import { MessageInfoUpdate, MessageUpdateType, WAMessage, WAMessageKey, WAMessageUpdate } from './Message' +import { MessageUpdateType, MessageUserReceiptUpdate, WAMessage, WAMessageKey, WAMessageUpdate } from './Message' import { ConnectionState } from './State' export type BaileysEventMap = { @@ -37,7 +37,7 @@ export type BaileysEventMap = { * */ 'messages.upsert': { messages: WAMessage[], type: MessageUpdateType } - 'message-info.update': MessageInfoUpdate[] + 'message-receipt.update': MessageUserReceiptUpdate[] 'groups.upsert': GroupMetadata[] 'groups.update': Partial[] diff --git a/src/Types/Message.ts b/src/Types/Message.ts index 4ee130b..5cbf760 100644 --- a/src/Types/Message.ts +++ b/src/Types/Message.ts @@ -166,14 +166,10 @@ export type MessageGenerationOptions = MessageContentGenerationOptions & Message export type MessageUpdateType = 'append' | 'notify' | 'replace' -export type MessageInfoEventMap = { [jid: string]: Date } -export interface MessageInfo { - reads: MessageInfoEventMap - deliveries: MessageInfoEventMap -} +export type MessageUserReceipt = proto.IUserReceipt export type WAMessageUpdate = { update: Partial, key: proto.IMessageKey } export type WAMessageCursor = { before: WAMessageKey | undefined } | { after: WAMessageKey | undefined } -export type MessageInfoUpdate = { key: proto.IMessageKey, update: Partial } +export type MessageUserReceiptUpdate = { key: proto.IMessageKey, receipt: MessageUserReceipt }