mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 19:28:17 +00:00
itoh is love itoh is bae this is his stuff
This commit is contained in:
@@ -127,9 +127,9 @@ export async function getPins(channelID: string) {
|
|||||||
return Promise.all(result.map((res) => structures.createMessage(res)));
|
return Promise.all(result.map((res) => structures.createMessage(res)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger a typing indicator for the specified channel. Generally bots should **NOT** implement this route.
|
* Trigger a typing indicator for the specified channel. Generally bots should **NOT** implement this route.
|
||||||
* However, if a bot is responding to a command and expects the computation to take a few seconds,
|
* However, if a bot is responding to a command and expects the computation to take a few seconds,
|
||||||
* this endpoint may be called to let the user know that the bot is processing their message.
|
* this endpoint may be called to let the user know that the bot is processing their message.
|
||||||
*/
|
*/
|
||||||
export async function startTyping(channelID: string) {
|
export async function startTyping(channelID: string) {
|
||||||
@@ -240,9 +240,13 @@ export async function sendMessage(
|
|||||||
replied_user: content.mentions.repliedUser,
|
replied_user: content.mentions.repliedUser,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
message_reference: {
|
...(content.replyMessageID
|
||||||
message_id: content.replyMessageID,
|
? {
|
||||||
},
|
message_reference: {
|
||||||
|
message_id: content.replyMessageID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
},
|
},
|
||||||
) as MessageCreateOptions;
|
) as MessageCreateOptions;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
export * from "https://deno.land/std@0.87.0/http/server.ts";
|
export * from "https://deno.land/std@0.88.0/http/server.ts";
|
||||||
|
|||||||
+24
-12
@@ -1,6 +1,7 @@
|
|||||||
import { restCache } from "./cache.ts";
|
import { restCache } from "./cache.ts";
|
||||||
import { createRequestBody, processRequestHeaders } from "./request.ts";
|
import { createRequestBody, processRequestHeaders } from "./request.ts";
|
||||||
import { HttpResponseCode } from "./types/mod.ts";
|
import { HttpResponseCode } from "./types/mod.ts";
|
||||||
|
import { delay } from "../util/utils.ts";
|
||||||
|
|
||||||
/** If the queue is not already processing, this will start processing the queue. */
|
/** If the queue is not already processing, this will start processing the queue. */
|
||||||
export function startQueue() {
|
export function startQueue() {
|
||||||
@@ -12,19 +13,24 @@ export function startQueue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Processes the queue by looping over each path separately until the queues are empty. */
|
/** Processes the queue by looping over each path separately until the queues are empty. */
|
||||||
export function processQueue() {
|
export async function processQueue() {
|
||||||
while (restCache.processingQueue) {
|
while (restCache.processingQueue) {
|
||||||
// FOR EVERY PATH WE WILL START ITS OWN LOOP.
|
// FOR EVERY PATH WE WILL START ITS OWN LOOP.
|
||||||
restCache.pathQueues.forEach(async (queue) => {
|
restCache.pathQueues.forEach(async (queue) => {
|
||||||
|
// MAKE SURE THIS QUEUE HAS NOT ALREADY STARTED
|
||||||
|
if (queue.processing) return;
|
||||||
// EACH PATH IS UNIQUE LIMITER
|
// EACH PATH IS UNIQUE LIMITER
|
||||||
while (queue.length) {
|
while (queue.requests.length) {
|
||||||
// IF THE BOT IS GLOBALLY RATELIMITED TRY AGAIN
|
// IF THE BOT IS GLOBALLY RATELIMITED TRY AGAIN
|
||||||
if (!restCache.globallyRateLimited) continue;
|
if (restCache.globallyRateLimited) continue;
|
||||||
// SELECT THE FIRST ITEM FROM THIS QUEUE
|
// SELECT THE FIRST ITEM FROM THIS QUEUE
|
||||||
const [queuedRequest] = queue;
|
const [queuedRequest] = queue.requests;
|
||||||
// IF THIS DOESNT HAVE ANY ITEMS JUST CANCEL, THE CLEANER WILL REMOVE IT.
|
// IF THIS DOESNT HAVE ANY ITEMS JUST CANCEL, THE CLEANER WILL REMOVE IT.
|
||||||
if (!queuedRequest) return;
|
if (!queuedRequest) return;
|
||||||
|
|
||||||
|
// MARK THIS QUEUE AS NOW BEING PROCESSED
|
||||||
|
queue.processing = true;
|
||||||
|
|
||||||
// IF THIS URL IS STILL RATE LIMITED, TRY AGAIN
|
// IF THIS URL IS STILL RATE LIMITED, TRY AGAIN
|
||||||
const urlResetIn = checkRateLimits(queuedRequest.payload.url);
|
const urlResetIn = checkRateLimits(queuedRequest.payload.url);
|
||||||
if (urlResetIn) continue;
|
if (urlResetIn) continue;
|
||||||
@@ -90,7 +96,7 @@ export function processQueue() {
|
|||||||
queuedRequest.request.respond(
|
queuedRequest.request.respond(
|
||||||
{ status: response.status, body: JSON.stringify({ error }) },
|
{ status: response.status, body: JSON.stringify({ error }) },
|
||||||
);
|
);
|
||||||
queue.shift();
|
queue.requests.shift();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +108,6 @@ export function processQueue() {
|
|||||||
|
|
||||||
// CONVERT THE RESPONSE TO JSON
|
// CONVERT THE RESPONSE TO JSON
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
|
|
||||||
// IF THE RESPONSE WAS RATE LIMITED, HANDLE ACCORDINGLY
|
// IF THE RESPONSE WAS RATE LIMITED, HANDLE ACCORDINGLY
|
||||||
if (
|
if (
|
||||||
json.retry_after ||
|
json.retry_after ||
|
||||||
@@ -126,7 +131,7 @@ export function processQueue() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
// REMOVE ITEM FROM QUEUE TO PREVENT RETRY
|
// REMOVE ITEM FROM QUEUE TO PREVENT RETRY
|
||||||
queue.shift();
|
queue.requests.shift();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +145,7 @@ export function processQueue() {
|
|||||||
|
|
||||||
restCache.eventHandlers.fetchSuccess(queuedRequest.payload);
|
restCache.eventHandlers.fetchSuccess(queuedRequest.payload);
|
||||||
// REMOVE FROM QUEUE
|
// REMOVE FROM QUEUE
|
||||||
queue.shift();
|
queue.requests.shift();
|
||||||
queuedRequest.request.respond(
|
queuedRequest.request.respond(
|
||||||
{ status: 200, body: JSON.stringify(json) },
|
{ status: 200, body: JSON.stringify(json) },
|
||||||
);
|
);
|
||||||
@@ -151,23 +156,30 @@ export function processQueue() {
|
|||||||
{ status: 404, body: JSON.stringify({ error }) },
|
{ status: 404, body: JSON.stringify({ error }) },
|
||||||
);
|
);
|
||||||
// REMOVE FROM QUEUE
|
// REMOVE FROM QUEUE
|
||||||
queue.shift();
|
queue.requests.shift();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK THE QUEUE AS NO LONGER PROCESSING
|
||||||
|
queue.processing = false;
|
||||||
// ONCE QUEUE IS DONE, WE CAN TRY CLEANING UP
|
// ONCE QUEUE IS DONE, WE CAN TRY CLEANING UP
|
||||||
cleanupQueues();
|
cleanupQueues();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await delay(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Cleans up the queues by checking if there is nothing left and removing it. */
|
/** Cleans up the queues by checking if there is nothing left and removing it. */
|
||||||
export function cleanupQueues() {
|
export function cleanupQueues() {
|
||||||
restCache.pathQueues.forEach((queue, key) => {
|
for (const [key, queue] of restCache.pathQueues) {
|
||||||
if (queue.length) return;
|
if (queue.requests.length) continue;
|
||||||
// REMOVE IT FROM CACHE
|
// REMOVE IT FROM CACHE
|
||||||
restCache.pathQueues.delete(key);
|
restCache.pathQueues.delete(key);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
// NO QUEUE LEFT, DISABLE THE QUEUE
|
||||||
|
if (!restCache.pathQueues.size) restCache.processingQueue = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check the rate limits for a url or a bucket. */
|
/** Check the rate limits for a url or a bucket. */
|
||||||
|
|||||||
+14
-4
@@ -1,4 +1,4 @@
|
|||||||
import { USER_AGENT } from "../util/constants.ts";
|
import { BASE_URL, USER_AGENT } from "../util/constants.ts";
|
||||||
import { restCache } from "./cache.ts";
|
import { restCache } from "./cache.ts";
|
||||||
import { ServerRequest } from "./deps.ts";
|
import { ServerRequest } from "./deps.ts";
|
||||||
import { startQueue } from "./queue.ts";
|
import { startQueue } from "./queue.ts";
|
||||||
@@ -20,6 +20,8 @@ export function processRequest(
|
|||||||
parts.shift();
|
parts.shift();
|
||||||
// REMOVES THE VERSION NUMBER
|
// REMOVES THE VERSION NUMBER
|
||||||
if (parts[0]?.startsWith("v")) parts.shift();
|
if (parts[0]?.startsWith("v")) parts.shift();
|
||||||
|
// SET THE NEW REQUEST URL
|
||||||
|
payload.url = `${BASE_URL}/v${options.apiVersion || 8}/${parts.join("/")}`;
|
||||||
// REMOVE THE MAJOR PARAM
|
// REMOVE THE MAJOR PARAM
|
||||||
parts.shift();
|
parts.shift();
|
||||||
|
|
||||||
@@ -28,19 +30,27 @@ export function processRequest(
|
|||||||
const queue = restCache.pathQueues.get(id);
|
const queue = restCache.pathQueues.get(id);
|
||||||
// IF THE QUEUE EXISTS JUST ADD THIS TO THE QUEUE
|
// IF THE QUEUE EXISTS JUST ADD THIS TO THE QUEUE
|
||||||
if (queue) {
|
if (queue) {
|
||||||
queue.push({ request, payload, options });
|
queue.requests.push({ request, payload, options });
|
||||||
} else {
|
} else {
|
||||||
// CREATES A NEW QUEUE
|
// CREATES A NEW QUEUE
|
||||||
restCache.pathQueues.set(id, [{ request, payload, options }]);
|
restCache.pathQueues.set(id, {
|
||||||
|
processing: false,
|
||||||
|
requests: [{
|
||||||
|
request,
|
||||||
|
payload,
|
||||||
|
options,
|
||||||
|
}],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("starting queue");
|
||||||
startQueue();
|
startQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates the request body and headers that are necessary to send a request. Will handle different types of methods and everything necessary for discord. */
|
/** 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) {
|
export function createRequestBody(queuedRequest: QueuedRequest) {
|
||||||
const headers: { [key: string]: string } = {
|
const headers: { [key: string]: string } = {
|
||||||
Authorization: queuedRequest.options.token,
|
Authorization: `Bot ${queuedRequest.options.token}`,
|
||||||
"User-Agent": USER_AGENT,
|
"User-Agent": USER_AGENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ function runMethod(
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
...(body as Record<string, unknown> || {}),
|
body: body || {},
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
authorization: restAuthorization,
|
authorization: restAuthorization,
|
||||||
|
|||||||
+1
-2
@@ -23,7 +23,6 @@ async function handlePayload(
|
|||||||
// INSTANTLY IGNORE ANY REQUESTS THAT DON'T HAVE THE SECRET AUTHORIZATION KEY
|
// INSTANTLY IGNORE ANY REQUESTS THAT DON'T HAVE THE SECRET AUTHORIZATION KEY
|
||||||
const authorization = request.headers.get("authorization");
|
const authorization = request.headers.get("authorization");
|
||||||
if (authorization !== options.authorization) return;
|
if (authorization !== options.authorization) return;
|
||||||
|
|
||||||
// READ BUFFER AFTER AUTH CHECK
|
// READ BUFFER AFTER AUTH CHECK
|
||||||
const buffer = await Deno.readAll(request.body);
|
const buffer = await Deno.readAll(request.body);
|
||||||
|
|
||||||
@@ -48,7 +47,7 @@ async function handlePayload(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PROCESS THE REQUEST
|
// PROCESS THE REQUEST
|
||||||
await processRequest(
|
processRequest(
|
||||||
request,
|
request,
|
||||||
{ method: data.method, url: data.url, body: data.body, retryCount: 0 },
|
{ method: data.method, url: data.url, body: data.body, retryCount: 0 },
|
||||||
options,
|
options,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { RestEventHandlers } from "./server.ts";
|
|||||||
|
|
||||||
export interface RestCache {
|
export interface RestCache {
|
||||||
/** The queues that are currently needing to be executed. Key is the url path and the value is all the requests in this same path. Paths are mapped by MAJOR params. */
|
/** The queues that are currently needing to be executed. Key is the url path and the value is all the requests in this same path. Paths are mapped by MAJOR params. */
|
||||||
pathQueues: Map<string, QueuedRequest[]>;
|
pathQueues: Map<string, Queue>;
|
||||||
/** Whether or not the queues are currently processing. */
|
/** Whether or not the queues are currently processing. */
|
||||||
processingQueue: boolean;
|
processingQueue: boolean;
|
||||||
/** Whether or not this token has been globally rate limited. */
|
/** Whether or not this token has been globally rate limited. */
|
||||||
@@ -13,3 +13,10 @@ export interface RestCache {
|
|||||||
/** The event handlers are functions that run when something is happening internally. Users can customize this for analytics, debugging, logging or anything their heart desires. */
|
/** The event handlers are functions that run when something is happening internally. Users can customize this for analytics, debugging, logging or anything their heart desires. */
|
||||||
eventHandlers: RestEventHandlers;
|
eventHandlers: RestEventHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Queue {
|
||||||
|
/** Whether or not this queue is being processed */
|
||||||
|
processing: boolean;
|
||||||
|
/** All the requests in this queue. */
|
||||||
|
requests: QueuedRequest[];
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ export interface RestServerOptions {
|
|||||||
token: string;
|
token: string;
|
||||||
/** When a request is rate limited, how many times should it keep retrying the request. Recommended: 10 */
|
/** When a request is rate limited, how many times should it keep retrying the request. Recommended: 10 */
|
||||||
maxRetryCount: number;
|
maxRetryCount: number;
|
||||||
|
/** The api version you would like to use */
|
||||||
|
apiVersion?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RestEventHandlers {
|
export interface RestEventHandlers {
|
||||||
|
|||||||
Reference in New Issue
Block a user