diff --git a/src/client/websocket/WebSocketManager.js b/src/client/websocket/WebSocketManager.js index 41c7ea407..83324576b 100644 --- a/src/client/websocket/WebSocketManager.js +++ b/src/client/websocket/WebSocketManager.js @@ -4,6 +4,7 @@ const WebSocket = require('ws'); const Constants = require('../../util/Constants'); const zlib = require('zlib'); const PacketManager = require('./packets/WebSocketPacketManager'); +const WebSocketManagerDataStore = require('../../structures/datastore/WebSocketManagerDataStore'); class WebSocketManager { @@ -12,9 +13,12 @@ class WebSocketManager { this.ws = null; this.packetManager = new PacketManager(this); this.emittedReady = false; + this.store = new WebSocketManagerDataStore(); + this.reconnecting = false; } connect(gateway) { + this.store.gateway = gateway; gateway += `/?v=${this.client.options.protocol_version}`; this.ws = new WebSocket(gateway); this.ws.onopen = () => this.EventOpen(); @@ -24,10 +28,34 @@ class WebSocketManager { } send(data) { - this.ws.send(JSON.stringify(data)); + if (this.ws.readyState === WebSocket.OPEN) { + this.ws.send(JSON.stringify(data)); + } } EventOpen() { + if (this.reconnecting) { + this._sendResume(); + } else { + this._sendNewIdentify(); + } + } + + _sendResume() { + let payload = { + token: this.client.store.token, + session_id: this.store.sessionID, + seq: this.store.sequence, + }; + + this.send({ + op: Constants.OPCodes.RESUME, + d: payload, + }); + } + + _sendNewIdentify() { + this.reconnecting = false; let payload = this.client.options.ws; payload.token = this.client.store.token; @@ -38,7 +66,9 @@ class WebSocketManager { } EventClose() { - + if (!this.reconnecting) { + this.tryReconnect(); + } } EventMessage(event) { @@ -57,7 +87,7 @@ class WebSocketManager { } EventError(e) { - + this.tryReconnect(); } checkIfReady() { @@ -75,6 +105,15 @@ class WebSocketManager { } } } + + tryReconnect() { + this.reconnecting = true; + this.ws.close(); + this.packetManager.handleQueue(); + this.client.emit(Constants.Events.RECONNECTING); + this.emittedReady = false; + this.connect(this.store.gateway); + } } module.exports = WebSocketManager; diff --git a/src/client/websocket/packets/WebSocketPacketManager.js b/src/client/websocket/packets/WebSocketPacketManager.js index 8e0341757..2f01da2a7 100644 --- a/src/client/websocket/packets/WebSocketPacketManager.js +++ b/src/client/websocket/packets/WebSocketPacketManager.js @@ -8,8 +8,6 @@ const BeforeReadyWhitelist = [ Constants.WSEvents.GUILD_DELETE, ]; -var amount = 0; - class WebSocketPacketManager { constructor(websocketManager) { @@ -58,8 +56,32 @@ class WebSocketPacketManager { } } + setSequence(s) { + if (s && s > this.ws.store.sequence) { + this.ws.store.sequence = s; + } + } + handle(packet) { - amount++; + + if (packet.op === Constants.OPCodes.RECONNECT) { + this.setSequence(packet.s); + this.ws.tryReconnect(); + return; + } + + if (packet.op === Constants.OPCodes.INVALID_SESSION) { + this.ws._sendNewIdentify(); + return; + } + + if (this.ws.reconnecting) { + this.ws.reconnecting = false; + this.ws.checkIfReady(); + } + + this.setSequence(packet.s); + if (!this.ws.emittedReady) { if (BeforeReadyWhitelist.indexOf(packet.t) === -1) { this.queue.push(packet); diff --git a/src/client/websocket/packets/handlers/Ready.js b/src/client/websocket/packets/handlers/Ready.js index b5bd514f3..ffd4cd0cb 100644 --- a/src/client/websocket/packets/handlers/Ready.js +++ b/src/client/websocket/packets/handlers/Ready.js @@ -28,6 +28,8 @@ class ReadyHandler extends AbstractHandler { client.store.NewChannel(privateDM); } + this.packetManager.ws.store.sessionID = data.session_id; + this.packetManager.ws.checkIfReady(); } diff --git a/src/structures/datastore/WebSocketManagerDataStore.js b/src/structures/datastore/WebSocketManagerDataStore.js new file mode 100644 index 000000000..a63d41369 --- /dev/null +++ b/src/structures/datastore/WebSocketManagerDataStore.js @@ -0,0 +1,14 @@ +'use strict'; + +const AbstractDataStore = require('./AbstractDataStore'); + +class WebSocketManagerDataStore extends AbstractDataStore{ + constructor() { + super(); + this.sessionID = null; + this.sequence = -1; + this.gateway = null; + } +} + +module.exports = WebSocketManagerDataStore; diff --git a/test/random.js b/test/random.js index 64575e0c5..8e4b8e315 100644 --- a/test/random.js +++ b/test/random.js @@ -4,9 +4,10 @@ const Discord = require('../'); let client = new Discord.Client(); -client.login(require('./auth.json').token).then(token => console.log('ready!')).catch(console.log); +client.login(require('./auth.json').token).then(token => console.log('logged in with token ' + token)).catch(console.log); client.on('ready', () => { + console.log('ready!'); }); client.on('guildCreate', (guild) => {