mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-01 20:46:08 +00:00
160 lines
6.1 KiB
TypeScript
160 lines
6.1 KiB
TypeScript
import { HTTPResponseCodes } from "../types/shared.ts";
|
|
import { BASE_URL } from "../util/constants.ts";
|
|
import { RequestMethod } from "./rest.ts";
|
|
import { RestManager } from "./restManager.ts";
|
|
|
|
export interface RestSendRequestOptions {
|
|
url: string;
|
|
method: RequestMethod;
|
|
bucketId?: string;
|
|
reject?: Function;
|
|
respond?: Function;
|
|
retryCount?: number;
|
|
payload?: {
|
|
headers: Record<string, string>;
|
|
body: string | FormData;
|
|
};
|
|
}
|
|
|
|
export async function sendRequest<T>(rest: RestManager, options: RestSendRequestOptions): Promise<T> {
|
|
try {
|
|
// CUSTOM HANDLER FOR USER TO LOG OR WHATEVER WHENEVER A FETCH IS MADE
|
|
rest.debug(`[REST - fetching] URL: ${options.url} | ${JSON.stringify(options)}`);
|
|
|
|
const newURL = options.url.startsWith(BASE_URL) ? options.url : `${BASE_URL}/v${rest.version}/${options.url}`;
|
|
|
|
rest.debug(`[REST - url data] URL: ${newURL}`);
|
|
|
|
const response = await fetch(
|
|
new Request(newURL, {
|
|
method: options.method,
|
|
headers: options.payload?.headers,
|
|
body: options.payload?.body,
|
|
}),
|
|
);
|
|
|
|
rest.debug(`[REST - fetched] URL: ${options.url} | ${JSON.stringify(options)}`);
|
|
|
|
const bucketIdFromHeaders = rest.processRequestHeaders(
|
|
rest,
|
|
rest.simplifyUrl(options.url, options.method),
|
|
response.headers,
|
|
);
|
|
// SET THE BUCKET Id IF IT WAS PRESENT
|
|
if (bucketIdFromHeaders) {
|
|
options.bucketId = bucketIdFromHeaders;
|
|
}
|
|
|
|
if (response.status < 200 || response.status >= 400) {
|
|
rest.debug(
|
|
`[REST - httpError] Payload: ${JSON.stringify(options)} | Response: ${JSON.stringify(response)}`,
|
|
);
|
|
|
|
let error = "REQUEST_UNKNOWN_ERROR";
|
|
switch (response.status) {
|
|
case HTTPResponseCodes.BadRequest:
|
|
error = "The options was improperly formatted, or the server couldn't understand it.";
|
|
break;
|
|
case HTTPResponseCodes.Unauthorized:
|
|
error = "The Authorization header was missing or invalid.";
|
|
break;
|
|
case HTTPResponseCodes.Forbidden:
|
|
error = "The Authorization token you passed did not have permission to the resource.";
|
|
break;
|
|
case HTTPResponseCodes.NotFound:
|
|
error = "The resource at the location specified doesn't exist.";
|
|
break;
|
|
case HTTPResponseCodes.MethodNotAllowed:
|
|
error = "The HTTP method used is not valid for the location specified.";
|
|
break;
|
|
case HTTPResponseCodes.GatewayUnavailable:
|
|
error = "There was not a gateway available to process your options. Wait a bit and retry.";
|
|
break;
|
|
}
|
|
|
|
if (
|
|
rest.invalidRequestErrorStatuses.includes(response.status) &&
|
|
!(response.status === 429 && response.headers.get("X-RateLimit-Scope"))
|
|
) {
|
|
// INCREMENT CURRENT INVALID REQUESTS
|
|
++rest.invalidRequests;
|
|
|
|
if (!rest.invalidRequestsTimeoutId) {
|
|
rest.invalidRequestsTimeoutId = setTimeout(() => {
|
|
rest.debug(`[REST - processGlobalQueue] Resetting invalid optionss counter in setTimeout.`);
|
|
rest.invalidRequests = 0;
|
|
rest.invalidRequestsTimeoutId = 0;
|
|
}, rest.invalidRequestsInterval);
|
|
}
|
|
}
|
|
|
|
// If NOT rate limited remove from queue
|
|
if (response.status !== 429) {
|
|
options.reject?.({
|
|
ok: false,
|
|
status: response.status,
|
|
error,
|
|
body: response.type ? JSON.stringify(await response.json()) : undefined,
|
|
});
|
|
|
|
throw new Error(
|
|
JSON.stringify({
|
|
ok: false,
|
|
status: response.status,
|
|
error,
|
|
body: response.type ? JSON.stringify(await response.json()) : undefined,
|
|
}),
|
|
);
|
|
} else {
|
|
if (options.retryCount && options.retryCount++ >= rest.maxRetryCount) {
|
|
rest.debug(`[REST - RetriesMaxed] ${JSON.stringify(options)}`);
|
|
// REMOVE ITEM FROM QUEUE TO PREVENT RETRY
|
|
options.reject?.({
|
|
ok: false,
|
|
status: response.status,
|
|
error: "The options was rate limited and it maxed out the retries limit.",
|
|
});
|
|
|
|
// @ts-ignore Code should never reach here
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// SOMETIMES DISCORD RETURNS AN EMPTY 204 RESPONSE THAT CAN'T BE MADE TO JSON
|
|
if (response.status === 204) {
|
|
rest.debug(`[REST - FetchSuccess] URL: ${options.url} | ${JSON.stringify(options)}`);
|
|
options.respond?.({
|
|
ok: true,
|
|
status: 204,
|
|
});
|
|
// @ts-ignore 204 will be void
|
|
return;
|
|
} else {
|
|
// CONVERT THE RESPONSE TO JSON
|
|
const json = JSON.stringify(await response.json());
|
|
|
|
rest.debug(`[REST - fetchSuccess] ${JSON.stringify(options)}`);
|
|
options.respond?.({
|
|
ok: true,
|
|
status: 200,
|
|
body: json,
|
|
});
|
|
|
|
return JSON.parse(json);
|
|
}
|
|
} catch (error) {
|
|
// SOMETHING WENT WRONG, LOG AND RESPOND WITH ERROR
|
|
rest.debug(`[REST - fetchFailed] Payload: ${JSON.stringify(options)} | Error: ${error}`);
|
|
options.reject?.({
|
|
ok: false,
|
|
status: 599,
|
|
error: "Internal Proxy Error",
|
|
});
|
|
|
|
throw new Error("Something went wrong in sendRequest", {
|
|
cause: error,
|
|
});
|
|
}
|
|
}
|