mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
65 lines
2.7 KiB
TypeScript
65 lines
2.7 KiB
TypeScript
import { GatewayOpcodes } from "../../types/shared.ts";
|
|
import { Shard, ShardSocketCloseCodes, ShardState } from "./types.ts";
|
|
|
|
export function startHeartbeating(shard: Shard, interval: number) {
|
|
// gateway.debug("GW HEARTBEATING_STARTED", { shardId, interval });
|
|
|
|
shard.heart.interval = interval;
|
|
|
|
// Only set the shard's state to `Unidentified`
|
|
// if heartbeating has not been started due to an identify or resume action.
|
|
if ([ShardState.Disconnected, ShardState.Offline].includes(shard.state)) {
|
|
shard.state = ShardState.Unidentified;
|
|
}
|
|
|
|
// The first heartbeat needs to be send with a random delay between `0` and `interval`
|
|
// Using a `setTimeout(_, jitter)` here to accomplish that.
|
|
// `Math.random()` can be `0` so we use `0.5` if this happens
|
|
// Reference: https://discord.com/developers/docs/topics/gateway#heartbeating
|
|
const jitter = Math.ceil(shard.heart.interval * (Math.random() || 0.5));
|
|
shard.heart.timeoutId = setTimeout(() => {
|
|
// Using a direct socket.send call here because heartbeat requests are reserved by us.
|
|
shard.socket?.send(JSON.stringify({
|
|
op: GatewayOpcodes.Heartbeat,
|
|
d: shard.previousSequenceNumber,
|
|
}));
|
|
|
|
shard.heart.lastBeat = Date.now();
|
|
shard.heart.acknowledged = false;
|
|
|
|
// After the random heartbeat jitter we can start a normal interval.
|
|
shard.heart.intervalId = setInterval(async () => {
|
|
// gateway.debug("GW DEBUG", `Running setInterval in heartbeat file. Shard: ${shardId}`);
|
|
|
|
// gateway.debug("GW HEARTBEATING", { shardId, shard: currentShard });
|
|
|
|
// The Shard did not receive a heartbeat ACK from Discord in time,
|
|
// therefore we have to assume that the connection has failed or got "zombied".
|
|
// The Shard needs to start a re-identify action accordingly.
|
|
// Reference: https://discord.com/developers/docs/topics/gateway#heartbeating-example-gateway-heartbeat-ack
|
|
if (!shard.heart.acknowledged) {
|
|
shard.close(
|
|
ShardSocketCloseCodes.ZombiedConnection,
|
|
"Zombied connection, did not receive an heartbeat ACK in time.",
|
|
);
|
|
|
|
return await shard.identify();
|
|
}
|
|
|
|
shard.heart.acknowledged = false;
|
|
|
|
// Using a direct socket.send call here because heartbeat requests are reserved by us.
|
|
shard.socket?.send(
|
|
JSON.stringify({
|
|
op: GatewayOpcodes.Heartbeat,
|
|
d: shard.previousSequenceNumber,
|
|
}),
|
|
);
|
|
|
|
shard.heart.lastBeat = Date.now();
|
|
|
|
shard.events.heartbeat?.(shard);
|
|
}, shard.heart.interval);
|
|
}, jitter);
|
|
}
|