PDO protocol (peer data operation): Get more history sync + better message retry mechanism (#919)

* feat(feature/pdo-sync): initial commit

* feat(feature/pdo-sync): Moved to conventional send functions, exported, patched some errors

* fix(feature/pdo-sync): Linting and more bugsquatting

* chore(feature/pdo-sync): linting done

* feat/fix(feat/pdo-sync): Newsletter decrypt + ack

* merge (#946)

* fix: profilePictureUrl (#901)

* Update module to latest version  (#926)

* Update package.json

Update the module to the latest

* Add files via upload

* Fix: Readme use upsert events (#908)

* Fix: getUSyncDevices (#862)

* Update messages-send.ts

* Update messages-send.ts

* Update messages-send.ts

* Fix lint

* Fix lint

* fix(master): update linting workflow to node 20 (current LTS)

---------

Co-authored-by: Akhlaqul Muhammad Fadwa <75623219+zennn08@users.noreply.github.com>
Co-authored-by: Rizz2Dev <muhamad.rizki27483@smp.belajar.id>
Co-authored-by: Oscar Guindzberg <oscar.guindzberg@gmail.com>
Co-authored-by: Bob <115008575+bobslavtriev@users.noreply.github.com>

* chore(feature/pdo-sync): final linting

* fix(feature/pdo-sync): make replies optional

* feat(feat/pdo-sync): add <unavailable> handle

* feat(feature/pdo-sync): Fixed the issues with peer messages and implemented some more logic

* fix(feature/pdo-sync): Make progress optional

* fix(feature/pdo-sync): Nullify and defeat Message absent from node if it is resolved immediately

* feat(feature/pdo-sync): Export message absent from node and export PDO request ID with it

---------

Co-authored-by: Akhlaqul Muhammad Fadwa <75623219+zennn08@users.noreply.github.com>
Co-authored-by: Rizz2Dev <muhamad.rizki27483@smp.belajar.id>
Co-authored-by: Oscar Guindzberg <oscar.guindzberg@gmail.com>
Co-authored-by: Bob <115008575+bobslavtriev@users.noreply.github.com>
This commit is contained in:
Rajeh Taher
2024-08-14 12:07:27 +03:00
committed by GitHub
parent 35f6d75cf8
commit 1f9cfb1cba
12 changed files with 316 additions and 60 deletions

View File

@@ -1,7 +1,7 @@
import { AxiosRequestConfig } from 'axios'
import type { Logger } from 'pino'
import { proto } from '../../WAProto'
import { AuthenticationCreds, BaileysEventEmitter, Chat, GroupMetadata, ParticipantAction, RequestJoinAction, RequestJoinMethod, SignalKeyStoreWithTransaction, SocketConfig, WAMessageStubType } from '../Types'
import { AuthenticationCreds, BaileysEventEmitter, CacheStore, Chat, GroupMetadata, ParticipantAction, RequestJoinAction, RequestJoinMethod, SignalKeyStoreWithTransaction, SocketConfig, WAMessageStubType } from '../Types'
import { getContentType, normalizeMessageContent } from '../Utils/messages'
import { areJidsSameUser, isJidBroadcast, isJidStatusBroadcast, jidNormalizedUser } from '../WABinary'
import { aesDecryptGCM, hmacSign } from './crypto'
@@ -10,6 +10,7 @@ import { downloadAndProcessHistorySyncNotification } from './history'
type ProcessMessageContext = {
shouldProcessHistoryMsg: boolean
placeholderResendCache?: CacheStore
creds: AuthenticationCreds
keyStore: SignalKeyStoreWithTransaction
ev: BaileysEventEmitter
@@ -33,7 +34,7 @@ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([
export const cleanMessage = (message: proto.IWebMessageInfo, meId: string) => {
// ensure remoteJid and participant doesn't have device or agent in it
message.key.remoteJid = jidNormalizedUser(message.key.remoteJid!)
message.key.participant = message.key.participant ? jidNormalizedUser(message.key.participant!) : undefined
message.key.participant = message.key.participant ? jidNormalizedUser(message.key.participant) : undefined
const content = normalizeMessageContent(message.message)
// if the message has a reaction, ensure fromMe & remoteJid are from our perspective
if(content?.reactionMessage) {
@@ -152,6 +153,7 @@ const processMessage = async(
message: proto.IWebMessageInfo,
{
shouldProcessHistoryMsg,
placeholderResendCache,
ev,
creds,
keyStore,
@@ -190,7 +192,7 @@ const processMessage = async(
if(protocolMsg) {
switch (protocolMsg.type) {
case proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION:
const histNotification = protocolMsg!.historySyncNotification!
const histNotification = protocolMsg.historySyncNotification!
const process = shouldProcessHistoryMsg
const isLatest = !creds.processedHistoryMessages?.length
@@ -202,19 +204,27 @@ const processMessage = async(
}, 'got history notification')
if(process) {
ev.emit('creds.update', {
processedHistoryMessages: [
...(creds.processedHistoryMessages || []),
{ key: message.key, messageTimestamp: message.messageTimestamp }
]
})
if(histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND) {
ev.emit('creds.update', {
processedHistoryMessages: [
...(creds.processedHistoryMessages || []),
{ key: message.key, messageTimestamp: message.messageTimestamp }
]
})
}
const data = await downloadAndProcessHistorySyncNotification(
histNotification,
options
)
ev.emit('messaging-history.set', { ...data, isLatest })
ev.emit('messaging-history.set', {
...data,
isLatest:
histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND
? isLatest
: undefined
})
}
break
@@ -267,14 +277,21 @@ const processMessage = async(
case proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
const response = protocolMsg.peerDataOperationRequestResponseMessage!
if(response) {
placeholderResendCache?.del(response.stanzaId!)
// TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
const { peerDataOperationResult } = response
for(const result of peerDataOperationResult!) {
const { placeholderMessageResendResponse: retryResponse } = result
if(retryResponse) {
const webMessageInfo = proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes!)
ev.emit('messages.update', [
{ key: webMessageInfo.key, update: { message: webMessageInfo.message } }
])
// wait till another upsert event is available, don't want it to be part of the PDO response message
setTimeout(() => {
ev.emit('messages.upsert', {
messages: [webMessageInfo],
type: 'notify',
requestId: response.stanzaId!
})
}, 500)
}
}
}
@@ -288,10 +305,10 @@ const processMessage = async(
}
ev.emit('messages.reaction', [{
reaction,
key: content.reactionMessage!.key!,
key: content.reactionMessage?.key!,
}])
} else if(message.messageStubType) {
const jid = message.key!.remoteJid!
const jid = message.key?.remoteJid!
//let actor = whatsappID (message.participant)
let participants: string[]
const emitParticipantsUpdate = (action: ParticipantAction) => (
@@ -380,7 +397,7 @@ const processMessage = async(
if(pollMsg) {
const meIdNormalised = jidNormalizedUser(meId)
const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
const voterJid = getKeyAuthor(message.key!, meIdNormalised)
const voterJid = getKeyAuthor(message.key, meIdNormalised)
const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
try {