From 39802eb44973bb35b4e71dc1d31b739d02f5c6dd Mon Sep 17 00:00:00 2001 From: Adhiraj Singh Date: Wed, 6 Jan 2021 18:21:36 +0530 Subject: [PATCH] Better phone connection detection --- src/Tests/Tests.Connect.ts | 15 +++++++++++ src/Tests/Tests.Misc.ts | 18 ++++++++++++- src/WAConnection/0.Base.ts | 42 +++++++++++++++++++++++------ src/WAConnection/7.MessagesExtra.ts | 5 +++- 4 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/Tests/Tests.Connect.ts b/src/Tests/Tests.Connect.ts index c49976c..9848c1c 100644 --- a/src/Tests/Tests.Connect.ts +++ b/src/Tests/Tests.Connect.ts @@ -372,6 +372,21 @@ describe ('Pending Requests', () => { conn.close () }) + it('[MANUAL] should receive query response after phone disconnect', async () => { + const conn = makeConnection () + await conn.loadAuthInfo('./auth_info.json').connect () + + console.log(`disconnect your phone from the internet!`) + await delay(5000) + const task = conn.loadMessages(testJid, 50) + setTimeout(() => console.log('reconnect your phone!'), 20_000) + + const result = await task + assert.ok(result.messages[0]) + assert.ok(!conn['phoneCheckInterval']) // should be undefined + + conn.close () + }) it('should re-execute query on connection closed error', async () => { const conn = makeConnection () //conn.pendingRequestTimeoutMs = 10_000 diff --git a/src/Tests/Tests.Misc.ts b/src/Tests/Tests.Misc.ts index bfa0cb1..c2e6f35 100644 --- a/src/Tests/Tests.Misc.ts +++ b/src/Tests/Tests.Misc.ts @@ -1,4 +1,4 @@ -import { Presence, ChatModification, delay, newMessagesDB, WA_DEFAULT_EPHEMERAL, MessageType } from '../WAConnection/WAConnection' +import { Presence, ChatModification, delay, newMessagesDB, WA_DEFAULT_EPHEMERAL, MessageType, WAMessage } from '../WAConnection/WAConnection' import { promises as fs } from 'fs' import * as assert from 'assert' import fetch from 'node-fetch' @@ -397,4 +397,20 @@ WAConnectionTest('Misc', conn => { assert.strictEqual(conn.blocklist.length, blockedCount); await waitForEventRemoved }) + it('should exit an invalid query', async () => { + // try and send an already sent message + let msg: WAMessage + await conn.findMessage(testJid, 5, m => { + if(m.key.fromMe) { + msg = m + return true + } + }) + try { + await conn.relayWAMessage(msg) + assert.fail('should not have sent') + } catch(error) { + assert.strictEqual(error.status, 422) + } + }) }) \ No newline at end of file diff --git a/src/WAConnection/0.Base.ts b/src/WAConnection/0.Base.ts index c265a58..96e5d59 100644 --- a/src/WAConnection/0.Base.ts +++ b/src/WAConnection/0.Base.ts @@ -180,16 +180,18 @@ export class WAConnection extends EventEmitter { * @param timeoutMs timeout after which the promise will reject */ async waitForMessage(tag: string, requiresPhoneConnection: boolean, timeoutMs?: number) { - if (requiresPhoneConnection) { - this.startPhoneCheckInterval () - } let onRecv: (json) => void let onErr: (err) => void + let cancelPhoneChecker: () => void + if (requiresPhoneConnection) { + this.startPhoneCheckInterval() + cancelPhoneChecker = this.exitQueryIfResponseNotExpected(tag, err => onErr(err)) + } try { const result = await Utils.promiseTimeout(timeoutMs, (resolve, reject) => { onRecv = resolve - onErr = ({reason}) => reject(new Error(reason)) + onErr = ({ reason, status }) => reject(new BaileysError(reason, { status })) this.on (`TAG:${tag}`, onRecv) this.on ('ws-close', onErr) // if the socket closes, you'll never receive the message }, @@ -199,6 +201,7 @@ export class WAConnection extends EventEmitter { requiresPhoneConnection && this.clearPhoneCheckInterval() this.off (`TAG:${tag}`, onRecv) this.off (`ws-close`, onErr) + cancelPhoneChecker && cancelPhoneChecker() } } /** Generic function for action, set queries */ @@ -253,7 +256,12 @@ export class WAConnection extends EventEmitter { // read here: http://getstatuscode.com/599 if (error.status === 599) { this.unexpectedDisconnect (DisconnectReason.badSession) - } else if ((error.message === 'close' || error.message === 'lost') && waitForOpen && this.state !== 'close') { + } else if ( + (error.message === 'close' || error.message === 'lost') && + waitForOpen && + this.state !== 'close' && + (this.pendingRequestTimeoutMs === null || + this.pendingRequestTimeoutMs > 0)) { // nothing here } else throw error @@ -262,6 +270,23 @@ export class WAConnection extends EventEmitter { } } } + protected exitQueryIfResponseNotExpected(tag: string, cancel: ({ reason, status }) => void) { + let timeout: NodeJS.Timeout + const listener = ({ connected }) => { + if(connected) { + timeout = setTimeout(() => { + this.logger.info({ tag }, `cancelling wait for message as a response is no longer expected from the phone`) + cancel({ reason: 'Not expecting a response', status: 422 }) + }, 5_000) + this.off('connection-phone-change', listener) + } + } + this.on('connection-phone-change', listener) + return () => { + this.off('connection-phone-change', listener) + timeout && clearTimeout(timeout) + } + } /** interval is started when a query takes too long to respond */ protected startPhoneCheckInterval () { this.phoneCheckListeners += 1 @@ -272,9 +297,10 @@ export class WAConnection extends EventEmitter { this.logger.info('checking phone connection...') this.sendAdminTest () - - this.phoneConnected = false - this.emit ('connection-phone-change', { connected: false }) + if(this.phoneConnected !== false) { + this.phoneConnected = false + this.emit ('connection-phone-change', { connected: false }) + } }, this.connectOptions.phoneResponseTime) } diff --git a/src/WAConnection/7.MessagesExtra.ts b/src/WAConnection/7.MessagesExtra.ts index 320acec..64894d0 100644 --- a/src/WAConnection/7.MessagesExtra.ts +++ b/src/WAConnection/7.MessagesExtra.ts @@ -265,7 +265,10 @@ export class WAConnection extends Base { const response: WANode = await this.query({json, binaryTags: [24, WAFlag.ignore], expect200: true}) // encrypt and send off const messages = response[2] ? response[2].map (row => row[2]) : [] - return { last: response[1]['last'] === 'true', messages: messages as WAMessage[] } + return { + last: response[1]['last'] === 'true', + messages: messages as WAMessage[] + } } /** * Delete a message in a chat for yourself