Fix retry receipt, fix assertingPreKeys, uploadPreKeys to 30, generate QR timeout and update example (#833)

* update example

* fix assertingPreKeys, uploadPreKeys to 30, generate QR timeout, sendRetryReceipt fix

* update example, change clear qr to event connection.update

* update example

* firstQR flag

* change checkConnection qr

* update example

* remove semis

* update example
This commit is contained in:
Diego Araujo
2021-11-14 23:41:39 -03:00
committed by GitHub
parent ae80566c0e
commit bbf5bc96cc
3 changed files with 69 additions and 32 deletions

View File

@@ -32,9 +32,10 @@ import makeWASocket, { WASocket, AuthenticationState, DisconnectReason, AnyMessa
JSON.stringify(state, BufferJSON.replacer, 2)
)
}
// start a connection
const startSock = () => {
const sock = makeWASocket({
let sock = makeWASocket({
logger: P({ level: 'trace' }),
printQRInTerminal: true,
auth: loadState()
@@ -50,15 +51,32 @@ import makeWASocket, { WASocket, AuthenticationState, DisconnectReason, AnyMessa
}
})
sock.ev.on('messages.update', m => console.log(m))
sock.ev.on('presence.update', m => console.log(m))
sock.ev.on('chats.update', m => console.log(m))
sock.ev.on('contacts.update', m => console.log(m))
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
if(connection === 'close') {
// reconnect if not logged out
if((lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut) {
sock = startSock()
} else {
console.log('connection closed')
}
}
console.log('connection update', update)
})
// listen for when the auth state is updated
// it is imperative you save this data, it affects the signing keys you need to have conversations
sock.ev.on('auth-state.update', () => saveState())
return sock
}
const sendMessageWTyping = async(msg: AnyMessageContent, jid: string) => {
await sock.presenceSubscribe(jid)
await delay(500)
@@ -71,19 +89,4 @@ import makeWASocket, { WASocket, AuthenticationState, DisconnectReason, AnyMessa
}
sock = startSock()
sock.ev.on('connection.update', (update) => {
const { connection, lastDisconnect } = update
if(connection === 'close') {
// reconnect if not logged out
if((lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut) {
sock = startSock()
} else {
console.log('connection closed')
}
}
console.log('connection update', update)
})
// listen for when the auth state is updated
// it is imperative you save this data, it affects the signing keys you need to have conversations
sock.ev.on('auth-state.update', () => saveState())
})()

View File

@@ -38,8 +38,15 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
await sendNode(stanza)
}
const retries = new Map<string, number>()
const sendRetryRequest = async(node: BinaryNode) => {
const retryCount = +(node.attrs.retryCount || 0) + 1
if (retries.has(node.attrs.id) && retries.get(node.attrs.id)! >= 5) {
retries.delete(node.attrs.id)
return
}
const retryCount = retries.get(node.attrs.id) || 1
retries.set(node.attrs.id, retryCount + 1)
const isGroup = !!node.attrs.participant
const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds
@@ -81,7 +88,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
if(retryCount > 1) {
const exec = generateSignalPubKey(Buffer.from(KEY_BUNDLE_TYPE)).slice(0, 1);
(node.content! as BinaryNode[]).push({
(receipt.content! as BinaryNode[]).push({
tag: 'keys',
attrs: { },
content: [
@@ -93,7 +100,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => {
]
})
}
await sendNode(node)
await sendNode(receipt)
logger.info({ msgId: node.attrs.id, retryCount }, 'sent retry receipt')

View File

@@ -50,6 +50,7 @@ export const makeSocket = ({
let lastDateRecv: Date
let epoch = 0
let keepAliveReq: NodeJS.Timeout
let qrTimer: NodeJS.Timeout
const uqTagId = `${randomBytes(1).toString('hex')[0]}.${randomBytes(1).toString('hex')[0]}-`
const generateMessageTag = () => `${uqTagId}${epoch++}`
@@ -174,10 +175,7 @@ export const makeSocket = ({
/** get some pre-keys and do something with them */
const assertingPreKeys = async(range: number, execute: (keys: { [_: number]: any }) => Promise<void>) => {
const { newPreKeys, lastPreKeyId, preKeysRange } = generateOrGetPreKeys(authState, range)
const preKeys = await getPreKeys(authState.keys, preKeysRange[0], preKeysRange[1])
await execute(preKeys)
creds.serverHasPreKeys = true
creds.nextPreKeyId = Math.max(lastPreKeyId+1, creds.nextPreKeyId)
creds.firstUnuploadedPreKeyId = Math.max(creds.firstUnuploadedPreKeyId, lastPreKeyId+1)
@@ -185,11 +183,14 @@ export const makeSocket = ({
Object.keys(newPreKeys).map(k => authState.keys.setPreKey(+k, newPreKeys[+k]))
)
const preKeys = await getPreKeys(authState.keys, preKeysRange[0], preKeysRange[0] + preKeysRange[1])
await execute(preKeys)
ev.emit('auth-state.update', authState)
}
/** generates and uploads a set of pre-keys */
const uploadPreKeys = async() => {
await assertingPreKeys(50, async preKeys => {
await assertingPreKeys(30, async preKeys => {
const node: BinaryNode = {
tag: 'iq',
attrs: {
@@ -397,7 +398,7 @@ export const makeSocket = ({
})
// QR gen
ws.on('CB:iq,type:set,pair-device', async (stanza: BinaryNode) => {
const postQR = async() => {
const postQR = async(qr: string) => {
if(printQRInTerminal) {
const QR = await import('qrcode-terminal').catch(err => {
logger.error('add `qrcode-terminal` as a dependency to auto-print QR')
@@ -405,8 +406,7 @@ export const makeSocket = ({
QR?.generate(qr, { small: true })
}
}
const refs = ((stanza.content[0] as BinaryNode).content as BinaryNode[]).map(n => n.content as string)
const iq: BinaryNode = {
tag: 'iq',
attrs: {
@@ -415,14 +415,41 @@ export const makeSocket = ({
id: stanza.attrs.id,
}
}
const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64');
await sendNode(iq)
const refs = ((stanza.content[0] as BinaryNode).content as BinaryNode[]).map(n => n.content as string)
const noiseKeyB64 = Buffer.from(creds.noiseKey.public).toString('base64')
const identityKeyB64 = Buffer.from(creds.signedIdentityKey.public).toString('base64')
const advB64 = creds.advSecretKey
const qr = [refs[0], noiseKeyB64, identityKeyB64, advB64].join(',');
ev.emit('connection.update', { qr })
await postQR()
await sendNode(iq)
let firstQR = true
const genPairQR = () => {
const ms = firstQR ? 60000 : 20000
firstQR = false
const ref = refs.shift()
if(!ref) {
end(new Boom('QR refs attempts ended', { statusCode: DisconnectReason.restartRequired }))
return
}
const qr = [ref, noiseKeyB64, identityKeyB64, advB64].join(',')
ev.emit('connection.update', { qr })
postQR(qr)
qrTimer = setTimeout(genPairQR, ms)
}
genPairQR()
const checkConnection = ({ connection }: ConnectionState) => {
if(connection === 'open' || connection === 'close') {
clearTimeout(qrTimer)
ev.off('connection.update', checkConnection)
}
}
ev.on('connection.update', checkConnection)
})
// device paired for the first time
// if device pairs successfully, the server asks to restart the connection