diff --git a/src/client/websocket/WebSocketManager.js b/src/client/websocket/WebSocketManager.js index 71cbf93c0..becc570c8 100644 --- a/src/client/websocket/WebSocketManager.js +++ b/src/client/websocket/WebSocketManager.js @@ -245,6 +245,8 @@ class WebSocketManager extends EventEmitter { }); shard.on(ShardEvents.DESTROYED, () => { + shard._cleanupConnection(); + this.debug('Shard was destroyed but no WebSocket connection was present! Reconnecting...', shard); this.client.emit(Events.SHARD_RECONNECTING, shard.id); diff --git a/src/client/websocket/WebSocketShard.js b/src/client/websocket/WebSocketShard.js index 5171d7e59..1b7d5495b 100644 --- a/src/client/websocket/WebSocketShard.js +++ b/src/client/websocket/WebSocketShard.js @@ -208,11 +208,18 @@ class WebSocketShard extends EventEmitter { this.once(ShardEvents.INVALID_SESSION, onInvalid); if (this.connection && this.connection.readyState === WebSocket.OPEN) { - this.debug('Connection found, attempting an immediate identify.'); + this.debug('An open connection was found, attempting an immediate identify.'); this.identify(); return; } + if (this.connection) { + this.debug(`A connection was found. Cleaning up before continuing. + State: ${CONNECTION_STATE[this.connection.readyState]}`); + this._cleanupConnection(); + this.connection.close(1000); + } + const wsQuery = { v: client.options.ws.version }; if (zlib) { @@ -526,9 +533,9 @@ class WebSocketShard extends EventEmitter { } else if (!this.lastHeartbeatAcked) { this.debug( `[${tag}] Didn't receive a heartbeat ack last time, assuming zombie connection. Destroying and reconnecting. - Status : ${STATUS_KEYS[this.status]} - Sequence : ${this.sequence} - Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}` + Status : ${STATUS_KEYS[this.status]} + Sequence : ${this.sequence} + Connection State: ${this.connection ? CONNECTION_STATE[this.connection.readyState] : 'No Connection??'}` ); this.destroy(4009); return; @@ -629,7 +636,8 @@ class WebSocketShard extends EventEmitter { */ _send(data) { if (!this.connection || this.connection.readyState !== WebSocket.OPEN) { - this.debug(`Tried to send packet ${JSON.stringify(data)} but no WebSocket is available!`); + this.debug(`Tried to send packet ${JSON.stringify(data)} but no WebSocket is available! Resetting the shard...`); + this.destroy(4000); return; } @@ -667,6 +675,8 @@ class WebSocketShard extends EventEmitter { * @private */ destroy(closeCode = 1000, cleanup = false) { + this.debug(`Destroying with close code ${closeCode}, attempting a reconnect: ${!cleanup}`); + this.setHeartbeatTimer(-1); this.setHelloTimeout(-1); @@ -696,6 +706,17 @@ class WebSocketShard extends EventEmitter { this.ratelimit.timer = null; } } + + /** + * Cleans up the WebSocket connection listeners. + * @private + */ + _cleanupConnection() { + this.connection.onopen = + this.connection.onclose = + this.connection.onerror = + this.connection.onmessage = null; + } } module.exports = WebSocketShard; diff --git a/typings/index.d.ts b/typings/index.d.ts index 3d55cb97e..d4160b59c 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -1717,6 +1717,7 @@ declare module 'discord.js' { private _send(data: object): void; private processQueue(): void; private destroy(closeCode: number): void; + private _cleanupConnection(): void; public send(data: object): void; public on(event: 'ready', listener: () => void): this;