diff --git a/src/Tests/Tests.Connect.ts b/src/Tests/Tests.Connect.ts index a18d011..267b768 100644 --- a/src/Tests/Tests.Connect.ts +++ b/src/Tests/Tests.Connect.ts @@ -71,16 +71,6 @@ describe('Test Connect', () => { )) .finally (() => conn.close()) }) -}) -describe ('Reconnects', () => { - const verifyConnectionOpen = async (conn: WAConnection) => { - // check that the connection stays open - conn.on ('close', ({reason}) => ( - reason !== DisconnectReason.intentional && assert.fail ('should not have closed again') - )) - await delay (60*1000) - conn.close () - } it ('should disconnect & reconnect phone', async () => { const conn = new WAConnection () await conn.loadAuthInfo('./auth_info.json').connect () @@ -103,6 +93,16 @@ describe ('Reconnects', () => { conn.close () } }) +}) +describe ('Reconnects', () => { + const verifyConnectionOpen = async (conn: WAConnection) => { + // check that the connection stays open + conn.on ('close', ({reason}) => ( + reason !== DisconnectReason.intentional && assert.fail ('should not have closed again') + )) + await delay (60*1000) + conn.close () + } /** * the idea is to test closing the connection at multiple points in the connection * and see if the library cleans up resources correctly @@ -125,19 +125,13 @@ describe ('Reconnects', () => { // exponentially increase the timeout disconnect timeout *= 2 } - conn.on ('close', ({reason}) => ( - // with v fast successive connections, WA sometimes incorrectly classifies a connection as taken over - (reason !== DisconnectReason.intentional && reason !== DisconnectReason.replaced) && - assert.fail ('should not have closed again') - )) - await delay (90*1000) - conn.close () + await verifyConnectionOpen (conn) }) /** * the idea is to test closing the connection at multiple points in the connection * and see if the library cleans up resources correctly */ - it('should cleanup correctly 2', async () => { + it('should disrupt connect loop', async () => { const conn = new WAConnection() conn.autoReconnect = ReconnectMode.onAllErrors conn.connectOptions.timeoutMs = 20000 @@ -217,36 +211,6 @@ describe ('Reconnects', () => { conn.close () } }) - it ('should disrupt connect loop', async () => { - const conn = new WAConnection () - conn.loadAuthInfo ('./auth_info.json') - conn.connectOptions.maxRetries = 20 - conn.connectOptions.timeoutMs = 20*1000 - - delay (3000) - .then (() => conn.close()) - - await assert.rejects( conn.connect () ) - - console.log ('rejected correctly') - - delay (3000) - .then (() => conn['conn'].terminate()) - .then (async () => { - while (conn['conn']) { - await delay(100) - } - console.log ('destroyed WS') - }) - .then (() => delay(5000)) - .then (() => conn['conn'].terminate()) - - await conn.connect () - - console.log ('opened connection') - - await verifyConnectionOpen (conn) - }) it ('should reconnect & stay connected', async () => { const conn = new WAConnection () conn.autoReconnect = ReconnectMode.onConnectionLost diff --git a/src/WAConnection/0.Base.ts b/src/WAConnection/0.Base.ts index a64e8f0..68eecb9 100644 --- a/src/WAConnection/0.Base.ts +++ b/src/WAConnection/0.Base.ts @@ -42,7 +42,8 @@ export class WAConnection extends EventEmitter { connectOptions: WAConnectOptions = { timeoutMs: 60*1000, waitForChats: true, - maxRetries: 5 + maxRetries: 5, + connectCooldownMs: 5000 } /** When to auto-reconnect */ autoReconnect = ReconnectMode.onConnectionLost @@ -70,7 +71,8 @@ export class WAConnection extends EventEmitter { protected lastSeen: Date = null // last keep alive received protected qrTimeout: NodeJS.Timeout - protected lastDisconnectReason: DisconnectReason + protected lastConnectTime: Date = null + protected lastDisconnectReason: DisconnectReason constructor () { super () @@ -311,7 +313,6 @@ export class WAConnection extends EventEmitter { this.msgCount = 0 this.phoneConnected = false this.lastDisconnectReason = reason - this.endConnection () @@ -319,14 +320,14 @@ export class WAConnection extends EventEmitter { this.pendingRequests.forEach (({reject}) => reject(new Error('close'))) this.pendingRequests = [] } - - // reconnecting if the timeout is active for the reconnect loop this.emit ('close', { reason, isReconnecting }) } protected endConnection () { this.conn?.removeAllListeners ('close') - this.conn?.close() + this.conn?.removeAllListeners ('message') + this.conn?.close () + this.conn?.terminate() this.conn = null this.lastSeen = null diff --git a/src/WAConnection/3.Connect.ts b/src/WAConnection/3.Connect.ts index dff2e3a..1e536dc 100644 --- a/src/WAConnection/3.Connect.ts +++ b/src/WAConnection/3.Connect.ts @@ -18,8 +18,11 @@ export class WAConnection extends Base { while (this.state === 'connecting') { tries += 1 try { - // if the first try failed, delay & connect again - await this.connectInternal (options, tries > 1 && 2000) + const diff = this.lastConnectTime ? new Date().getTime()-this.lastConnectTime.getTime() : Infinity + await this.connectInternal ( + options, + diff > this.connectOptions.connectCooldownMs ? 0 : this.connectOptions.connectCooldownMs + ) this.phoneConnected = true this.state = 'open' @@ -34,6 +37,8 @@ export class WAConnection extends Base { } if (!willReconnect) throw error + } finally { + this.lastConnectTime = new Date() } } diff --git a/src/WAConnection/Constants.ts b/src/WAConnection/Constants.ts index da4ba82..377ebf3 100644 --- a/src/WAConnection/Constants.ts +++ b/src/WAConnection/Constants.ts @@ -65,6 +65,8 @@ export type WAConnectOptions = { maxRetries?: number /** should the chats be waited for */ waitForChats?: boolean + + connectCooldownMs?: number } export type WAConnectionState = 'open' | 'connecting' | 'close' diff --git a/src/WAConnection/Utils.ts b/src/WAConnection/Utils.ts index 1500df3..65fdf54 100644 --- a/src/WAConnection/Utils.ts +++ b/src/WAConnection/Utils.ts @@ -123,7 +123,7 @@ export const openWebSocketConnection = (timeoutMs: number, retryOnNetworkError: try { const ws = await newWS() if (cancelled) { - ws.close () + ws.terminate () break } else return ws } catch (error) {