Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Client): add apiResponse and apiRequest events #6739

Merged
merged 4 commits into from Oct 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 19 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -52,6 +52,7 @@
"@discordjs/collection": "^0.2.1",
"@discordjs/form-data": "^3.0.1",
"@sapphire/async-queue": "^1.1.5",
"@types/node-fetch": "^2.5.12",
"@types/ws": "^8.2.0",
"discord-api-types": "^0.23.1",
"node-fetch": "^2.6.1",
Expand Down
63 changes: 62 additions & 1 deletion src/rest/RequestHandler.js
Expand Up @@ -5,7 +5,7 @@ const DiscordAPIError = require('./DiscordAPIError');
const HTTPError = require('./HTTPError');
const RateLimitError = require('./RateLimitError');
const {
Events: { DEBUG, RATE_LIMIT, INVALID_REQUEST_WARNING },
Events: { DEBUG, RATE_LIMIT, INVALID_REQUEST_WARNING, API_RESPONSE, API_REQUEST },
} = require('../util/Constants');
const Util = require('../util/Util');

Expand Down Expand Up @@ -162,6 +162,34 @@ class RequestHandler {
}
this.manager.globalRemaining--;

/**
* Represents a request that will or has been made to the Discord API
* @typedef {Object} APIRequest
* @property {HTTPMethod} method The HTTP method used in this request
* @property {string} path The full path used to make the request
* @property {string} route The API route identifying the ratelimit for this request
* @property {Object} options Additional options for this request
* @property {number} retries The number of times this request has been attempted
*/

if (this.manager.client.listenerCount(API_REQUEST)) {
/**
* Emitted before every API request.
* This event can emit several times for the same request, e.g. when hitting a rate limit.
* <info>This is an informational event that is emitted quite frequently,
* it is highly recommended to check `request.path` to filter the data.</info>
* @event Client#apiRequest
* @param {APIRequest} request The request that is about to be sent
*/
this.manager.client.emit(API_REQUEST, {
method: request.method,
path: request.path,
route: request.route,
options: request.options,
retries: request.retries,
});
}

// Perform the request
let res;
try {
Expand All @@ -176,6 +204,29 @@ class RequestHandler {
return this.execute(request);
}

if (this.manager.client.listenerCount(API_RESPONSE)) {
/**
* Emitted after every API request has received a response.
* This event does not necessarily correlate to completion of the request, e.g. when hitting a rate limit.
* <info>This is an informational event that is emitted quite frequently,
* it is highly recommended to check `request.path` to filter the data.</info>
* @event Client#apiResponse
* @param {APIRequest} request The request that triggered this response
* @param {Response} response The response received from the Discord API
*/
this.manager.client.emit(
API_RESPONSE,
{
method: request.method,
path: request.path,
route: request.route,
options: request.options,
retries: request.retries,
},
res.clone(),
);
}

let sublimitTimeout;
if (res.headers) {
const serverDate = res.headers.get('date');
Expand Down Expand Up @@ -315,3 +366,13 @@ class RequestHandler {
}

module.exports = RequestHandler;

/**
* @external HTTPMethod
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods}
*/

/**
* @external Response
iCrawl marked this conversation as resolved.
Show resolved Hide resolved
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Response}
*/
2 changes: 2 additions & 0 deletions src/util/Constants.js
Expand Up @@ -124,6 +124,8 @@ exports.Opcodes = {
exports.Events = {
RATE_LIMIT: 'rateLimit',
INVALID_REQUEST_WARNING: 'invalidRequestWarning',
API_RESPONSE: 'apiResponse',
API_REQUEST: 'apiRequest',
CLIENT_READY: 'ready',
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate',
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete',
Expand Down
13 changes: 13 additions & 0 deletions typings/index.d.ts
Expand Up @@ -49,6 +49,7 @@ import {
import { ChildProcess } from 'node:child_process';
import { EventEmitter } from 'node:events';
import { AgentOptions } from 'node:https';
import { Response } from 'node-fetch';
import { Stream } from 'node:stream';
import { MessagePort, Worker } from 'node:worker_threads';
import * as WebSocket from 'ws';
Expand Down Expand Up @@ -3129,6 +3130,14 @@ export interface APIErrors {
STICKER_ANIMATION_DURATION_EXCEEDS_MAXIMUM_OF_5_SECONDS: 170007;
}

export interface APIRequest {
method: 'get' | 'post' | 'delete' | 'patch' | 'put';
options: unknown;
path: string;
retries: number;
route: string;
}

export interface ApplicationAsset {
name: string;
id: Snowflake;
Expand Down Expand Up @@ -3439,6 +3448,8 @@ export interface ChannelWebhookCreateOptions {
}

export interface ClientEvents {
apiResponse: [request: APIRequest, response: Response];
apiRequest: [request: APIRequest];
applicationCommandCreate: [command: ApplicationCommand];
applicationCommandDelete: [command: ApplicationCommand];
applicationCommandUpdate: [oldCommand: ApplicationCommand | null, newCommand: ApplicationCommand];
Expand Down Expand Up @@ -3677,6 +3688,8 @@ export interface ConstantsColors {
export interface ConstantsEvents {
RATE_LIMIT: 'rateLimit';
INVALID_REQUEST_WARNING: 'invalidRequestWarning';
API_RESPONSE: 'apiResponse';
API_REQUEST: 'apiRequest';
CLIENT_READY: 'ready';
APPLICATION_COMMAND_CREATE: 'applicationCommandCreate';
APPLICATION_COMMAND_DELETE: 'applicationCommandDelete';
Expand Down