Reconnect fixes

This commit is contained in:
Adhiraj
2020-08-19 16:06:20 +05:30
parent 95d2567e76
commit a6c8fee814
6 changed files with 100 additions and 14 deletions

View File

@@ -124,6 +124,8 @@ conn.regenerateQRIntervalMs = 20000 // QR regen every 20 seconds
Baileys now uses the EventEmitter syntax for events.
They're all nicely typed up, so you shouldn't have any issues with an Intellisense editor like VS Code.
Also, these events are fired regardless of whether they are initiated by the Baileys client or are relayed from your phone.
``` ts
/** when the connection has opened successfully */

View File

@@ -1,7 +1,8 @@
import * as assert from 'assert'
import {WAConnection} from '../WAConnection/WAConnection'
import { AuthenticationCredentialsBase64, BaileysError, MessageLogLevel } from '../WAConnection/Constants'
import { AuthenticationCredentialsBase64, BaileysError, MessageLogLevel, ReconnectMode } from '../WAConnection/Constants'
import { delay, promiseTimeout } from '../WAConnection/Utils'
import { close } from 'fs'
describe('QR Generation', () => {
it('should generate QR', async () => {
@@ -72,7 +73,84 @@ describe('Test Connect', () => {
.finally (() => conn.close())
})
})
describe ('Pending Requests', async () => {
describe ('Reconnects', () => {
it ('should disconnect & reconnect phone', async () => {
const conn = new WAConnection ()
await conn.loadAuthInfo('./auth_info.json').connect ()
assert.equal (conn.phoneConnected, true)
try {
const waitForEvent = expect => new Promise (resolve => {
conn.on ('connection-phone-change', ({connected}) => {
assert.equal (connected, expect)
conn.removeAllListeners ('connection-phone-change')
resolve ()
})
})
console.log ('disconnect your phone from the internet')
await waitForEvent (false)
console.log ('reconnect your phone to the internet')
await waitForEvent (true)
} finally {
conn.close ()
}
})
it ('should reconnect connection', async () => {
const conn = new WAConnection ()
conn.autoReconnect = ReconnectMode.onConnectionLost
await conn.loadAuthInfo('./auth_info.json').connect ()
assert.equal (conn.phoneConnected, true)
try {
const closeConn = () => conn['conn']?.terminate ()
const task = new Promise (resolve => {
let closes = 0
conn.on ('closed', ({reason, isReconnecting}) => {
console.log (`closed: ${reason}`)
assert.ok (reason)
assert.ok (isReconnecting)
closes += 1
// let it fail reconnect a few times
if (closes > 4) {
console.log ('here')
conn.removeAllListeners ('closed')
conn.removeAllListeners ('connecting')
resolve ()
}
})
conn.on ('connecting', () => {
// close again
delay (500).then (closeConn)
})
})
closeConn ()
await task
await new Promise (resolve => {
conn.on ('open', () => {
conn.removeAllListeners ('open')
resolve ()
})
})
conn.close ()
conn.on ('connecting', () => assert.fail('should not connect'))
await delay (2000)
} finally {
conn.removeAllListeners ('connecting')
conn.removeAllListeners ('closed')
conn.removeAllListeners ('open')
conn.close ()
}
})
})
describe ('Pending Requests', () => {
it('should queue requests when closed', async () => {
const conn = new WAConnection ()
conn.pendingRequestTimeoutMs = null

View File

@@ -73,12 +73,12 @@ export class WAConnection extends EventEmitter {
this.registerCallback (['Cmd', 'type:disconnect'], json => this.unexpectedDisconnect(json[1].kind))
}
async unexpectedDisconnect (error?: DisconnectReason) {
const willReconnect = this.autoReconnect === ReconnectMode.onAllErrors || (this.autoReconnect === ReconnectMode.onConnectionLost && (error === 'lost' || error === 'closed'))
const willReconnect = this.autoReconnect === ReconnectMode.onAllErrors || (this.autoReconnect === ReconnectMode.onConnectionLost && (error !== 'replaced'))
this.log (`got disconnected, reason ${error || 'unknown'}${willReconnect ? ', reconnecting in a few seconds...' : ''}`, MessageLogLevel.info)
this.closeInternal(error, willReconnect)
willReconnect && this.reconnectLoop ()
willReconnect && !this.cancelReconnect && this.reconnectLoop ()
}
/**
* base 64 encode the authentication credentials and return them
@@ -285,7 +285,7 @@ export class WAConnection extends EventEmitter {
this.pendingRequests.forEach (({reject}) => reject(new Error('closed')))
this.pendingRequests = []
}
protected closeInternal (reason?: DisconnectReason, isReconnecting: boolean = false) {
protected closeInternal (reason?: DisconnectReason, isReconnecting: boolean=false) {
this.qrTimeout && clearTimeout (this.qrTimeout)
this.phoneCheck && clearTimeout (this.phoneCheck)
@@ -303,8 +303,8 @@ export class WAConnection extends EventEmitter {
}
})
if (this.keepAliveReq) clearInterval(this.keepAliveReq)
this.emit ('closed', { reason, isReconnecting })
// reconnecting if the timeout is active for the reconnect loop
this.emit ('closed', { reason, isReconnecting: this.cancelReconnect || isReconnecting })
}
protected async reconnectLoop () {

View File

@@ -28,6 +28,7 @@ export class WAConnection extends Base {
this.startKeepAliveRequest()
this.conn.removeAllListeners ('error')
this.conn.removeAllListeners ('close')
this.conn.on ('close', () => this.unexpectedDisconnect ('closed'))
this.state = 'open'
@@ -37,7 +38,8 @@ export class WAConnection extends Base {
})
this.conn.on('message', m => this.onMessageRecieved(m))
// if there was an error in the WebSocket
this.conn.on('error', error => { this.closeInternal(error.message as any); reject(error) })
this.conn.on('error', reject)
this.conn.on('close', () => reject(new Error('closed')))
})
try {
@@ -77,7 +79,6 @@ export class WAConnection extends Base {
let receivedMessages = false
let convoResolve: () => void
this.log('waiting for chats & contacts', MessageLogLevel.info) // wait for the message with chats
const waitForConvos = () =>
Utils.promiseTimeout(timeoutMs, resolve => {
convoResolve = () => {
@@ -91,7 +92,7 @@ export class WAConnection extends Base {
}
const chatUpdate = json => {
receivedMessages = true
const isLast = json[1].last || (json[1].add === 'last' && stopAfterMostRecentMessage)
const isLast = json[1].last || stopAfterMostRecentMessage
const messages = json[2] as WANode[]
if (messages) {
@@ -133,6 +134,8 @@ export class WAConnection extends Base {
this.deregisterCallback(['response', 'type:chat'])
this.log ('received chats list', MessageLogLevel.info)
if (this.chats.all().length > 0) waitForConvos().then (resolve)
else resolve ()
})
@@ -157,6 +160,8 @@ export class WAConnection extends Base {
resolve ()
this.deregisterCallback(['response', 'type:contacts'])
this.log ('received contacts list', MessageLogLevel.info)
})
})
)
@@ -259,6 +264,7 @@ export class WAConnection extends Base {
try {
await this.connect ()
this.cancelReconnect = null
break
} catch (error) {
this.log (`error in reconnecting: ${error}, reconnecting...`, MessageLogLevel.info)
}

View File

@@ -261,7 +261,7 @@ export class WAConnection extends Base {
}
protected registerPhoneConnectionPoll () {
this.phoneCheck = setInterval (() => {
this.checkPhoneConnection (7500) // 7500 ms for timeout
this.checkPhoneConnection (5000) // 5000 ms for timeout
.then (connected => {
if (this.phoneConnected != connected) {
this.emit ('connection-phone-change', {connected})
@@ -269,7 +269,7 @@ export class WAConnection extends Base {
this.phoneConnected = connected
})
.catch (error => this.log(`error in getting phone connection: ${error}`, MessageLogLevel.info))
}, 20000)
}, 15000)
}
// Add all event types

View File

@@ -134,7 +134,7 @@ export class WAConnection extends Base {
/** Get the invite link of the given group */
async groupInviteCode(jid: string) {
const json = ['query', 'inviteCode', jid]
const response = await this.query({json})
const response = await this.query({json, expect200: true})
return response.code as string
}
}