more cleanup

This commit is contained in:
Skillz
2020-04-27 11:48:49 -04:00
parent c3021535ce
commit 43b85f4e03
5 changed files with 43 additions and 59 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
# Discordeno
Discord API library wrapper in Deno
[Discord Server](https://discord.gg/rFJzqex)
[Discord Server](https://discord.gg/J4NqJ72)
## Bot Boilerplate Template / Frameworks
+26 -44
View File
@@ -8,12 +8,12 @@ import {
Presence_Update_Payload,
Typing_Start_Payload,
Voice_State_Update_Payload,
ReadyPayload,
} from "../types/discord.ts"
// import { spawnShards } from "./sharding_manager.ts"
import { connectWebSocket, isWebSocketCloseEvent, WebSocket } from "https://deno.land/std@v0.41.0/ws/mod.ts"
import { Client_Options, Event_Handlers } from "../types/options.ts"
import { CollectedMessageType } from "../types/message-type.ts"
import { send_constant_heartbeats, update_previous_sequence_number } from "./gateway.ts"
import { send_constant_heartbeats, update_previous_sequence_number, previous_sequence_number } from "./gateway.ts"
import { create_guild } from "../structures/guild.ts"
import {
handle_internal_guild_create,
@@ -67,6 +67,8 @@ export let authorization = ""
export let bot_id = ""
/** The bot's token. This should never be used by end users. It is meant to be used internally to make requests to the Discord API. */
export let token = ""
/** The session id is needed for RESUME functionality when discord disconnects randomly. */
export let sessionID = ""
export let event_handlers: Event_Handlers = {}
export const create_client = async (data: Client_Options) => {
@@ -83,8 +85,7 @@ export const create_client = async (data: Client_Options) => {
// Initial API connection to get info about bots connection
const bot_gateway_data = (await Request_Manager.get(endpoints.GATEWAY_BOT)) as DiscordBotGatewayData
const socket = await connectWebSocket(bot_gateway_data.url)
collect_messages(socket)
let socket = await connectWebSocket(bot_gateway_data.url)
const payload = {
token: data.token,
@@ -97,50 +98,30 @@ export const create_client = async (data: Client_Options) => {
// Intial identify with the gateway
await socket.send(JSON.stringify({ op: GatewayOpcode.Identify, d: payload }))
for await (const _message of connect(socket)) {
for await (const message of socket.receive()) {
if (typeof message === "string") {
handle_discord_payload(JSON.parse(message), socket)
} else if (isWebSocketCloseEvent(message)) {
logRed(`Close :( ${message}`)
// RESUME: Websocket closed/disconnected so we should try and resume the connection.
socket = await connectWebSocket(bot_gateway_data.url)
await socket.send(
JSON.stringify({
op: GatewayOpcode.Resume,
d: {
token: data.token,
session_id: sessionID,
seq: previous_sequence_number,
},
})
)
}
}
// spawnShards(bot_gateway_data, 1, socket, payload)
}
async function* collect_messages(socket: WebSocket) {
for await (const message of socket.receive()) {
if (typeof message === "string") {
yield {
type: CollectedMessageType.Message,
data: JSON.parse(message),
}
} else if (isWebSocketCloseEvent(message)) {
yield { type: CollectedMessageType.Close, ...message }
return
}
}
}
/** Begins initial handshake, creates the websocket with Discord and spawns all necessary shards. */
async function* connect(socket: WebSocket) {
for await (const message of collect_messages(socket)) {
switch (message.type) {
case CollectedMessageType.Ping:
logRed("Ping!")
yield message
break
case CollectedMessageType.Pong:
logRed("Pong!")
yield message
break
case CollectedMessageType.Close:
logRed(`Close :( ${message}`)
yield message
break
case CollectedMessageType.Message:
handle_discord_payload(message.data, socket)
yield message
break
}
}
}
function handle_discord_payload(data: DiscordPayload, socket: WebSocket) {
// Update the sequence number if it is present so that heartbeating can be accurate
if (data.s) update_previous_sequence_number(data.s)
@@ -153,11 +134,12 @@ function handle_discord_payload(data: DiscordPayload, socket: WebSocket) {
// Incase the user wants to listen to heartbeat responses
return event_handlers.heartbeat?.()
case GatewayOpcode.Reconnect:
case GatewayOpcode.InvalidSession:
// TODO: Reconnect to the gateway https://discordapp.com/developers/docs/topics/gateway#reconnect
return
case GatewayOpcode.Dispatch:
if (data.t === "READY") {
console.debug(data)
sessionID = (data.d as ReadyPayload).session_id
return event_handlers.ready?.()
}
if (data.t === "CHANNEL_CREATE") return handle_internal_channel_create(data.d as Channel_Create_Payload)
+1 -1
View File
@@ -3,7 +3,7 @@ import { GatewayOpcode } from "../types/discord.ts"
import { delay } from "https://deno.land/std@v0.41.0/util/async.ts"
// Discord requests null if no number has yet been sent by discord
let previous_sequence_number: number | null = null
export let previous_sequence_number: number | null = null
// 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.
export const send_constant_heartbeats = async (socket: WebSocket, interval: number) => {
+14 -7
View File
@@ -45,7 +45,7 @@ export enum GatewayOpcode {
RequestGuildMembers,
InvalidSession,
Hello,
HeartbeatACK
HeartbeatACK,
}
export enum GatewayCloseEventCode {
@@ -59,7 +59,7 @@ export enum GatewayCloseEventCode {
RateLimited,
SessionTimeout,
InvalidShard,
ShardingRequired
ShardingRequired,
}
export enum VoiceOpcode {
@@ -73,7 +73,7 @@ export enum VoiceOpcode {
Resume,
Hello,
Resumed,
ClientDisconnect = 13
ClientDisconnect = 13,
}
export enum VoiceCloseEventCode {
@@ -87,7 +87,7 @@ export enum VoiceCloseEventCode {
UnknownProtocol,
Disconnected = 4014,
VoiceServerCrashed,
UnknownEncryptionMode
UnknownEncryptionMode,
}
export enum HttpResponseCode {
@@ -101,7 +101,7 @@ export enum HttpResponseCode {
NotFound,
MethodNotAllowed,
TooManyRequests = 429,
GatewayUnavailable = 502
GatewayUnavailable = 502,
// ServerError left untyped because it's 5xx.
}
@@ -157,7 +157,7 @@ export enum JSONErrorCode {
InviteAcceptedToGuildApplicationBotNotIn,
InvalidAPIVersion = 50041,
ReactionBlocked = 90001,
ResourceOverloaded = 130000
ResourceOverloaded = 130000,
}
export interface Properties {
@@ -182,7 +182,7 @@ export enum StatusType {
DoNotDisturb = "dnd",
Idle = "idle",
Invisible = "invisible",
Offline = "offline"
Offline = "offline",
}
export type Status_Type = "online" | "dnd" | "idle" | "invisible" | "offline"
@@ -255,3 +255,10 @@ export interface Voice_State_Update_Payload {
/** Whether this user is muted by the bot */
suppress: boolean
}
export interface ReadyPayload {
/** used for resuming connections */
session_id: string
/** (shard_id, num_shards) the shard information associated with this session, if sent when identifying */
shard?: [number, number]
}
-6
View File
@@ -1,6 +0,0 @@
export enum CollectedMessageType {
Ping,
Pong,
Close,
Message
}