fix: catch unexpected errors on MD

This commit is contained in:
Adhiraj Singh
2022-03-15 12:34:52 +05:30
parent 8a9de2f042
commit 13b0da0954
3 changed files with 107 additions and 53 deletions

View File

@@ -19,10 +19,11 @@ export const makeChatsSocket = (config: SocketConfig) => {
sendNode, sendNode,
query, query,
fetchPrivacySettings, fetchPrivacySettings,
onUnexpectedError,
} = sock } = sock
const mutationMutex = makeMutex() const mutationMutex = makeMutex()
/// helper function to fetch an app state sync key
const getAppStateSyncKey = async(keyId: string) => { const getAppStateSyncKey = async(keyId: string) => {
const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]) const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId])
return key return key
@@ -176,35 +177,30 @@ export const makeChatsSocket = (config: SocketConfig) => {
}] }]
}] }]
}) })
const profiles = getBinaryNodeChild(getBinaryNodeChild(results, 'business_profile'), 'profile')
if(!profiles) {
// if not bussines
if(logger.level === 'trace') {
logger.trace({ jid }, 'Not bussines')
}
return const profileNode = getBinaryNodeChild(results, 'business_profile')
const profiles = getBinaryNodeChild(profileNode, 'profile')
if(profiles) {
const address = getBinaryNodeChild(profiles, 'address')
const description = getBinaryNodeChild(profiles, 'description')
const website = getBinaryNodeChild(profiles, 'website')
const email = getBinaryNodeChild(profiles, 'email')
const category = getBinaryNodeChild(getBinaryNodeChild(profiles, 'categories'), 'category')
const business_hours = getBinaryNodeChild(profiles, 'business_hours')
const business_hours_config = business_hours && getBinaryNodeChildren(business_hours, 'business_hours_config')
return {
wid: profiles.attrs?.jid,
address: address?.content.toString(),
description: description?.content.toString(),
website: [website?.content.toString()],
email: email?.content.toString(),
category: category?.content.toString(),
business_hours: {
timezone: business_hours?.attrs?.timezone,
business_config: business_hours_config?.map(({ attrs }) => attrs as unknown as WABusinessHoursConfig)
}
} as unknown as WABusinessProfile
} }
const address = getBinaryNodeChild(profiles, 'address')
const description = getBinaryNodeChild(profiles, 'description')
const website = getBinaryNodeChild(profiles, 'website')
const email = getBinaryNodeChild(profiles, 'email')
const category = getBinaryNodeChild(getBinaryNodeChild(profiles, 'categories'), 'category')
const business_hours = getBinaryNodeChild(profiles, 'business_hours')
const business_hours_config = business_hours && getBinaryNodeChildren(business_hours, 'business_hours_config')
return {
wid: profiles.attrs?.jid,
address: address?.content.toString(),
description: description?.content.toString(),
website: [website?.content.toString()],
email: email?.content.toString(),
category: category?.content.toString(),
business_hours: {
timezone: business_hours?.attrs?.timezone,
business_config: business_hours_config?.map(({ attrs }) => attrs as unknown as WABusinessHoursConfig)
}
} as unknown as WABusinessProfile
} }
const updateAccountSyncTimestamp = async(fromTimestamp: number | string) => { const updateAccountSyncTimestamp = async(fromTimestamp: number | string) => {
@@ -431,7 +427,6 @@ export const makeChatsSocket = (config: SocketConfig) => {
} }
const resyncMainAppState = async() => { const resyncMainAppState = async() => {
logger.debug('resyncing main app state') logger.debug('resyncing main app state')
await ( await (
@@ -445,7 +440,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
]) ])
) )
.catch(err => ( .catch(err => (
logger.warn({ trace: err.stack }, 'failed to sync app state') onUnexpectedError(err, 'main app sync')
)) ))
) )
} }
@@ -480,7 +475,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
} else if(action?.pushNameSetting) { } else if(action?.pushNameSetting) {
const me = { const me = {
...authState.creds.me!, ...authState.creds.me!,
name: action?.pushNameSetting?.name! name: action?.pushNameSetting?.name!
} }
ev.emit('creds.update', { me }) ev.emit('creds.update', { me })
} else if(action?.pinAction) { } else if(action?.pinAction) {
@@ -640,6 +635,20 @@ export const makeChatsSocket = (config: SocketConfig) => {
return appPatch(patch) return appPatch(patch)
} }
/**
* queries need to be fired on connection open
* help ensure parity with WA Web
* */
const fireInitQueries = () => (
Promise.all([
fetchAbt(),
fetchProps(),
fetchBlocklist(),
fetchPrivacySettings(),
sendPresenceUpdate('available')
])
)
ws.on('CB:presence', handlePresenceUpdate) ws.on('CB:presence', handlePresenceUpdate)
ws.on('CB:chatstate', handlePresenceUpdate) ws.on('CB:chatstate', handlePresenceUpdate)
@@ -680,12 +689,10 @@ export const makeChatsSocket = (config: SocketConfig) => {
ev.on('connection.update', ({ connection }) => { ev.on('connection.update', ({ connection }) => {
if(connection === 'open') { if(connection === 'open') {
fetchAbt() fireInitQueries()
fetchProps() .catch(
fetchBlocklist() error => onUnexpectedError(error, 'connection open requests')
fetchPrivacySettings() )
sendPresenceUpdate('available')
} }
}) })

View File

@@ -1,7 +1,7 @@
import { proto } from '../../WAProto' import { proto } from '../../WAProto'
import { KEY_BUNDLE_TYPE } from '../Defaults' import { KEY_BUNDLE_TYPE } from '../Defaults'
import { Chat, GroupMetadata, MessageUserReceipt, ParticipantAction, SocketConfig, WAMessageStubType } from '../Types' import { BaileysEventMap, Chat, GroupMetadata, MessageUserReceipt, ParticipantAction, SocketConfig, WAMessageStubType } from '../Types'
import { decodeMessageStanza, downloadAndProcessHistorySyncNotification, encodeBigEndian, generateSignalPubKey, normalizeMessageContent, toNumber, xmppPreKey, xmppSignedPreKey } from '../Utils' import { decodeMessageStanza, downloadAndProcessHistorySyncNotification, encodeBigEndian, generateSignalPubKey, normalizeMessageContent, toNumber, xmppPreKey, xmppSignedPreKey } from '../Utils'
import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex' import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex'
import { areJidsSameUser, BinaryNode, BinaryNodeAttributes, getAllBinaryNodeChildren, getBinaryNodeChildren, isJidGroup, jidDecode, jidEncode, jidNormalizedUser } from '../WABinary' import { areJidsSameUser, BinaryNode, BinaryNodeAttributes, getAllBinaryNodeChildren, getBinaryNodeChildren, isJidGroup, jidDecode, jidEncode, jidNormalizedUser } from '../WABinary'
@@ -15,6 +15,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
ev, ev,
authState, authState,
ws, ws,
onUnexpectedError,
assertSessions, assertSessions,
assertingPreKeys, assertingPreKeys,
sendNode, sendNode,
@@ -94,6 +95,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
} }
] ]
} }
if(node.attrs.recipient) { if(node.attrs.recipient) {
receipt.attrs.recipient = node.attrs.recipient receipt.attrs.recipient = node.attrs.recipient
} }
@@ -103,9 +105,9 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
} }
if(retryCount > 1) { if(retryCount > 1) {
const exec = generateSignalPubKey(Buffer.from(KEY_BUNDLE_TYPE)).slice(0, 1); const exec = generateSignalPubKey(Buffer.from(KEY_BUNDLE_TYPE)).slice(0, 1)
const content = receipt.content! as BinaryNode[]
(receipt.content! as BinaryNode[]).push({ content.push({
tag: 'keys', tag: 'keys',
attrs: { }, attrs: { },
content: [ content: [
@@ -357,10 +359,13 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
ev.emit('messages.upsert', { messages: [msg], type: stanza.attrs.offline ? 'append' : 'notify' }) ev.emit('messages.upsert', { messages: [msg], type: stanza.attrs.offline ? 'append' : 'notify' })
} }
) )
.catch(
error => onUnexpectedError(error, 'processing message')
)
}) })
ws.on('CB:ack,class:message', async(node: BinaryNode) => { ws.on('CB:ack,class:message', async(node: BinaryNode) => {
await sendNode({ sendNode({
tag: 'ack', tag: 'ack',
attrs: { attrs: {
class: 'receipt', class: 'receipt',
@@ -368,6 +373,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
from: node.attrs.from from: node.attrs.from
} }
}) })
.catch(err => onUnexpectedError(err, 'ack message receipt'))
logger.debug({ attrs: node.attrs }, 'sending receipt for ack') logger.debug({ attrs: node.attrs }, 'sending receipt for ack')
}) })
@@ -376,7 +382,10 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
const [child] = getAllBinaryNodeChildren(node) const [child] = getAllBinaryNodeChildren(node)
if(!!child?.tag) { if(!!child?.tag) {
await sendMessageAck(node, { class: 'call', type: child.tag }) sendMessageAck(node, { class: 'call', type: child.tag })
.catch(
error => onUnexpectedError(error, 'ack call')
)
} }
}) })
@@ -489,11 +498,9 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
) )
} }
ws.on('CB:receipt', handleReceipt) const handleNotification = async(node: BinaryNode) => {
ws.on('CB:notification', async(node: BinaryNode) => {
const remoteJid = node.attrs.from const remoteJid = node.attrs.from
processingMutex.mutex( await processingMutex.mutex(
remoteJid, remoteJid,
() => { () => {
const msg = processNotification(node) const msg = processNotification(node)
@@ -516,15 +523,19 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
) )
await sendMessageAck(node, { class: 'notification', type: node.attrs.type }) await sendMessageAck(node, { class: 'notification', type: node.attrs.type })
}) }
ev.on('messages.upsert', async({ messages, type }) => { const handleUpsertedMessages = async({ messages, type }: BaileysEventMap<any>['messages.upsert']) => {
if(type === 'notify' || type === 'append') { if(type === 'notify' || type === 'append') {
const chat: Partial<Chat> = { id: messages[0].key.remoteJid } const chatId = jidNormalizedUser(messages[0].key.remoteJid)
const chat: Partial<Chat> = { id: chatId }
const contactNameUpdates: { [_: string]: string } = { } const contactNameUpdates: { [_: string]: string } = { }
for(const msg of messages) { for(const msg of messages) {
const normalizedChatId = jidNormalizedUser(msg.key.remoteJid)
if(!!msg.pushName) { if(!!msg.pushName) {
const jid = msg.key.fromMe ? jidNormalizedUser(authState.creds.me!.id) : (msg.key.participant || msg.key.remoteJid) let jid = msg.key.fromMe ? authState.creds.me!.id : (msg.key.participant || msg.key.remoteJid)
jid = jidNormalizedUser(jid)
contactNameUpdates[jid] = msg.pushName contactNameUpdates[jid] = msg.pushName
// update our pushname too // update our pushname too
if(msg.key.fromMe && authState.creds.me?.name !== msg.pushName) { if(msg.key.fromMe && authState.creds.me?.name !== msg.pushName) {
@@ -533,7 +544,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
} }
await processingMutex.mutex( await processingMutex.mutex(
'p-' + chat.id!, 'p-' + normalizedChatId,
() => processMessage(msg, chat) () => processMessage(msg, chat)
) )
@@ -555,6 +566,29 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
)) ))
} }
} }
}
ws.on('CB:receipt', node => {
handleReceipt(node)
.catch(
error => onUnexpectedError(error, 'handling receipt')
)
})
ws.on('CB:notification', async(node: BinaryNode) => {
handleNotification(node)
.catch(
error => {
onUnexpectedError(error, 'handling notification')
}
)
})
ev.on('messages.upsert', data => {
handleUpsertedMessages(data)
.catch(
error => onUnexpectedError(error, 'handling upserted messages')
)
}) })
return { ...sock, processMessage, sendMessageAck, sendRetryRequest } return { ...sock, processMessage, sendMessageAck, sendRetryRequest }

