From 5fd1fe2c5c33893ac2432b51d048c584fe7a8483 Mon Sep 17 00:00:00 2001 From: Splatterxl Date: Thu, 5 May 2022 18:30:25 +0100 Subject: [PATCH] refactor(rest:manager): don't use client for options Signed-off-by: Splatterxl --- packages/fuwa/src/client/Client.ts | 19 ++++++---- packages/rest/__test__/index.js | 33 +++++++++++++++++ packages/rest/src/BucketQueueManager.ts | 13 +++---- packages/rest/src/RESTClient.ts | 28 ++++++++++----- packages/rest/src/RequestManager.ts | 43 ++++++++++++++--------- packages/rest/typings/RESTClient.d.ts | 1 + packages/rest/typings/RequestManager.d.ts | 16 ++++++--- 7 files changed, 110 insertions(+), 43 deletions(-) create mode 100644 packages/rest/__test__/index.js diff --git a/packages/fuwa/src/client/Client.ts b/packages/fuwa/src/client/Client.ts index ff6951c6..283f7862 100644 --- a/packages/fuwa/src/client/Client.ts +++ b/packages/fuwa/src/client/Client.ts @@ -153,18 +153,12 @@ export class Client extends EventEmitter { super(); this.options = Object.assign( + {}, DefaultClientOptions, options, ) as Required; this.options.intents = resolveIntents(this.options.intents!); this.#token = token; - this.http = new RequestManager( - new RESTClient( - RESTClient.createRESTOptions(this.options, this.#token, 'Bot'), - ), - this, - ); - this.ws = new GatewayManager(this); if (!this.options.logger) { this.logger = new DisabledLogger(); @@ -176,6 +170,17 @@ export class Client extends EventEmitter { this.logger = this.options.logger; } + this.http = new RequestManager( + new RESTClient( + RESTClient.createRESTOptions(this.options, this.#token, 'Bot'), + ), + { + timings: this.options.httpTimings, + logger: this.logger, + }, + ); + this.ws = new GatewayManager(this); + this.guilds = new GuildManager(this); this.users = new UserManager(this); this.channels = new ChannelManager(this); diff --git a/packages/rest/__test__/index.js b/packages/rest/__test__/index.js new file mode 100644 index 00000000..70b3c3a9 --- /dev/null +++ b/packages/rest/__test__/index.js @@ -0,0 +1,33 @@ +const REST = require('..'); +const assert = require('assert'); + +const manager = new REST.default( + new REST.RESTClient(REST.DefaultDiscordOptions), + { + timings: true, + logger: { + debug: console.log, + trace: console.log, + kleur: null + } + } +); + +manager.client.setAuth(process.env.DISCORD_TOKEN); + +assert.strictEqual(manager.client.getAuth(), process.env.DISCORD_TOKEN); +assert.strictEqual(manager.client.baseURL, REST.DefaultDiscordOptions.baseURL); +assert.strictEqual( + manager.client.options.userAgent, + REST.DefaultDiscordOptions.userAgent, +); +assert.strictEqual(manager.client.version, REST.DefaultDiscordOptions.version); + +manager + .queue('/gateway') + .then(res => res.body.json()) + .then(json => { + assert.deepStrictEqual(json, { + url: 'wss://gateway.discord.gg', + }); + }); diff --git a/packages/rest/src/BucketQueueManager.ts b/packages/rest/src/BucketQueueManager.ts index e607648c..07657fc4 100644 --- a/packages/rest/src/BucketQueueManager.ts +++ b/packages/rest/src/BucketQueueManager.ts @@ -80,14 +80,11 @@ export class BucketQueueManager { } } + #__log_header() { + return `[${this.manager.__log_header()} -> ${this.id}]`; + } + private debug(...data: any[]) { - this.manager._client?.debug( - `[${this.manager._client?.logger - .kleur() - .blueBright('REST')} => ${this.manager._client?.logger - .kleur() - .green(this.id)}]`, - ...data, - ); + this.manager.debug(this.#__log_header(), ...data); } } diff --git a/packages/rest/src/RESTClient.ts b/packages/rest/src/RESTClient.ts index 72f13ce1..bb03c2b9 100644 --- a/packages/rest/src/RESTClient.ts +++ b/packages/rest/src/RESTClient.ts @@ -1,6 +1,7 @@ import FormData from 'form-data'; import undici from 'undici'; -import { ResponseData } from 'undici/types/dispatcher'; +import { inspect } from 'util'; +import { RequestOptions, ResponseData } from 'undici/types/dispatcher'; import { APIRequest } from './APIRequest'; import { RouteLike } from './RequestManager.js'; @@ -63,6 +64,9 @@ export class RESTClient { this.#auth = auth; return this; } + public getAuth() { + return this.#auth; + } public createHeaders(request: APIRequest): Record { const headers: Record = request.headers ?? {}; @@ -173,10 +177,10 @@ export class RESTClient { public execute(request: APIRequest, tracefunc?: any): Promise { request = this.resolveBody(request); - const options: any = { - method: request.method, + const options: RequestOptions = { + method: request.method ?? 'GET', headers: this.createHeaders(request), - }, + } as RequestOptions, url = this.createURL(request); if (request.body) options.body = request.body; @@ -185,9 +189,14 @@ export class RESTClient { tracefunc( options.method, url, - '\n', - 'body:', - prettifyBody(options.headers['content-type'] ?? '', options.body), + options.body + ? prettifyBody( + options.headers![ + 'content-type' as keyof typeof options['headers'] + ], + options.body! as Buffer, + ) + : '', ); } @@ -206,7 +215,10 @@ export interface RESTClientOptions { function prettifyBody(contentType: string, body: Buffer) { if (contentType.startsWith('application/json')) { - return JSON.parse(body.toString()); + return inspect(JSON.parse(body.toString()), { + depth: null, + colors: false, + }); } return body?.toString(); diff --git a/packages/rest/src/RequestManager.ts b/packages/rest/src/RequestManager.ts index d453ade5..8f3a9230 100644 --- a/packages/rest/src/RequestManager.ts +++ b/packages/rest/src/RequestManager.ts @@ -7,10 +7,18 @@ import { APIError, parseErr, RateLimitedError, - RESTError + RESTError, } from './RESTError.js'; -// Yeah, copied from Discord.js because I can't even think for myself. +export interface RequestManagerOptions { + timings?: boolean; + logger?: { + debug?: (...args: any[]) => void; + trace?: (...args: any[]) => void; + kleur?: any; + }; +} + export class RequestManager { // maybe this'll be of some use someday // private buckets: Map = new Map(); @@ -28,12 +36,10 @@ export class RequestManager { /** When the global rate limit will reset. */ public reset = Date.now() + 1e3; - /** Whether to measure the timing of HTTP requests */ - public timings = false; - - constructor(public client: RESTClient, public _client?: any) { - if (_client?.options?.httpTimings) this.timings = true; - } + constructor( + public client: RESTClient, + public options: RequestManagerOptions = {}, + ) {} public get durUntilReset() { return this.reset + this.offset - Date.now(); @@ -60,7 +66,7 @@ export class RequestManager { bucket: BucketQueueManager, req: Required, ): Promise { - if (this.timings) req.httpStartTime = Date.now(); + if (this.options.timings) req.httpStartTime = Date.now(); const res = await this.client.execute(req, this.trace.bind(this)), now = Date.now(); @@ -71,7 +77,7 @@ export class RequestManager { `${req.method.toUpperCase()} ${req.route} -> ${res.statusCode} ${ STATUS_CODES[res.statusCode] }${ - this.timings + this.options.timings ? ` (${now - req.startTime}ms${ now - req.httpStartTime !== now - req.startTime ? ` full; ${now - req.httpStartTime}ms http` @@ -99,7 +105,7 @@ export class RequestManager { if (req.retries < req.allowedRetries) { req.retries++; - this._client.debug('got ratelimited at', bucket.id, '- retrying'); + this.debug('got ratelimited at', bucket.id, '- retrying'); return this.queue(req); } else { @@ -144,7 +150,7 @@ export class RequestManager { req = resolveRequest({ route: req, ...options }); } else req = resolveRequest(req); - if (this.timings) req.startTime = Date.now(); + if (this.options.timings) req.startTime = Date.now(); if (!req.useRateLimits) return this.makeRequest( @@ -172,15 +178,20 @@ export class RequestManager { } #__log_header() { - return `[${this._client?.logger.kleur().green('REST')}]`; + return `[${this.options?.logger?.kleur?.().green('REST') ?? 'REST'}]`; + } + + /** @ignore */ + __log_header() { + return this.#__log_header(); } - private debug(...args: any[]) { - this._client?.logger.debug(this.#__log_header(), ...args); + debug(...args: any[]) { + this.options?.logger?.debug?.(this.#__log_header(), ...args); } private trace(...args: any[]) { - this._client?.logger.trace('[REST]', ...args); + this.options?.logger?.trace?.('[REST]', ...args); } } diff --git a/packages/rest/typings/RESTClient.d.ts b/packages/rest/typings/RESTClient.d.ts index 12c07aa1..02eabdd6 100644 --- a/packages/rest/typings/RESTClient.d.ts +++ b/packages/rest/typings/RESTClient.d.ts @@ -10,6 +10,7 @@ export declare class RESTClient { static createRESTOptions(clientOptions: any, token: string, tokenType: 'Bot' | 'Bearer'): RESTClientOptions; static getDefaultOptions(token: string): Required; setAuth(auth: string): this; + getAuth(): string | undefined; createHeaders(request: APIRequest): Record; formatRoute(route: RouteLike, versioned?: boolean, useBase?: boolean): string; resolveBody(req: APIRequest): APIRequest; diff --git a/packages/rest/typings/RequestManager.d.ts b/packages/rest/typings/RequestManager.d.ts index dbdad41e..2f49f61d 100644 --- a/packages/rest/typings/RequestManager.d.ts +++ b/packages/rest/typings/RequestManager.d.ts @@ -2,17 +2,24 @@ import { ResponseData } from 'undici/types/dispatcher'; import { APIRequest } from './APIRequest.js'; import { BucketQueueManager } from './BucketQueueManager.js'; import { RESTClient } from './RESTClient'; +export interface RequestManagerOptions { + timings?: boolean; + logger?: { + debug?: (...args: any[]) => void; + trace?: (...args: any[]) => void; + kleur?: any; + }; +} export declare class RequestManager { #private; client: RESTClient; - _client?: any; + options: RequestManagerOptions; limit: number; offset: number; buckets: Map; remaining: number; reset: number; - timings: boolean; - constructor(client: RESTClient, _client?: any); + constructor(client: RESTClient, options?: RequestManagerOptions); get durUntilReset(): number; getBucket(route: RouteLike): string[]; get globalLimited(): boolean; @@ -20,7 +27,8 @@ export declare class RequestManager { queue(route: RouteLike, options?: Omit): Promise>; queue(req: APIRequest): Promise>; private updateOffset; - private debug; + __log_header(): string; + debug(...args: any[]): void; private trace; } export declare type RouteLike = `/${string}`;