feat: implement "snapshot" resyncing

This commit is contained in:
Adhiraj Singh
2021-11-24 18:48:00 +05:30
parent aae2b7a559
commit 983b28ba0e
2 changed files with 146 additions and 55 deletions

View File

@@ -1,7 +1,7 @@
import { SocketConfig, WAPresence, PresenceData, Chat, WAPatchCreate, WAMediaUpload, ChatMutation, WAPatchName, LTHashState, ChatModification, Contact } from "../Types";
import { BinaryNode, getBinaryNodeChild, getBinaryNodeChildren, jidNormalizedUser, S_WHATSAPP_NET } from "../WABinary";
import { proto } from '../../WAProto'
import { generateProfilePicture, toNumber, encodeSyncdPatch, decodePatches, extractSyncdPatches, chatModificationToAppPatch } from "../Utils";
import { generateProfilePicture, toNumber, encodeSyncdPatch, decodePatches, extractSyncdPatches, chatModificationToAppPatch, decodeSyncdSnapshot } from "../Utils";
import { makeMessagesSocket } from "./messages-send";
import makeMutex from "../Utils/make-mutex";
@@ -170,7 +170,9 @@ export const makeChatsSocket = (config: SocketConfig) => {
})
}
const resyncAppState = async(collections: WAPatchName[], fromScratch: boolean = false, returnSnapshot: boolean = false) => {
const resyncAppStateInternal = async(collections: WAPatchName[], fromScratch: boolean = false, returnSnapshot: boolean = false) => {
if(fromScratch) returnSnapshot = true
const states = { } as { [T in WAPatchName]: LTHashState }
for(const name of collections) {
let state: LTHashState = fromScratch ? undefined : await authState.keys.getAppStateSyncVersion(name)
@@ -205,13 +207,20 @@ export const makeChatsSocket = (config: SocketConfig) => {
]
})
const decoded = extractSyncdPatches(result) // extract from binary node
const decoded = await extractSyncdPatches(result) // extract from binary node
for(const key in decoded) {
const name = key as WAPatchName
const { patches, snapshot } = decoded[name]
if(snapshot) {
const newState = await decodeSyncdSnapshot(name, snapshot, authState.keys.getAppStateSyncKey)
states[name] = newState
logger.info(`restored state of ${name} from snapshot to v${newState.version}`)
}
// only process if there are syncd patches
if(decoded[name].length) {
const { newMutations, state: newState } = await decodePatches(name, decoded[name], states[name], authState.keys.getAppStateSyncKey, true)
if(patches.length) {
const { newMutations, state: newState } = await decodePatches(name, patches, states[name], authState.keys.getAppStateSyncKey, true)
await authState.keys.setAppStateSyncVersion(name, newState)
@@ -221,6 +230,15 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
}
const resyncAppState = async(collections: WAPatchName[], returnSnapshot: boolean = false) => {
try {
await resyncAppStateInternal(collections, returnSnapshot)
} catch(error) {
logger.info({ collections, error: error.stack }, 'failed to sync state from version, trying from scratch')
await resyncAppStateInternal(collections, true, true)
}
}
/**
* fetch the profile picture of a user/group
* type = "preview" for a low res picture
@@ -381,12 +399,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
const name = patchCreate.type
await mutationMutex.mutex(
async() => {
try {
await resyncAppState([name])
} catch(error) {
logger.info({ name, error: error.stack }, 'failed to sync state from version, trying from scratch')
await resyncAppState([name], true)
}
await resyncAppState([name])
const { patch, state } = await encodeSyncdPatch(
patchCreate,
authState,