mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 11:28:15 +00:00
eaff54f90f
* refactor: rename *ID to *Id * Update src/helpers/commands/delete_slash_command.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/commands/delete_slash_command.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/commands/delete_slash_response.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/commands/edit_slash_response.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/utils.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/utils.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/utils.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/utils.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/utils.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/commands/get_slash_command.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/commands/send_interaction_response.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/commands/upsert_slash_command.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/guilds/edit_widget.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/guilds/get_widget.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/guilds/get_widget.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/guilds/get_widget_image_url.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/guilds/get_widget_image_url.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/guilds/get_widget_settings.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update .gitignore Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update LICENSE Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/members/edit_bot_profile.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/members/edit_bot_profile.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/webhooks/create_webhook.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/webhooks/delete_webhook.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/constants.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/webhooks/edit_webhook.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/webhooks/execute_webhook.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/webhooks/get_webhook.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/rest/cache.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/rest/request.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/constants.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/helpers/commands/delete_slash_response.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/constants.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/constants.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/constants.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/constants.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/utils.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Update src/util/utils.ts Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com> * Revert docs file Co-authored-by: ITOH <72305210+itohatweb@users.noreply.github.com>
163 lines
4.9 KiB
TypeScript
163 lines
4.9 KiB
TypeScript
import { BASE_URL, USER_AGENT } from "../util/constants.ts";
|
|
import { restCache } from "./cache.ts";
|
|
import { ServerRequest } from "./deps.ts";
|
|
import { processQueue } from "./queue.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,
|
|
) {
|
|
const route = request.url.substring(request.url.indexOf("api/"));
|
|
const parts = route.split("/");
|
|
// REMOVE THE API
|
|
parts.shift();
|
|
// 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("/")}`;
|
|
// REMOVE THE MAJOR PARAM
|
|
parts.shift();
|
|
|
|
const [id] = parts;
|
|
|
|
const queue = restCache.pathQueues.get(id);
|
|
// IF THE QUEUE EXISTS JUST ADD THIS TO THE QUEUE
|
|
if (queue) {
|
|
queue.push({ request, payload, options });
|
|
} else {
|
|
// CREATES A NEW QUEUE
|
|
restCache.pathQueues.set(id, [{
|
|
request,
|
|
payload,
|
|
options,
|
|
}]);
|
|
processQueue(id);
|
|
}
|
|
}
|
|
|
|
/** 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 } = {
|
|
Authorization: `Bot ${queuedRequest.options.token}`,
|
|
"User-Agent": USER_AGENT,
|
|
};
|
|
|
|
// GET METHODS SHOULD NOT HAVE A BODY
|
|
if (queuedRequest.request.method === "GET") {
|
|
queuedRequest.payload.body = undefined;
|
|
}
|
|
|
|
// IF A REASON IS PROVIDED ENCODE IT IN HEADERS
|
|
if (queuedRequest.payload.body?.reason) {
|
|
headers["X-Audit-Log-Reason"] = encodeURIComponent(
|
|
queuedRequest.payload.body.reason,
|
|
);
|
|
}
|
|
|
|
// IF A FILE/ATTACHMENT IS PRESENT WE NEED SPECIAL HANDLING
|
|
if (queuedRequest.payload.body?.file) {
|
|
const form = new FormData();
|
|
form.append(
|
|
"file",
|
|
queuedRequest.payload.body.file.blob,
|
|
queuedRequest.payload.body.file.name,
|
|
);
|
|
form.append(
|
|
"payload_json",
|
|
JSON.stringify({ ...queuedRequest.payload.body, file: undefined }),
|
|
);
|
|
queuedRequest.payload.body.file = form;
|
|
} else if (
|
|
queuedRequest.payload.body &&
|
|
!["GET", "DELETE"].includes(queuedRequest.request.method)
|
|
) {
|
|
headers["Content-Type"] = "application/json";
|
|
}
|
|
|
|
return {
|
|
headers,
|
|
body: queuedRequest.payload.body?.file ||
|
|
JSON.stringify(queuedRequest.payload.body),
|
|
method: queuedRequest.request.method,
|
|
};
|
|
}
|
|
|
|
/** Processes the rate limit headers and determines if it needs to be ratelimited and returns the bucket id if available */
|
|
export function processRequestHeaders(url: string, headers: Headers) {
|
|
let ratelimited = false;
|
|
|
|
// GET ALL NECESSARY HEADERS
|
|
const remaining = headers.get("x-ratelimit-remaining");
|
|
const resetTimestamp = headers.get("x-ratelimit-reset");
|
|
const retryAfter = headers.get("retry-after");
|
|
const global = headers.get("x-ratelimit-global");
|
|
const bucketId = headers.get("x-ratelimit-bucket");
|
|
|
|
// IF THERE IS NO REMAINING RATE LIMIT, MARK IT AS RATE LIMITED
|
|
if (remaining && remaining === "0") {
|
|
ratelimited = true;
|
|
|
|
// SAVE THE URL AS LIMITED, IMPORTANT FOR NEW REQUESTS BY USER WITHOUT BUCKET
|
|
restCache.ratelimitedPaths.set(url, {
|
|
url,
|
|
resetTimestamp: Number(resetTimestamp) * 1000,
|
|
bucketId,
|
|
});
|
|
|
|
// SAVE THE BUCKET AS LIMITED SINCE DIFFERENT URLS MAY SHARE A BUCKET
|
|
if (bucketId) {
|
|
restCache.ratelimitedPaths.set(bucketId, {
|
|
url,
|
|
resetTimestamp: Number(resetTimestamp) * 1000,
|
|
bucketId,
|
|
});
|
|
}
|
|
}
|
|
|
|
// IF THERE IS NO REMAINING GLOBAL LIMIT, MARK IT RATE LIMITED GLOBALLY
|
|
if (global) {
|
|
const reset = Date.now() + (Number(retryAfter) * 1000);
|
|
restCache.eventHandlers.globallyRateLimited(url, reset);
|
|
restCache.globallyRateLimited = true;
|
|
ratelimited = true;
|
|
|
|
restCache.ratelimitedPaths.set("global", {
|
|
url: "global",
|
|
resetTimestamp: reset,
|
|
bucketId,
|
|
});
|
|
|
|
if (bucketId) {
|
|
restCache.ratelimitedPaths.set(bucketId, {
|
|
url: "global",
|
|
resetTimestamp: reset,
|
|
bucketId,
|
|
});
|
|
}
|
|
}
|
|
|
|
return ratelimited ? bucketId : undefined;
|
|
}
|
|
|
|
/** This wll create a infinite loop running in 1 seconds using tail recursion to keep rate limits clean. When a rate limit resets, this will remove it so the queue can proceed. */
|
|
function processRateLimitedPaths() {
|
|
const now = Date.now();
|
|
|
|
restCache.ratelimitedPaths.forEach((value, key) => {
|
|
// IF THE TIME HAS NOT REACHED CANCEL
|
|
if (value.resetTimestamp > now) return;
|
|
// RATE LIMIT IS OVER, DELETE THE RATE LIMITER
|
|
restCache.ratelimitedPaths.delete(key);
|
|
// IF IT WAS GLOBAL ALSO MARK THE GLOBAL VALUE AS FALSE
|
|
if (key === "global") restCache.globallyRateLimited = false;
|
|
});
|
|
|
|
// RECHECK IN 1 SECOND
|
|
setTimeout(() => processRateLimitedPaths(), 1000);
|
|
}
|
|
|
|
/** Starts the loop */
|
|
processRateLimitedPaths();
|