mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 05:32:09 +03:00
133 lines
4.1 KiB
TypeScript
133 lines
4.1 KiB
TypeScript
// Loaded from https://deno.land/x/discordeno@11.0.0-rc.2/src/ws/handle_on_message.ts
|
|
|
|
|
|
import { eventHandlers } from "../bot.ts";
|
|
import { handlers } from "../handlers/mod.ts";
|
|
import { DiscordGatewayOpcodes } from "../types/codes/gateway_opcodes.ts";
|
|
import type { DiscordGatewayPayload } from "../types/gateway/gateway_payload.ts";
|
|
import type { DiscordHello } from "../types/gateway/hello.ts";
|
|
import type { DiscordReady } from "../types/gateway/ready.ts";
|
|
import { camelize, delay } from "../util/utils.ts";
|
|
import { decompressWith } from "./deps.ts";
|
|
import { identify } from "./identify.ts";
|
|
import { resume } from "./resume.ts";
|
|
import { ws } from "./ws.ts";
|
|
|
|
/** Handler for handling every message event from websocket. */
|
|
// deno-lint-ignore no-explicit-any
|
|
export async function handleOnMessage(message: any, shardId: number) {
|
|
if (message instanceof ArrayBuffer) {
|
|
message = new Uint8Array(message);
|
|
}
|
|
|
|
if (message instanceof Uint8Array) {
|
|
message = decompressWith(message, 0, (slice: Uint8Array) => ws.utf8decoder.decode(slice));
|
|
}
|
|
|
|
if (typeof message !== "string") return;
|
|
|
|
const shard = ws.shards.get(shardId);
|
|
|
|
const messageData = JSON.parse(message) as DiscordGatewayPayload;
|
|
ws.log("RAW", { shardId, payload: messageData });
|
|
|
|
switch (messageData.op) {
|
|
case DiscordGatewayOpcodes.Heartbeat:
|
|
if (shard?.ws.readyState !== WebSocket.OPEN) return;
|
|
|
|
shard.heartbeat.lastSentAt = Date.now();
|
|
// Discord randomly sends this requiring an immediate heartbeat back
|
|
ws.sendShardMessage(
|
|
shard,
|
|
{
|
|
op: DiscordGatewayOpcodes.Heartbeat,
|
|
d: shard?.previousSequenceNumber,
|
|
},
|
|
true
|
|
);
|
|
break;
|
|
case DiscordGatewayOpcodes.Hello:
|
|
ws.heartbeat(shardId, (messageData.d as DiscordHello).heartbeat_interval);
|
|
break;
|
|
case DiscordGatewayOpcodes.HeartbeatACK:
|
|
if (ws.shards.has(shardId)) {
|
|
ws.shards.get(shardId)!.heartbeat.acknowledged = true;
|
|
}
|
|
break;
|
|
case DiscordGatewayOpcodes.Reconnect:
|
|
ws.log("RECONNECT", { shardId });
|
|
|
|
if (ws.shards.has(shardId)) {
|
|
ws.shards.get(shardId)!.resuming = true;
|
|
}
|
|
|
|
await resume(shardId);
|
|
break;
|
|
case DiscordGatewayOpcodes.InvalidSession:
|
|
ws.log("INVALID_SESSION", { shardId, payload: messageData });
|
|
|
|
// We need to wait for a random amount of time between 1 and 5: https://discord.com/developers/docs/topics/gateway#resuming
|
|
await delay(Math.floor((Math.random() * 4 + 1) * 1000));
|
|
|
|
// When d is false we need to reidentify
|
|
if (!messageData.d) {
|
|
await identify(shardId, ws.maxShards);
|
|
break;
|
|
}
|
|
|
|
if (ws.shards.has(shardId)) {
|
|
ws.shards.get(shardId)!.resuming = true;
|
|
}
|
|
|
|
await resume(shardId);
|
|
break;
|
|
default:
|
|
if (messageData.t === "RESUMED") {
|
|
ws.log("RESUMED", { shardId });
|
|
|
|
if (ws.shards.has(shardId)) {
|
|
ws.shards.get(shardId)!.resuming = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Important for RESUME
|
|
if (messageData.t === "READY") {
|
|
const shard = ws.shards.get(shardId);
|
|
if (shard) {
|
|
shard.sessionId = (messageData.d as DiscordReady).session_id;
|
|
}
|
|
|
|
ws.loadingShards.get(shardId)?.resolve(true);
|
|
ws.loadingShards.delete(shardId);
|
|
// Wait 5 seconds to spawn next shard
|
|
setTimeout(() => {
|
|
const bucket = ws.buckets.get(shardId % ws.botGatewayData.sessionStartLimit.maxConcurrency);
|
|
if (bucket) bucket.createNextShard = true;
|
|
}, 5000);
|
|
}
|
|
|
|
// Update the sequence number if it is present
|
|
if (messageData.s) {
|
|
const shard = ws.shards.get(shardId);
|
|
if (shard) {
|
|
shard.previousSequenceNumber = messageData.s;
|
|
}
|
|
}
|
|
|
|
if (ws.url) await ws.handleDiscordPayload(messageData, shardId);
|
|
else {
|
|
eventHandlers.raw?.(messageData);
|
|
await eventHandlers.dispatchRequirements?.(messageData, shardId);
|
|
|
|
if (messageData.op !== DiscordGatewayOpcodes.Dispatch) return;
|
|
|
|
if (!messageData.t) return;
|
|
|
|
return handlers[messageData.t]?.(camelize(messageData), shardId);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|