heartbeat change

This commit is contained in:
ITOH
2021-04-15 14:25:26 +02:00
parent f5d6a85882
commit 2c97964f0f
5 changed files with 48 additions and 52 deletions
+15 -22
View File
@@ -1,8 +1,9 @@
import { DiscordGatewayOpcodes } from "../types/codes/gateway_opcodes.ts"; import { DiscordGatewayOpcodes } from "../types/codes/gateway_opcodes.ts";
import { delay } from "../util/utils.ts";
import { identify } from "./identify.ts"; import { identify } from "./identify.ts";
import { ws } from "./ws.ts"; import { ws } from "./ws.ts";
export function heartbeat(shardId: number, interval: number) { export async function heartbeat(shardId: number, interval: number) {
ws.log("HEARTBEATING_STARTED", { shardId, interval }); ws.log("HEARTBEATING_STARTED", { shardId, interval });
const shard = ws.shards.get(shardId); const shard = ws.shards.get(shardId);
@@ -11,18 +12,20 @@ export function heartbeat(shardId: number, interval: number) {
ws.log("HEARTBEATING_DETAILS", { shardId, interval, shard }); ws.log("HEARTBEATING_DETAILS", { shardId, interval, shard });
shard.heartbeat.keepAlive = true; shard.heartbeat.keepAlive = true;
shard.heartbeat.acknowledged = true; shard.heartbeat.acknowledged = false;
shard.heartbeat.lastSentAt = Date.now(); shard.heartbeat.lastSentAt = Date.now();
shard.heartbeat.interval = interval; shard.heartbeat.interval = interval;
// The first heartbeat should not wait for the entire interval to pass: https://discord.com/developers/docs/topics/gateway#heartbeating // The first heartbeat is special so we send it without setInterval: https://discord.com/developers/docs/topics/gateway#heartbeating
shard.heartbeat.timeoutId = setTimeout( await delay(Math.floor(shard.heartbeat.interval * Math.random()));
() => sendHeartbeat(shardId),
Math.floor(shard.heartbeat.interval * Math.random()),
);
}
function sendHeartbeat(shardId: number) { shard.queue.unshift({
op: DiscordGatewayOpcodes.Heartbeat,
d: shard.previousSequenceNumber,
});
ws.processQueue(shard.id);
shard.heartbeat.intervalId = setInterval(() => {
ws.log("DEBUG", `Running setInterval in heartbeat file.`); ws.log("DEBUG", `Running setInterval in heartbeat file.`);
const currentShard = ws.shards.get(shardId); const currentShard = ws.shards.get(shardId);
if (!currentShard) return; if (!currentShard) return;
@@ -36,7 +39,7 @@ function sendHeartbeat(shardId: number) {
ws.log("HEARTBEATING_CLOSED", { shardId, shard: currentShard }); ws.log("HEARTBEATING_CLOSED", { shardId, shard: currentShard });
// STOP THE HEARTBEAT // STOP THE HEARTBEAT
return; return clearInterval(shard.heartbeat.intervalId);
} }
if (!currentShard.heartbeat.acknowledged) { if (!currentShard.heartbeat.acknowledged) {
@@ -44,13 +47,7 @@ function sendHeartbeat(shardId: number) {
return identify(shardId, ws.maxShards); return identify(shardId, ws.maxShards);
} }
if (currentShard.ws.readyState !== WebSocket.OPEN) { if (currentShard.ws.readyState !== WebSocket.OPEN) return;
currentShard.heartbeat.timeoutId = setTimeout(
() => sendHeartbeat(shardId),
currentShard.heartbeat.interval,
);
return;
}
currentShard.ws.send(JSON.stringify({ currentShard.ws.send(JSON.stringify({
op: DiscordGatewayOpcodes.Heartbeat, op: DiscordGatewayOpcodes.Heartbeat,
@@ -58,9 +55,5 @@ function sendHeartbeat(shardId: number) {
})); }));
currentShard.heartbeat.acknowledged = false; currentShard.heartbeat.acknowledged = false;
}, shard.heartbeat.interval);
currentShard.heartbeat.timeoutId = setTimeout(
() => sendHeartbeat(shardId),
currentShard.heartbeat.interval,
);
} }
+5 -2
View File
@@ -7,7 +7,10 @@ export async function identify(shardId: number, maxShards: number) {
// Need to clear the old heartbeat interval // Need to clear the old heartbeat interval
const oldShard = ws.shards.get(shardId); const oldShard = ws.shards.get(shardId);
if (oldShard) { if (oldShard) {
clearTimeout(oldShard.heartbeat.timeoutId); if (oldShard.ws.readyState === WebSocket.OPEN) {
oldShard.ws.close(3065, "Reidentifying closure of old shard");
}
clearInterval(oldShard.heartbeat.intervalId);
} }
// CREATE A SHARD // CREATE A SHARD
@@ -29,7 +32,7 @@ export async function identify(shardId: number, maxShards: number) {
acknowledged: false, acknowledged: false,
keepAlive: false, keepAlive: false,
interval: 0, interval: 0,
timeoutId: 0, intervalId: 0,
}, },
queue: [], queue: [],
processingQueue: false, processingQueue: false,
+2 -2
View File
@@ -19,7 +19,7 @@ export async function resume(shardId: number) {
oldShard.ws.close(3065, "Resuming the shard, closing old shard."); oldShard.ws.close(3065, "Resuming the shard, closing old shard.");
} }
// STOP OLD HEARTBEAT // STOP OLD HEARTBEAT
clearTimeout(oldShard.heartbeat.timeoutId); clearInterval(oldShard.heartbeat.intervalId);
ws.shards.set(shardId, { ws.shards.set(shardId, {
id: shardId, id: shardId,
@@ -36,7 +36,7 @@ export async function resume(shardId: number) {
acknowledged: false, acknowledged: false,
keepAlive: false, keepAlive: false,
interval: 0, interval: 0,
timeoutId: 0, intervalId: 0,
}, },
queue: oldShard.queue || [], queue: oldShard.queue || [],
processingQueue: false, processingQueue: false,
+1 -1
View File
@@ -143,7 +143,7 @@ export interface DiscordenoShard {
/** The interval between heartbeats requested by discord. */ /** The interval between heartbeats requested by discord. */
interval: number; interval: number;
/** The id of the interval, useful for stopping the interval if ws closed. */ /** The id of the interval, useful for stopping the interval if ws closed. */
timeoutId: number; intervalId: number;
}; };
/** The items/requestst that are in queue to be sent to this shard websocket. */ /** The items/requestst that are in queue to be sent to this shard websocket. */
queue: WebSocketRequest[]; queue: WebSocketRequest[];
+1 -1
View File
@@ -7,7 +7,7 @@ Deno.test({
name: "[ws] Close all shards manually.", name: "[ws] Close all shards manually.",
async fn() { async fn() {
ws.shards.forEach((shard) => { ws.shards.forEach((shard) => {
clearTimeout(shard.heartbeat.timeoutId); clearInterval(shard.heartbeat.intervalId);
shard.ws.close(3064, "Discordeno Testing Finished! Do Not RESUME!"); shard.ws.close(3064, "Discordeno Testing Finished! Do Not RESUME!");
}); });