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:
Khafra
2022-05-12 16:49:15 -04:00
committed by GitHub
parent 4515a1ea80
commit d1ec8c37ff
19 changed files with 964 additions and 605 deletions

View File

@@ -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.`);
}