From 32e07422f314393298ef0c0ed3de4035b64697bd Mon Sep 17 00:00:00 2001 From: Skillz Date: Sun, 17 May 2020 09:28:39 -0400 Subject: [PATCH] bette error handling --- module/shard.ts | 165 ++++++++++++++++++++++++------------------------ 1 file changed, 83 insertions(+), 82 deletions(-) diff --git a/module/shard.ts b/module/shard.ts index 925e60ed8..60ba65cb3 100644 --- a/module/shard.ts +++ b/module/shard.ts @@ -12,13 +12,14 @@ import { import { logRed } from "../utils/logger.ts"; import { FetchMembersOptions } from "../types/guild.ts"; import { delay } from "https://deno.land/std@0.50.0/async/delay.ts"; + let shardSocket: WebSocket; /** The session id is needed for RESUME functionality when discord disconnects randomly. */ let sessionID = ""; // Discord requests null if no number has yet been sent by discord -export let previousSequenceNumber: number | null = null; +let previousSequenceNumber: number | null = null; let needToResume = false; // TODO: If a client does not receive a heartbeat ack between its attempts at sending heartbeats, it should immediately terminate the connection with a non-1000 close code, reconnect, and attempt to resume. @@ -43,7 +44,7 @@ async function resumeConnection( if (needToResume) resumeConnection(botGatewayData, identifyPayload); } -export const createShard = async ( +const createShard = async ( botGatewayData: DiscordBotGatewayData, identifyPayload: object, resuming = false, @@ -67,57 +68,64 @@ export const createShard = async ( })); } - try { - for await (const message of shardSocket) { - if (typeof message === "string") { - const data = JSON.parse(message); + for await (const message of shardSocket) { + if (typeof message === "string") { + const data = JSON.parse(message); - switch (data.op) { - case GatewayOpcode.Hello: - sendConstantHeartbeats( - (data.d as DiscordHeartbeatPayload).heartbeat_interval, - ); + switch (data.op) { + case GatewayOpcode.Hello: + sendConstantHeartbeats( + (data.d as DiscordHeartbeatPayload).heartbeat_interval, + ); + break; + case GatewayOpcode.Reconnect: + case GatewayOpcode.InvalidSession: + needToResume = true; + resumeConnection(botGatewayData, identifyPayload); + break; + default: + if (data.t === "RESUMED") { + needToResume = false; break; - case GatewayOpcode.Reconnect: - case GatewayOpcode.InvalidSession: - needToResume = true; - resumeConnection(botGatewayData, identifyPayload); - break; - default: - if (data.t === "RESUMED") { - needToResume = false; - break; - } - // Important for RESUME - if (data.t === "READY") { - sessionID = (data.d as ReadyPayload).session_id; - } + } + // Important for RESUME + if (data.t === "READY") { + sessionID = (data.d as ReadyPayload).session_id; + } - // Update the sequence number if it is present - if (data.s) previousSequenceNumber = data.s; + // Update the sequence number if it is present + if (data.s) previousSequenceNumber = data.s; - // @ts-ignore - postMessage( - { - type: "HANDLE_DISCORD_PAYLOAD", - payload: message, - resumeInterval, - }, - ); - break; - } - } else if (isWebSocketCloseEvent(message)) { - logRed(`Close :( ${JSON.stringify(message)}`); + // @ts-ignore + postMessage( + { + type: "HANDLE_DISCORD_PAYLOAD", + payload: message, + resumeInterval, + }, + ); + break; + } + } else if (isWebSocketCloseEvent(message)) { + logRed(`Close :( ${JSON.stringify(message)}`); + // These error codes should just crash the projects + if ([4004, 4005, 4012, 4013, 4014].includes(message.code)) { + throw new Error( + "Shard.ts: Error occurred that is not resumeable or able to be reconnected.", + ); + } + // These error codes can not be resumed but need to reconnect from start + if ([4003, 4007, 4008, 4009].includes(message.code)) { + createShard(botGatewayData, identifyPayload); + } else { needToResume = true; resumeConnection(botGatewayData, identifyPayload); } } - } catch (error) { - logRed(error); } }; -export function requestGuildMembers( +function requestGuildMembers( guildID: string, nonce: string, options?: FetchMembersOptions, @@ -135,46 +143,39 @@ export function requestGuildMembers( })); } -// TODO: Remove ts-ignore once https://github.com/denoland/deno/issues/5262 fixed +// TODO: Errors need to be fixed by VSC plugin +postMessage({ type: "REQUEST_CLIENT_OPTIONS" }); // @ts-ignore -if (typeof self.postMessage === "function") { - // @ts-ignore - postMessage({ type: "REQUEST_CLIENT_OPTIONS" }); -} -// @ts-ignore -if (typeof self.onmessage === "function") { - // @ts-ignore - onmessage = (message) => { - if (message.data.type === "CREATE_SHARD") { - createShard( - message.data.botGatewayData, - message.data.identifyPayload, - ); - } +onmessage = (message: MessageEvent) => { + if (message.data.type === "CREATE_SHARD") { + createShard( + message.data.botGatewayData, + message.data.identifyPayload, + ); + } - if (message.data.type === "FETCH_MEMBERS") { - requestGuildMembers( - message.data.guildID, - message.data.nonce, - message.data.options, - ); - } + if (message.data.type === "FETCH_MEMBERS") { + requestGuildMembers( + message.data.guildID, + message.data.nonce, + message.data.options, + ); + } - if (message.data.type === "EDIT_BOTS_STATUS") { - shardSocket.send(JSON.stringify({ - op: GatewayOpcode.StatusUpdate, - d: { - since: null, - game: message.data.game.name - ? { - name: message.data.game.name, - type: message.data.game.type, - } - : null, - status: message.data.status, - afk: false, - }, - })); - } - }; -} + if (message.data.type === "EDIT_BOTS_STATUS") { + shardSocket.send(JSON.stringify({ + op: GatewayOpcode.StatusUpdate, + d: { + since: null, + game: message.data.game.name + ? { + name: message.data.game.name, + type: message.data.game.type, + } + : null, + status: message.data.status, + afk: false, + }, + })); + } +};