mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-14 10:33:30 +01:00
feat(rest): use undici (#7747)
Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com> Co-authored-by: ckohen <chaikohen@gmail.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { APIVersion } from 'discord-api-types/v10';
|
||||
import { getGlobalDispatcher } from 'undici';
|
||||
import type { RESTOptions } from '../REST';
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment
|
||||
const Package = require('../../../package.json');
|
||||
@@ -7,7 +8,9 @@ const Package = require('../../../package.json');
|
||||
export const DefaultUserAgent = `DiscordBot (${Package.homepage}, ${Package.version})`;
|
||||
|
||||
export const DefaultRestOptions: Required<RESTOptions> = {
|
||||
agent: {},
|
||||
get agent() {
|
||||
return getGlobalDispatcher();
|
||||
},
|
||||
api: 'https://discord.com/api',
|
||||
authPrefix: 'Bot',
|
||||
cdn: 'https://cdn.discordapp.com',
|
||||
@@ -32,7 +35,6 @@ export const enum RESTEvents {
|
||||
Debug = 'restDebug',
|
||||
InvalidRequestWarning = 'invalidRequestWarning',
|
||||
RateLimited = 'rateLimited',
|
||||
Request = 'request',
|
||||
Response = 'response',
|
||||
HashSweep = 'hashSweep',
|
||||
HandlerSweep = 'handlerSweep',
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
import { Blob } from 'node:buffer';
|
||||
import { URLSearchParams } from 'node:url';
|
||||
import { types } from 'node:util';
|
||||
import type { RESTPatchAPIChannelJSONBody } from 'discord-api-types/v10';
|
||||
import type { Response } from 'node-fetch';
|
||||
import { FormData, type Dispatcher, type RequestInit } from 'undici';
|
||||
import type { RequestOptions } from '../REST';
|
||||
import { RequestMethod } from '../RequestManager';
|
||||
|
||||
export function parseHeader(header: string | string[] | undefined): string | undefined {
|
||||
if (header === undefined) {
|
||||
return header;
|
||||
} else if (typeof header === 'string') {
|
||||
return header;
|
||||
}
|
||||
|
||||
return header.join(';');
|
||||
}
|
||||
|
||||
function serializeSearchParam(value: unknown): string | null {
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
@@ -43,14 +57,15 @@ export function makeURLSearchParams(options?: Record<string, unknown>) {
|
||||
|
||||
/**
|
||||
* Converts the response to usable data
|
||||
* @param res The node-fetch response
|
||||
* @param res The fetch response
|
||||
*/
|
||||
export function parseResponse(res: Response): Promise<unknown> {
|
||||
if (res.headers.get('Content-Type')?.startsWith('application/json')) {
|
||||
return res.json();
|
||||
export function parseResponse(res: Dispatcher.ResponseData): Promise<unknown> {
|
||||
const header = parseHeader(res.headers['content-type']);
|
||||
if (header?.startsWith('application/json')) {
|
||||
return res.body.json();
|
||||
}
|
||||
|
||||
return res.arrayBuffer();
|
||||
return res.body.arrayBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,3 +90,48 @@ export function hasSublimit(bucketRoute: string, body?: unknown, method?: string
|
||||
// If we are checking if a request has a sublimit on a route not checked above, sublimit all requests to avoid a flood of 429s
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function resolveBody(body: RequestInit['body']): Promise<RequestOptions['body']> {
|
||||
// eslint-disable-next-line no-eq-null
|
||||
if (body == null) {
|
||||
return null;
|
||||
} else if (typeof body === 'string') {
|
||||
return body;
|
||||
} else if (types.isUint8Array(body)) {
|
||||
return body;
|
||||
} else if (types.isArrayBuffer(body)) {
|
||||
return new Uint8Array(body);
|
||||
} else if (body instanceof URLSearchParams) {
|
||||
return body.toString();
|
||||
} else if (body instanceof DataView) {
|
||||
return new Uint8Array(body.buffer);
|
||||
} else if (body instanceof Blob) {
|
||||
return new Uint8Array(await body.arrayBuffer());
|
||||
} else if (body instanceof FormData) {
|
||||
return body;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
} else if ((body as Iterable<Uint8Array>)[Symbol.iterator]) {
|
||||
const chunks = [...(body as Iterable<Uint8Array>)];
|
||||
const length = chunks.reduce((a, b) => a + b.length, 0);
|
||||
|
||||
const uint8 = new Uint8Array(length);
|
||||
let lengthUsed = 0;
|
||||
|
||||
return chunks.reduce((a, b) => {
|
||||
a.set(b, lengthUsed);
|
||||
lengthUsed += b.length;
|
||||
return a;
|
||||
}, uint8);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
} else if ((body as AsyncIterable<Uint8Array>)[Symbol.asyncIterator]) {
|
||||
const chunks: Uint8Array[] = [];
|
||||
|
||||
for await (const chunk of body as AsyncIterable<Uint8Array>) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
throw new TypeError(`Unable to resolve body.`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user