mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 11:28:15 +00:00
fix: rest errors preventing startup
This commit is contained in:
+10
-25
@@ -2,6 +2,7 @@ import { getGatewayBot } from "./helpers/misc/get_gateway_bot.ts";
|
||||
import { DiscordGatewayIntents } from "./types/gateway/gateway_intents.ts";
|
||||
import { DiscordGetGatewayBot } from "./types/gateway/get_gateway_bot.ts";
|
||||
import { baseEndpoints, GATEWAY_VERSION } from "./util/constants.ts";
|
||||
import { ws } from "./ws/ws.ts";
|
||||
|
||||
export let authorization = "";
|
||||
export let secretKey = "";
|
||||
@@ -39,18 +40,14 @@ export async function startBot(config: BotConfig) {
|
||||
proxyWSURL = botGatewayData.url;
|
||||
identifyPayload.token = config.token;
|
||||
identifyPayload.intents = config.intents.reduce(
|
||||
(
|
||||
bits,
|
||||
next,
|
||||
) => (bits |= typeof next === "string"
|
||||
? DiscordGatewayIntents[next]
|
||||
: next),
|
||||
0,
|
||||
(bits, next) =>
|
||||
(bits |= typeof next === "string" ? DiscordGatewayIntents[next] : next),
|
||||
0
|
||||
);
|
||||
lastShardId = botGatewayData.shards;
|
||||
identifyPayload.shard = [0, lastShardId];
|
||||
|
||||
await spawnShards(botGatewayData, identifyPayload, 0, lastShardId);
|
||||
ws.spawnShards();
|
||||
}
|
||||
|
||||
/** Allows you to dynamically update the event handlers by passing in new eventHandlers */
|
||||
@@ -78,7 +75,7 @@ export function setApplicationId(id: string) {
|
||||
* Please be aware if you are a beginner developer using this, things will not work as per the guides. This is for advanced developers only!
|
||||
*
|
||||
* Advanced Devs: This function will allow you to have an insane amount of customization potential as when you get to large bots you need to be able to optimize every tiny detail to make you bot work the way you need.
|
||||
*/
|
||||
*/
|
||||
export async function startBigBrainBot(data: BigBrainBotConfig) {
|
||||
authorization = `Bot ${data.token}`;
|
||||
identifyPayload.token = `Bot ${data.token}`;
|
||||
@@ -92,13 +89,9 @@ export async function startBigBrainBot(data: BigBrainBotConfig) {
|
||||
}
|
||||
|
||||
identifyPayload.intents = data.intents.reduce(
|
||||
(
|
||||
bits,
|
||||
next,
|
||||
) => (bits |= typeof next === "string"
|
||||
? DiscordGatewayIntents[next]
|
||||
: next),
|
||||
0,
|
||||
(bits, next) =>
|
||||
(bits |= typeof next === "string" ? DiscordGatewayIntents[next] : next),
|
||||
0
|
||||
);
|
||||
|
||||
// PROXY DOESNT NEED US SPAWNING SHARDS
|
||||
@@ -106,15 +99,7 @@ export async function startBigBrainBot(data: BigBrainBotConfig) {
|
||||
// Initial API connection to get info about bots connection
|
||||
botGatewayData = await getGatewayBot();
|
||||
proxyWSURL = botGatewayData.url;
|
||||
await spawnShards(
|
||||
botGatewayData,
|
||||
identifyPayload,
|
||||
data.firstShardId,
|
||||
data.lastShardId ||
|
||||
(botGatewayData.shards >= 25
|
||||
? (data.firstShardId + 25)
|
||||
: botGatewayData.shards),
|
||||
);
|
||||
ws.spawnShards(data.firstShardId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { USER_AGENT } from "../util/constants.ts";
|
||||
|
||||
/** Creates the request body and headers that are necessary to send a request. Will handle different types of methods and everything necessary for discord. */
|
||||
export function createRequestBody(queuedRequest: QueuedRequest) {
|
||||
const headers: { [key: string]: string } = {
|
||||
@@ -6,7 +8,7 @@ export function createRequestBody(queuedRequest: QueuedRequest) {
|
||||
};
|
||||
|
||||
// GET METHODS SHOULD NOT HAVE A BODY
|
||||
if (queuedRequest.request.method === "GET") {
|
||||
if (queuedRequest.request.method.toUpperCase() === "GET") {
|
||||
queuedRequest.payload.body = undefined;
|
||||
}
|
||||
|
||||
|
||||
+37
-28
@@ -1,4 +1,5 @@
|
||||
import { DiscordHTTPResponseCodes } from "../types/codes/http_response_codes.ts";
|
||||
import { delay } from "../util/utils.ts";
|
||||
import { rest } from "./rest.ts";
|
||||
|
||||
/** Processes the queue by looping over each path separately until the queues are empty. */
|
||||
@@ -36,13 +37,19 @@ export async function processQueue(id: string) {
|
||||
|
||||
// IF THIS IS A GET REQUEST, CHANGE THE BODY TO QUERY PARAMETERS
|
||||
const query =
|
||||
queuedRequest.request.method === "GET" && queuedRequest.payload.body
|
||||
? Object.entries(queuedRequest.payload.body).map(([key, value]) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(value as string)}`
|
||||
queuedRequest.request.method.toUpperCase() === "GET" &&
|
||||
queuedRequest.payload.body
|
||||
? Object.entries(queuedRequest.payload.body)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(
|
||||
value as string
|
||||
)}`
|
||||
)
|
||||
.join("&")
|
||||
: "";
|
||||
const urlToUse = queuedRequest.request.method === "GET" && query
|
||||
const urlToUse =
|
||||
queuedRequest.request.method.toUpperCase() === "GET" && query
|
||||
? `${queuedRequest.request.url}?${query}`
|
||||
: queuedRequest.request.url;
|
||||
|
||||
@@ -52,45 +59,49 @@ export async function processQueue(id: string) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
urlToUse,
|
||||
rest.createRequestBody(queuedRequest),
|
||||
rest.createRequestBody(queuedRequest)
|
||||
);
|
||||
|
||||
rest.eventHandlers.fetched(queuedRequest.payload);
|
||||
const bucketIdFromHeaders = rest.processRequestHeaders(
|
||||
queuedRequest.request.url,
|
||||
response.headers,
|
||||
response.headers
|
||||
);
|
||||
|
||||
if (response.status < 200 || response.status >= 400) {
|
||||
rest.eventHandlers.error(
|
||||
"httpError",
|
||||
queuedRequest.payload,
|
||||
response,
|
||||
);
|
||||
rest.eventHandlers.error("httpError", queuedRequest.payload, response);
|
||||
|
||||
let error = "REQUEST_UNKNOWN_ERROR";
|
||||
switch (response.status) {
|
||||
case DiscordHTTPResponseCodes.BadRequest:
|
||||
error =
|
||||
"The request was improperly formatted, or the server couldn't understand it.";
|
||||
break;
|
||||
case DiscordHTTPResponseCodes.Unauthorized:
|
||||
error = "The Authorization header was missing or invalid.";
|
||||
break;
|
||||
case DiscordHTTPResponseCodes.Forbidden:
|
||||
error =
|
||||
"The Authorization token you passed did not have permission to the resource.";
|
||||
break;
|
||||
case DiscordHTTPResponseCodes.NotFound:
|
||||
error = "The resource at the location specified doesn't exist.";
|
||||
break;
|
||||
case DiscordHTTPResponseCodes.MethodNotAllowed:
|
||||
error =
|
||||
"The HTTP method used is not valid for the location specified.";
|
||||
break;
|
||||
case DiscordHTTPResponseCodes.GatewayUnavailable:
|
||||
error =
|
||||
"There was not a gateway available to process your request. Wait a bit and retry.";
|
||||
break;
|
||||
}
|
||||
|
||||
queuedRequest.request.respond(
|
||||
{ status: response.status, body: JSON.stringify({ error }) },
|
||||
);
|
||||
queuedRequest.request.respond({
|
||||
status: response.status,
|
||||
body: JSON.stringify({ error }),
|
||||
});
|
||||
|
||||
queue.shift();
|
||||
continue;
|
||||
}
|
||||
@@ -115,17 +126,13 @@ export async function processQueue(id: string) {
|
||||
queuedRequest.options.maxRetryCount
|
||||
) {
|
||||
rest.eventHandlers.retriesMaxed(queuedRequest.payload);
|
||||
queuedRequest.request.respond(
|
||||
{
|
||||
queuedRequest.request.respond({
|
||||
status: 200,
|
||||
body: JSON.stringify(
|
||||
{
|
||||
body: JSON.stringify({
|
||||
error:
|
||||
"The request was rate limited and it maxed out the retries limit.",
|
||||
},
|
||||
),
|
||||
},
|
||||
);
|
||||
}),
|
||||
});
|
||||
// REMOVE ITEM FROM QUEUE TO PREVENT RETRY
|
||||
queue.shift();
|
||||
continue;
|
||||
@@ -142,16 +149,18 @@ export async function processQueue(id: string) {
|
||||
rest.eventHandlers.fetchSuccess(queuedRequest.payload);
|
||||
// REMOVE FROM QUEUE
|
||||
queue.shift();
|
||||
queuedRequest.request.respond(
|
||||
{ status: 200, body: JSON.stringify(json) },
|
||||
);
|
||||
queuedRequest.request.respond({
|
||||
status: 200,
|
||||
body: JSON.stringify(json),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// SOMETHING WENT WRONG, LOG AND RESPOND WITH ERROR
|
||||
rest.eventHandlers.fetchFailed(queuedRequest.payload, error);
|
||||
queuedRequest.request.respond(
|
||||
{ status: 404, body: JSON.stringify({ error }) },
|
||||
);
|
||||
queuedRequest.request.respond({
|
||||
status: 404,
|
||||
body: JSON.stringify({ error }),
|
||||
});
|
||||
// REMOVE FROM QUEUE
|
||||
queue.shift();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { BASE_URL } from "../util/constants.ts";
|
||||
import { rest } from "./rest.ts";
|
||||
|
||||
/** Processes a request and assigns it to a queue or creates a queue if none exists for it. */
|
||||
export function processRequest(
|
||||
request: ServerRequest,
|
||||
payload: RunMethodOptions,
|
||||
options: RestServerOptions,
|
||||
payload: RunMethodOptions
|
||||
) {
|
||||
const route = request.url.substring(request.url.indexOf("api/"));
|
||||
const parts = route.split("/");
|
||||
@@ -11,23 +13,24 @@ export function processRequest(
|
||||
// REMOVES THE VERSION NUMBER
|
||||
if (parts[0]?.startsWith("v")) parts.shift();
|
||||
// SET THE NEW REQUEST URL
|
||||
request.url = `${BASE_URL}/v${options.apiVersion || 8}/${parts.join("/")}`;
|
||||
request.url = `${BASE_URL}/v${rest.apiVersion}/${parts.join("/")}`;
|
||||
// REMOVE THE MAJOR PARAM
|
||||
parts.shift();
|
||||
|
||||
const [id] = parts;
|
||||
|
||||
const queue = restCache.pathQueues.get(id);
|
||||
const queue = rest.pathQueues.get(id);
|
||||
// IF THE QUEUE EXISTS JUST ADD THIS TO THE QUEUE
|
||||
if (queue) {
|
||||
queue.push({ request, payload, options });
|
||||
queue.push({ request, payload });
|
||||
} else {
|
||||
// CREATES A NEW QUEUE
|
||||
restCache.pathQueues.set(id, [{
|
||||
rest.pathQueues.set(id, [
|
||||
{
|
||||
request,
|
||||
payload,
|
||||
options,
|
||||
}]);
|
||||
processQueue(id);
|
||||
},
|
||||
]);
|
||||
rest.processQueue(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { processRequestHeaders } from "./process_request_headers.ts";
|
||||
import { runMethod } from "./run_method.ts";
|
||||
|
||||
export const rest = {
|
||||
apiVersion: "8",
|
||||
/** The secret authorization key to confirm that this was a request made by you and not a DDOS attack. */
|
||||
authorization: "discordeno_best_lib_ever",
|
||||
pathQueues: new Map(),
|
||||
|
||||
@@ -46,8 +46,7 @@ export function runMethod(
|
||||
}
|
||||
|
||||
// No proxy so we need to handle all rate limiting and such
|
||||
// deno-lint-ignore no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = async () => {
|
||||
try {
|
||||
const rateLimitResetIn = rest.checkRateLimits(url);
|
||||
@@ -143,14 +142,10 @@ export function runMethod(
|
||||
}
|
||||
};
|
||||
|
||||
rest.addToQueue({
|
||||
rest.processRequest({ url, method, respond: (data: { status: number, body?: string; }) => resolve(JSON.parse(data.body || "{}")) }, {
|
||||
callback,
|
||||
bucketId,
|
||||
url,
|
||||
});
|
||||
if (!rest.queueInProcess) {
|
||||
rest.queueInProcess = true;
|
||||
await rest.processQueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export async function createShard(shardId: number) {
|
||||
ws.log("ERROR", { shardId, error: errorEvent });
|
||||
};
|
||||
|
||||
socket.onmessage = ({ data: message }) => handleOnMessage(message, shardId);
|
||||
socket.onmessage = ({ data: message }) => ws.handleOnMessage(message, shardId);
|
||||
|
||||
socket.onclose = (event) => {
|
||||
ws.log("CLOSED", { shardId, payload: event });
|
||||
|
||||
@@ -15,6 +15,7 @@ export async function identify(shardId: number, maxShards: number) {
|
||||
sessionId: "",
|
||||
previousSequenceNumber: 0,
|
||||
resuming: false,
|
||||
unavailableGuildIds: new Set(),
|
||||
heartbeat: {
|
||||
lastSentAt: 0,
|
||||
lastReceivedAt: 0,
|
||||
|
||||
@@ -28,6 +28,7 @@ export async function resume(shardId: number) {
|
||||
sessionId,
|
||||
previousSequenceNumber,
|
||||
resuming: false,
|
||||
unavailableGuildIds: new Set(),
|
||||
heartbeat: {
|
||||
lastSentAt: 0,
|
||||
lastReceivedAt: 0,
|
||||
|
||||
@@ -116,6 +116,8 @@ export interface DiscordenoShard {
|
||||
previousSequenceNumber: number | null;
|
||||
/** Whether the shard is currently resuming. */
|
||||
resuming: boolean;
|
||||
/** The list of guild ids that are currently unavailable due to an outage. */
|
||||
unavailableGuildIds: Set<string>;
|
||||
heartbeat: {
|
||||
/** The exact timestamp the last heartbeat was sent */
|
||||
lastSentAt: number;
|
||||
|
||||
Reference in New Issue
Block a user