View File

@@ -84,6 +84,14 @@ export const makeSocket = ({
return sendRawMessage(buff) return sendRawMessage(buff)
} }
/** log & process any unexpected errors */
const onUnexpectedError = (error: Error, msg: string) => {
logger.error(
{ trace: error.stack, output: (error as any).output },
`unexpected error in '${msg}'`
)
}
/** await the next incoming message */ /** await the next incoming message */
const awaitNextMessage = async(sendMsg?: Uint8Array) => { const awaitNextMessage = async(sendMsg?: Uint8Array) => {
if(ws.readyState !== ws.OPEN) { if(ws.readyState !== ws.OPEN) {
@@ -200,7 +208,11 @@ export const makeSocket = ({
startKeepAliveRequest() startKeepAliveRequest()
} }
/** get some pre-keys and do something with them */ /**
* get some pre-keys and do something with them
* @param range how many pre-keys to get
* @param execute what to do with them
*/
const assertingPreKeys = async(range: number, execute: (keys: { [_: number]: any }) => Promise<void>) => { const assertingPreKeys = async(range: number, execute: (keys: { [_: number]: any }) => Promise<void>) => {
const { newPreKeys, lastPreKeyId, preKeysRange } = generateOrGetPreKeys(authState.creds, range) const { newPreKeys, lastPreKeyId, preKeysRange } = generateOrGetPreKeys(authState.creds, range)
@@ -558,6 +570,7 @@ export const makeSocket = ({
sendNode, sendNode,
logout, logout,
end, end,
onUnexpectedError,
/** Waits for the connection to WA to reach a state */ /** Waits for the connection to WA to reach a state */
waitForConnectionUpdate: bindWaitForConnectionUpdate(ev) waitForConnectionUpdate: bindWaitForConnectionUpdate(ev)
} }