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,16 +1,17 @@
import { Boom } from '@hapi/boom'
import NodeCache from 'node-cache'
import readline from 'readline'
import makeWASocket, { AnyMessageContent, BinaryInfo, delay, DisconnectReason, encodeWAM, fetchLatestBaileysVersion, getAggregateVotesInPollMessage, makeCacheableSignalKeyStore, makeInMemoryStore, PHONENUMBER_MCC, proto, useMultiFileAuthState, WAMessageContent, WAMessageKey } from '../src'
import MAIN_LOGGER from '../src/Utils/logger'
import makeWASocket, { AnyMessageContent, BinaryInfo, delay, DisconnectReason, downloadAndProcessHistorySyncNotification, encodeWAM, fetchLatestBaileysVersion, getAggregateVotesInPollMessage, getHistoryMsg, isJidNewsletter, makeCacheableSignalKeyStore, makeInMemoryStore, PHONENUMBER_MCC, proto, useMultiFileAuthState, WAMessageContent, WAMessageKey } from '../src'
//import MAIN_LOGGER from '../src/Utils/logger'
import open from 'open'
import fs from 'fs'
import P from 'pino'
const logger = MAIN_LOGGER.child({})
const logger = P({ timestamp: () => `,"time":"${new Date().toJSON()}"` }, P.destination('./wa-logs.txt'))
logger.level = 'trace'
const useStore = !process.argv.includes('--no-store')
const doReplies = !process.argv.includes('--no-reply')
const doReplies = process.argv.includes('--do-reply')
const usePairingCode = process.argv.includes('--use-pairing-code')
const useMobile = process.argv.includes('--mobile')
@@ -18,6 +19,8 @@ const useMobile = process.argv.includes('--mobile')
// keep this out of the socket itself, so as to prevent a message decryption/encryption loop across socket restarts
const msgRetryCounterCache = new NodeCache()
const onDemandMap = new Map<string, string>()
// Read line interface
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
const question = (text: string) => new Promise<string>((resolve) => rl.question(text, resolve))
@@ -231,8 +234,11 @@ const startSock = async() => {
// history received
if(events['messaging-history.set']) {
const { chats, contacts, messages, isLatest } = events['messaging-history.set']
console.log(`recv ${chats.length} chats, ${contacts.length} contacts, ${messages.length} msgs (is latest: ${isLatest})`)
const { chats, contacts, messages, isLatest, progress, syncType } = events['messaging-history.set']
if (syncType === proto.HistorySync.HistorySyncType.ON_DEMAND) {
console.log('received on-demand history sync, messages=', messages)
}
console.log(`recv ${chats.length} chats, ${contacts.length} contacts, ${messages.length} msgs (is latest: ${isLatest}, progress: ${progress}%), type: ${syncType}`)
}
// received a new message
@@ -241,8 +247,65 @@ const startSock = async() => {
console.log('recv messages ', JSON.stringify(upsert, undefined, 2))
if(upsert.type === 'notify') {
for(const msg of upsert.messages) {
if(!msg.key.fromMe && doReplies) {
for (const msg of upsert.messages) {
//TODO: More built-in implementation of this
/* if (
msg.message?.protocolMessage?.type ===
proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION
) {
const historySyncNotification = getHistoryMsg(msg.message)
if (
historySyncNotification?.syncType ==
proto.HistorySync.HistorySyncType.ON_DEMAND
) {
const { messages } =
await downloadAndProcessHistorySyncNotification(
historySyncNotification,
{}
)
const chatId = onDemandMap.get(
historySyncNotification!.peerDataRequestSessionId!
)
console.log(messages)
onDemandMap.delete(
historySyncNotification!.peerDataRequestSessionId!
)
/*
// 50 messages is the limit imposed by whatsapp
//TODO: Add ratelimit of 7200 seconds
//TODO: Max retries 10
const messageId = await sock.fetchMessageHistory(
50,
oldestMessageKey,
oldestMessageTimestamp
)
onDemandMap.set(messageId, chatId)
}
} */
if (msg.message?.conversation || msg.message?.extendedTextMessage?.text) {
const text = msg.message?.conversation || msg.message?.extendedTextMessage?.text
if (text == "requestPlaceholder" && !upsert.requestId) {
const messageId = await sock.requestPlaceholderResend(msg.key)
console.log('requested placeholder resync, id=', messageId)
} else if (upsert.requestId) {
console.log('Message received from phone, id=', upsert.requestId, msg)
}
// go to an old chat and send this
if (text == "onDemandHistSync") {
const messageId = await sock.fetchMessageHistory(50, msg.key, msg.messageTimestamp!)
console.log('requested on-demand sync, id=', messageId)
}
}
if(!msg.key.fromMe && doReplies && !isJidNewsletter(msg.key?.remoteJid!)) {
console.log('replying to', msg.key.remoteJid)
await sock!.readMessages([msg.key])
await sendMessageWTyping({ text: 'Hello there!' }, msg.key.remoteJid!)