Files
Baileys/src/Utils/history.ts
Adhiraj Singh d0330d1863 refactor!: cleaner message history sync
This is a breaking change,
1. three events (chats.set, contacts.set, messages.set) are now just one `messaging-history.set` event
2. no need to debounce for app state sync
3. added a new "conditional" chat update to allow for correct app state sync despite not having the chat available on hand
2022-09-29 16:32:57 +05:30

111 lines
3.0 KiB
TypeScript

import { AxiosRequestConfig } from 'axios'
import { promisify } from 'util'
import { inflate } from 'zlib'
import { proto } from '../../WAProto'
import { Chat, Contact, WAMessageStubType } from '../Types'
import { isJidUser } from '../WABinary'
import { toNumber } from './generics'
import { normalizeMessageContent } from './messages'
import { downloadContentFromMessage } from './messages-media'
const inflatePromise = promisify(inflate)
export const downloadHistory = async(
msg: proto.Message.IHistorySyncNotification,
options: AxiosRequestConfig<any>
) => {
const stream = await downloadContentFromMessage(msg, 'md-msg-hist', { options })
const bufferArray: Buffer[] = []
for await (const chunk of stream) {
bufferArray.push(chunk)
}
let buffer = Buffer.concat(bufferArray)
// decompress buffer
buffer = await inflatePromise(buffer)
const syncData = proto.HistorySync.decode(buffer)
return syncData
}
export const processHistoryMessage = (item: proto.IHistorySync) => {
const messages: proto.IWebMessageInfo[] = []
const contacts: Contact[] = []
const chats: Chat[] = []
switch (item.syncType) {
case proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP:
case proto.HistorySync.HistorySyncType.RECENT:
case proto.HistorySync.HistorySyncType.FULL:
for(const chat of item.conversations! as Chat[]) {
contacts.push({ id: chat.id, name: chat.name || undefined })
const msgs = chat.messages || []
delete chat.messages
delete chat.archived
delete chat.muteEndTime
delete chat.pinned
for(const item of msgs) {
const message = item.message!
messages.push(message)
if(!chat.messages) {
// keep only the most recent message in the chat array
chat.messages = [{ message }]
}
if(!message.key.fromMe && !chat.lastMessageRecvTimestamp) {
chat.lastMessageRecvTimestamp = toNumber(message.messageTimestamp)
}
if(
!message.key.fromMe
&& message.messageStubType === WAMessageStubType.BIZ_PRIVACY_MODE_TO_BSP
&& message.messageStubParameters?.[0]
) {
contacts.push({
id: message.key.participant || message.key.remoteJid!,
verifiedName: message.messageStubParameters?.[0],
})
}
}
if(isJidUser(chat.id) && chat.readOnly && chat.archived) {
delete chat.readOnly
}
chats.push({ ...chat })
}
break
case proto.HistorySync.HistorySyncType.PUSH_NAME:
for(const c of item.pushnames!) {
contacts.push({ notify: c.pushname!, id: c.id! })
}
break
}
return {
chats,
contacts,
messages,
}
}
export const downloadAndProcessHistorySyncNotification = async(
msg: proto.Message.IHistorySyncNotification,
options: AxiosRequestConfig<any>
) => {
const historyMsg = await downloadHistory(msg, options)
return processHistoryMessage(historyMsg)
}
export const getHistoryMsg = (message: proto.IMessage) => {
const normalizedContent = !!message ? normalizeMessageContent(message) : undefined
const anyHistoryMsg = normalizedContent?.protocolMessage?.historySyncNotification
return anyHistoryMsg
}