mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Reconnect fixes
This commit is contained in:
@@ -124,6 +124,8 @@ conn.regenerateQRIntervalMs = 20000 // QR regen every 20 seconds
|
|||||||
Baileys now uses the EventEmitter syntax for events.
|
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.
|
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
|
``` ts
|
||||||
|
|
||||||
/** when the connection has opened successfully */
|
/** when the connection has opened successfully */
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import * as assert from 'assert'
|
import * as assert from 'assert'
|
||||||
import {WAConnection} from '../WAConnection/WAConnection'
|
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 { delay, promiseTimeout } from '../WAConnection/Utils'
|
||||||
|
import { close } from 'fs'
|
||||||
|
|
||||||
describe('QR Generation', () => {
|
describe('QR Generation', () => {
|
||||||
it('should generate QR', async () => {
|
it('should generate QR', async () => {
|
||||||
@@ -72,7 +73,84 @@ describe('Test Connect', () => {
|
|||||||
.finally (() => conn.close())
|
.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 () => {
|
it('should queue requests when closed', async () => {
|
||||||
const conn = new WAConnection ()
|
const conn = new WAConnection ()
|
||||||
conn.pendingRequestTimeoutMs = null
|
conn.pendingRequestTimeoutMs = null
|
||||||
|
|||||||
@@ -73,12 +73,12 @@ export class WAConnection extends EventEmitter {
|
|||||||
this.registerCallback (['Cmd', 'type:disconnect'], json => this.unexpectedDisconnect(json[1].kind))
|
this.registerCallback (['Cmd', 'type:disconnect'], json => this.unexpectedDisconnect(json[1].kind))
|
||||||
}
|
}
|
||||||
async unexpectedDisconnect (error?: DisconnectReason) {
|
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.log (`got disconnected, reason ${error || 'unknown'}${willReconnect ? ', reconnecting in a few seconds...' : ''}`, MessageLogLevel.info)
|
||||||
|
|
||||||
this.closeInternal(error, willReconnect)
|
this.closeInternal(error, willReconnect)
|
||||||
willReconnect && this.reconnectLoop ()
|
|
||||||
|
willReconnect && !this.cancelReconnect && this.reconnectLoop ()
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* base 64 encode the authentication credentials and return them
|
* 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.forEach (({reject}) => reject(new Error('closed')))
|
||||||
this.pendingRequests = []
|
this.pendingRequests = []
|
||||||
}
|
}
|
||||||
protected closeInternal (reason?: DisconnectReason, isReconnecting: boolean = false) {
|
protected closeInternal (reason?: DisconnectReason, isReconnecting: boolean=false) {
|
||||||
this.qrTimeout && clearTimeout (this.qrTimeout)
|
this.qrTimeout && clearTimeout (this.qrTimeout)
|
||||||
this.phoneCheck && clearTimeout (this.phoneCheck)
|
this.phoneCheck && clearTimeout (this.phoneCheck)
|
||||||
|
|
||||||
@@ -303,8 +303,8 @@ export class WAConnection extends EventEmitter {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (this.keepAliveReq) clearInterval(this.keepAliveReq)
|
if (this.keepAliveReq) clearInterval(this.keepAliveReq)
|
||||||
|
// reconnecting if the timeout is active for the reconnect loop
|
||||||
this.emit ('closed', { reason, isReconnecting })
|
this.emit ('closed', { reason, isReconnecting: this.cancelReconnect || isReconnecting })
|
||||||
}
|
}
|
||||||
protected async reconnectLoop () {
|
protected async reconnectLoop () {
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export class WAConnection extends Base {
|
|||||||
this.startKeepAliveRequest()
|
this.startKeepAliveRequest()
|
||||||
|
|
||||||
this.conn.removeAllListeners ('error')
|
this.conn.removeAllListeners ('error')
|
||||||
|
this.conn.removeAllListeners ('close')
|
||||||
this.conn.on ('close', () => this.unexpectedDisconnect ('closed'))
|
this.conn.on ('close', () => this.unexpectedDisconnect ('closed'))
|
||||||
|
|
||||||
this.state = 'open'
|
this.state = 'open'
|
||||||
@@ -37,7 +38,8 @@ export class WAConnection extends Base {
|
|||||||
})
|
})
|
||||||
this.conn.on('message', m => this.onMessageRecieved(m))
|
this.conn.on('message', m => this.onMessageRecieved(m))
|
||||||
// if there was an error in the WebSocket
|
// 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 {
|
try {
|
||||||
@@ -77,7 +79,6 @@ export class WAConnection extends Base {
|
|||||||
let receivedMessages = false
|
let receivedMessages = false
|
||||||
let convoResolve: () => void
|
let convoResolve: () => void
|
||||||
|
|
||||||
this.log('waiting for chats & contacts', MessageLogLevel.info) // wait for the message with chats
|
|
||||||
const waitForConvos = () =>
|
const waitForConvos = () =>
|
||||||
Utils.promiseTimeout(timeoutMs, resolve => {
|
Utils.promiseTimeout(timeoutMs, resolve => {
|
||||||
convoResolve = () => {
|
convoResolve = () => {
|
||||||
@@ -91,7 +92,7 @@ export class WAConnection extends Base {
|
|||||||
}
|
}
|
||||||
const chatUpdate = json => {
|
const chatUpdate = json => {
|
||||||
receivedMessages = true
|
receivedMessages = true
|
||||||
const isLast = json[1].last || (json[1].add === 'last' && stopAfterMostRecentMessage)
|
const isLast = json[1].last || stopAfterMostRecentMessage
|
||||||
const messages = json[2] as WANode[]
|
const messages = json[2] as WANode[]
|
||||||
|
|
||||||
if (messages) {
|
if (messages) {
|
||||||
@@ -133,6 +134,8 @@ export class WAConnection extends Base {
|
|||||||
|
|
||||||
this.deregisterCallback(['response', 'type:chat'])
|
this.deregisterCallback(['response', 'type:chat'])
|
||||||
|
|
||||||
|
this.log ('received chats list', MessageLogLevel.info)
|
||||||
|
|
||||||
if (this.chats.all().length > 0) waitForConvos().then (resolve)
|
if (this.chats.all().length > 0) waitForConvos().then (resolve)
|
||||||
else resolve ()
|
else resolve ()
|
||||||
})
|
})
|
||||||
@@ -157,6 +160,8 @@ export class WAConnection extends Base {
|
|||||||
resolve ()
|
resolve ()
|
||||||
|
|
||||||
this.deregisterCallback(['response', 'type:contacts'])
|
this.deregisterCallback(['response', 'type:contacts'])
|
||||||
|
|
||||||
|
this.log ('received contacts list', MessageLogLevel.info)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@@ -259,6 +264,7 @@ export class WAConnection extends Base {
|
|||||||
try {
|
try {
|
||||||
await this.connect ()
|
await this.connect ()
|
||||||
this.cancelReconnect = null
|
this.cancelReconnect = null
|
||||||
|
break
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.log (`error in reconnecting: ${error}, reconnecting...`, MessageLogLevel.info)
|
this.log (`error in reconnecting: ${error}, reconnecting...`, MessageLogLevel.info)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ export class WAConnection extends Base {
|
|||||||
}
|
}
|
||||||
protected registerPhoneConnectionPoll () {
|
protected registerPhoneConnectionPoll () {
|
||||||
this.phoneCheck = setInterval (() => {
|
this.phoneCheck = setInterval (() => {
|
||||||
this.checkPhoneConnection (7500) // 7500 ms for timeout
|
this.checkPhoneConnection (5000) // 5000 ms for timeout
|
||||||
.then (connected => {
|
.then (connected => {
|
||||||
if (this.phoneConnected != connected) {
|
if (this.phoneConnected != connected) {
|
||||||
this.emit ('connection-phone-change', {connected})
|
this.emit ('connection-phone-change', {connected})
|
||||||
@@ -269,7 +269,7 @@ export class WAConnection extends Base {
|
|||||||
this.phoneConnected = connected
|
this.phoneConnected = connected
|
||||||
})
|
})
|
||||||
.catch (error => this.log(`error in getting phone connection: ${error}`, MessageLogLevel.info))
|
.catch (error => this.log(`error in getting phone connection: ${error}`, MessageLogLevel.info))
|
||||||
}, 20000)
|
}, 15000)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all event types
|
// Add all event types
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export class WAConnection extends Base {
|
|||||||
/** Get the invite link of the given group */
|
/** Get the invite link of the given group */
|
||||||
async groupInviteCode(jid: string) {
|
async groupInviteCode(jid: string) {
|
||||||
const json = ['query', 'inviteCode', jid]
|
const json = ['query', 'inviteCode', jid]
|
||||||
const response = await this.query({json})
|
const response = await this.query({json, expect200: true})
|
||||||
return response.code as string
|
return response.code as string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user