diff --git a/src/client/Client.js b/src/client/Client.js index b2a1b6afd..eccab6df5 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -148,6 +148,13 @@ class Client extends EventEmitter { */ this.readyAt = null; + /** + * The previous heartbeat pings of the websocket (most recent first, limited to three elements) + * @type {number[]} + */ + this.pings = []; + + this._pingTimestamp = 0; this._timeouts = new Set(); this._intervals = new Set(); @@ -174,6 +181,15 @@ class Client extends EventEmitter { return this.readyAt ? Date.now() - this.readyAt : null; } + /** + * The average heartbeat ping of the websocket + * @type {number} + * @readonly + */ + get ping() { + return this.pings.reduce((prev, p) => prev + p, 0) / this.pings.length; + } + /** * Returns a collection, mapping guild ID to voice connections. * @type {Collection} @@ -392,6 +408,11 @@ class Client extends EventEmitter { this._intervals.delete(interval); } + _pong(startTime) { + this.pings.unshift(Date.now() - startTime); + if (this.pings.length > 3) this.pings.length = 3; + } + _setPresence(id, presence) { if (this.presences.get(id)) { this.presences.get(id).update(presence); diff --git a/src/client/ClientManager.js b/src/client/ClientManager.js index 2d1ae7ef1..6e5ea5159 100644 --- a/src/client/ClientManager.js +++ b/src/client/ClientManager.js @@ -50,6 +50,7 @@ class ClientManager { setupKeepAlive(time) { this.heartbeatInterval = this.client.setInterval(() => { this.client.emit('debug', 'Sending heartbeat'); + this.client._pingTimestamp = Date.now(); this.client.ws.send({ op: Constants.OPCodes.HEARTBEAT, d: this.client.ws.sequence, diff --git a/src/client/websocket/packets/WebSocketPacketManager.js b/src/client/websocket/packets/WebSocketPacketManager.js index 9b3f04d31..099579912 100644 --- a/src/client/websocket/packets/WebSocketPacketManager.js +++ b/src/client/websocket/packets/WebSocketPacketManager.js @@ -82,7 +82,10 @@ class WebSocketPacketManager { return false; } - if (packet.op === Constants.OPCodes.HEARTBEAT_ACK) this.ws.client.emit('debug', 'Heartbeat acknowledged'); + if (packet.op === Constants.OPCodes.HEARTBEAT_ACK) { + this.ws.client._pong(this.ws.client._pingTimestamp); + this.ws.client.emit('debug', 'Heartbeat acknowledged'); + } if (this.ws.status === Constants.Status.RECONNECTING) { this.ws.reconnecting = false;