Add files via upload

This commit is contained in:
Murat
2023-11-29 18:23:54 +03:00
committed by GitHub
parent bdb4e9d949
commit 119d0275bd
79 changed files with 23303 additions and 0 deletions

137
node_modules/eris/lib/rest/Endpoints.js generated vendored Normal file
View File

@ -0,0 +1,137 @@
"use strict";
const {REST_VERSION} = require("../Constants");
module.exports.BASE_URL = "/api/v" + REST_VERSION;
module.exports.CDN_URL = "https://cdn.discordapp.com";
module.exports.CLIENT_URL = "https://discord.com";
module.exports.ORIGINAL_INTERACTION_RESPONSE = (appID, interactToken) => `/webhooks/${appID}/${interactToken}`;
module.exports.COMMAND = (applicationID, commandID) => `/applications/${applicationID}/commands/${commandID}`;
module.exports.COMMANDS = (applicationID) => `/applications/${applicationID}/commands`;
module.exports.COMMAND_PERMISSIONS = (applicationID, guildID, commandID) => `/applications/${applicationID}/guilds/${guildID}/commands/${commandID}/permissions`;
module.exports.CHANNEL = (chanID) => `/channels/${chanID}`;
module.exports.CHANNEL_BULK_DELETE = (chanID) => `/channels/${chanID}/messages/bulk-delete`;
module.exports.CHANNEL_CALL_RING = (chanID) => `/channels/${chanID}/call/ring`;
module.exports.CHANNEL_CROSSPOST = (chanID, msgID) => `/channels/${chanID}/messages/${msgID}/crosspost`;
module.exports.CHANNEL_FOLLOW = (chanID) => `/channels/${chanID}/followers`;
module.exports.CHANNEL_INVITES = (chanID) => `/channels/${chanID}/invites`;
module.exports.CHANNEL_MESSAGE_REACTION = (chanID, msgID, reaction) => `/channels/${chanID}/messages/${msgID}/reactions/${reaction}`;
module.exports.CHANNEL_MESSAGE_REACTION_USER = (chanID, msgID, reaction, userID) => `/channels/${chanID}/messages/${msgID}/reactions/${reaction}/${userID}`;
module.exports.CHANNEL_MESSAGE_REACTIONS = (chanID, msgID) => `/channels/${chanID}/messages/${msgID}/reactions`;
module.exports.CHANNEL_MESSAGE = (chanID, msgID) => `/channels/${chanID}/messages/${msgID}`;
module.exports.CHANNEL_MESSAGES = (chanID) => `/channels/${chanID}/messages`;
module.exports.CHANNEL_MESSAGES_SEARCH = (chanID) => `/channels/${chanID}/messages/search`;
module.exports.CHANNEL_PERMISSION = (chanID, overID) => `/channels/${chanID}/permissions/${overID}`;
module.exports.CHANNEL_PERMISSIONS = (chanID) => `/channels/${chanID}/permissions`;
module.exports.CHANNEL_PIN = (chanID, msgID) => `/channels/${chanID}/pins/${msgID}`;
module.exports.CHANNEL_PINS = (chanID) => `/channels/${chanID}/pins`;
module.exports.CHANNEL_RECIPIENT = (groupID, userID) => `/channels/${groupID}/recipients/${userID}`;
module.exports.CHANNEL_TYPING = (chanID) => `/channels/${chanID}/typing`;
module.exports.CHANNEL_WEBHOOKS = (chanID) => `/channels/${chanID}/webhooks`;
module.exports.CHANNELS = "/channels";
module.exports.CUSTOM_EMOJI_GUILD = (emojiID) => `/emojis/${emojiID}/guild`;
module.exports.DISCOVERY_CATEGORIES = "/discovery/categories";
module.exports.DISCOVERY_VALIDATION = "/discovery/valid-term";
module.exports.GATEWAY = "/gateway";
module.exports.GATEWAY_BOT = "/gateway/bot";
module.exports.GUILD = (guildID) => `/guilds/${guildID}`;
module.exports.GUILD_AUDIT_LOGS = (guildID) => `/guilds/${guildID}/audit-logs`;
module.exports.GUILD_BAN = (guildID, memberID) => `/guilds/${guildID}/bans/${memberID}`;
module.exports.GUILD_BANS = (guildID) => `/guilds/${guildID}/bans`;
module.exports.GUILD_CHANNELS = (guildID) => `/guilds/${guildID}/channels`;
module.exports.GUILD_COMMAND = (applicationID, guildID, commandID) => `/applications/${applicationID}/guilds/${guildID}/commands/${commandID}`;
module.exports.GUILD_COMMAND_PERMISSIONS = (applicationID, guildID) => `/applications/${applicationID}/guilds/${guildID}/commands/permissions`;
module.exports.GUILD_COMMANDS = (applicationID, guildID) => `/applications/${applicationID}/guilds/${guildID}/commands`;
module.exports.GUILD_DISCOVERY = (guildID) => `/guilds/${guildID}/discovery-metadata`;
module.exports.GUILD_DISCOVERY_CATEGORY = (guildID, categoryID) => `/guilds/${guildID}/discovery-categories/${categoryID}`;
module.exports.GUILD_EMOJI = (guildID, emojiID) => `/guilds/${guildID}/emojis/${emojiID}`;
module.exports.GUILD_EMOJIS = (guildID) => `/guilds/${guildID}/emojis`;
module.exports.GUILD_INTEGRATION = (guildID, inteID) => `/guilds/${guildID}/integrations/${inteID}`;
module.exports.GUILD_INTEGRATION_SYNC = (guildID, inteID) => `/guilds/${guildID}/integrations/${inteID}/sync`;
module.exports.GUILD_INTEGRATIONS = (guildID) => `/guilds/${guildID}/integrations`;
module.exports.GUILD_INVITES = (guildID) => `/guilds/${guildID}/invites`;
module.exports.GUILD_VANITY_URL = (guildID) => `/guilds/${guildID}/vanity-url`;
module.exports.GUILD_MEMBER = (guildID, memberID) => `/guilds/${guildID}/members/${memberID}`;
module.exports.GUILD_MEMBER_NICK = (guildID, memberID) => `/guilds/${guildID}/members/${memberID}/nick`;
module.exports.GUILD_MEMBER_ROLE = (guildID, memberID, roleID) => `/guilds/${guildID}/members/${memberID}/roles/${roleID}`;
module.exports.GUILD_MEMBERS = (guildID) => `/guilds/${guildID}/members`;
module.exports.GUILD_MEMBERS_SEARCH = (guildID) => `/guilds/${guildID}/members/search`;
module.exports.GUILD_MESSAGES_SEARCH = (guildID) => `/guilds/${guildID}/messages/search`;
module.exports.GUILD_PREVIEW = (guildID) => `/guilds/${guildID}/preview`;
module.exports.GUILD_PRUNE = (guildID) => `/guilds/${guildID}/prune`;
module.exports.GUILD_ROLE = (guildID, roleID) => `/guilds/${guildID}/roles/${roleID}`;
module.exports.GUILD_ROLES = (guildID) => `/guilds/${guildID}/roles`;
module.exports.GUILD_SCHEDULED_EVENT = (guildID, scheduledEventID) => `/guilds/${guildID}/scheduled-events/${scheduledEventID}`;
module.exports.GUILD_SCHEDULED_EVENT_USERS = (guildID, scheduledEventID) => `/guilds/${guildID}/scheduled-events/${scheduledEventID}/users`;
module.exports.GUILD_SCHEDULED_EVENTS = (guildID) => `/guilds/${guildID}/scheduled-events`;
module.exports.GUILD_STICKER = (guildID, stickerID) => `/guilds/${guildID}/stickers/${stickerID}`;
module.exports.GUILD_STICKERS = (guildID) => `/guilds/${guildID}/stickers`;
module.exports.GUILD_TEMPLATE = (code) => `/guilds/templates/${code}`;
module.exports.GUILD_TEMPLATES = (guildID) => `/guilds/${guildID}/templates`;
module.exports.GUILD_TEMPLATE_GUILD = (guildID, code) => `/guilds/${guildID}/templates/${code}`;
module.exports.GUILD_VOICE_REGIONS = (guildID) => `/guilds/${guildID}/regions`;
module.exports.GUILD_WEBHOOKS = (guildID) => `/guilds/${guildID}/webhooks`;
module.exports.GUILD_WELCOME_SCREEN = (guildID) => `/guilds/${guildID}/welcome-screen`;
module.exports.GUILD_WIDGET = (guildID) => `/guilds/${guildID}/widget.json`;
module.exports.GUILD_WIDGET_SETTINGS = (guildID) => `/guilds/${guildID}/widget`;
module.exports.GUILD_VOICE_STATE = (guildID, user) => `/guilds/${guildID}/voice-states/${user}`;
module.exports.GUILDS = "/guilds";
module.exports.INTERACTION_RESPOND = (interactID, interactToken) => `/interactions/${interactID}/${interactToken}/callback`;
module.exports.INVITE = (inviteID) => `/invites/${inviteID}`;
module.exports.OAUTH2_APPLICATION = (appID) => `/oauth2/applications/${appID}`;
module.exports.STAGE_INSTANCE = (channelID) => `/stage-instances/${channelID}`;
module.exports.STAGE_INSTANCES = "/stage-instances";
module.exports.STICKER = (stickerID) => `/stickers/${stickerID}`;
module.exports.STICKER_PACKS = "/sticker-packs";
module.exports.THREAD_MEMBER = (channelID, userID) => `/channels/${channelID}/thread-members/${userID}`;
module.exports.THREAD_MEMBERS = (channelID) => `/channels/${channelID}/thread-members`;
module.exports.THREAD_WITH_MESSAGE = (channelID, msgID) => `/channels/${channelID}/messages/${msgID}/threads`;
module.exports.THREAD_WITHOUT_MESSAGE = (channelID) => `/channels/${channelID}/threads`;
module.exports.THREADS_ACTIVE = (channelID) => `/channels/${channelID}/threads/active`;
module.exports.THREADS_ARCHIVED = (channelID, type) => `/channels/${channelID}/threads/archived/${type}`;
module.exports.THREADS_ARCHIVED_JOINED = (channelID) => `/channels/${channelID}/users/@me/threads/archived/private`;
module.exports.THREADS_GUILD_ACTIVE = (guildID) => `/guilds/${guildID}/threads/active`;
module.exports.USER = (userID) => `/users/${userID}`;
module.exports.USER_BILLING = (userID) => `/users/${userID}/billing`;
module.exports.USER_BILLING_PAYMENTS = (userID) => `/users/${userID}/billing/payments`;
module.exports.USER_BILLING_PREMIUM_SUBSCRIPTION = (userID) => `/users/${userID}/billing/premium-subscription`;
module.exports.USER_CHANNELS = (userID) => `/users/${userID}/channels`;
module.exports.USER_CONNECTIONS = (userID) => `/users/${userID}/connections`;
module.exports.USER_CONNECTION_PLATFORM = (userID, platform, id) => `/users/${userID}/connections/${platform}/${id}`;
module.exports.USER_GUILD = (userID, guildID) => `/users/${userID}/guilds/${guildID}`;
module.exports.USER_GUILDS = (userID) => `/users/${userID}/guilds`;
module.exports.USER_MFA_CODES = (userID) => `/users/${userID}/mfa/codes`;
module.exports.USER_MFA_TOTP_DISABLE = (userID) => `/users/${userID}/mfa/totp/disable`;
module.exports.USER_MFA_TOTP_ENABLE = (userID) => `/users/${userID}/mfa/totp/enable`;
module.exports.USER_NOTE = (userID, targetID) => `/users/${userID}/note/${targetID}`;
module.exports.USER_PROFILE = (userID) => `/users/${userID}/profile`;
module.exports.USER_RELATIONSHIP = (userID, relID) => `/users/${userID}/relationships/${relID}`;
module.exports.USER_SETTINGS = (userID) => `/users/${userID}/settings`;
module.exports.USERS = "/users";
module.exports.VOICE_REGIONS = "/voice/regions";
module.exports.WEBHOOK = (hookID) => `/webhooks/${hookID}`;
module.exports.WEBHOOK_MESSAGE = (hookID, token, msgID) => `/webhooks/${hookID}/${token}/messages/${msgID}`;
module.exports.WEBHOOK_SLACK = (hookID) => `/webhooks/${hookID}/slack`;
module.exports.WEBHOOK_TOKEN = (hookID, token) => `/webhooks/${hookID}/${token}`;
module.exports.WEBHOOK_TOKEN_SLACK = (hookID, token) => `/webhooks/${hookID}/${token}/slack`;
// CDN Endpoints
module.exports.ACHIEVEMENT_ICON = (applicationID, achievementID, icon) => `/app-assets/${applicationID}/achievements/${achievementID}/icons/${icon}`;
module.exports.APPLICATION_ASSET = (applicationID, asset) => `/app-assets/${applicationID}/${asset}`;
module.exports.APPLICATION_ICON = (applicationID, icon) => `/app-icons/${applicationID}/${icon}`;
module.exports.BANNER = (guildOrUserID, hash) => `/banners/${guildOrUserID}/${hash}`;
module.exports.CHANNEL_ICON = (chanID, chanIcon) => `/channel-icons/${chanID}/${chanIcon}`;
module.exports.CUSTOM_EMOJI = (emojiID) => `/emojis/${emojiID}`;
module.exports.DEFAULT_USER_AVATAR = (userDiscriminator) => `/embed/avatars/${userDiscriminator}`;
module.exports.GUILD_AVATAR = (guildID, userID, guildAvatar) => `/guilds/${guildID}/users/${userID}/avatars/${guildAvatar}`;
module.exports.GUILD_DISCOVERY_SPLASH = (guildID, guildDiscoverySplash) => `/discovery-splashes/${guildID}/${guildDiscoverySplash}`;
module.exports.GUILD_ICON = (guildID, guildIcon) => `/icons/${guildID}/${guildIcon}`;
module.exports.GUILD_SCHEDULED_EVENT_COVER = (eventID, eventIcon) => `/guild-events/${eventID}/${eventIcon}`;
module.exports.GUILD_SPLASH = (guildID, guildSplash) => `/splashes/${guildID}/${guildSplash}`;
module.exports.ROLE_ICON = (roleID, roleIcon) => `/role-icons/${roleID}/${roleIcon}`;
module.exports.TEAM_ICON = (teamID, teamIcon) => `/team-icons/${teamID}/${teamIcon}`;
module.exports.USER_AVATAR = (userID, userAvatar) => `/avatars/${userID}/${userAvatar}`;
// Client Endpoints
module.exports.MESSAGE_LINK = (guildID, channelID, messageID) => `/channels/${guildID}/${channelID}/${messageID}`;

451
node_modules/eris/lib/rest/RequestHandler.js generated vendored Normal file
View File

@ -0,0 +1,451 @@
"use strict";
const util = require("util");
const Base = require("../structures/Base");
const DiscordHTTPError = require("../errors/DiscordHTTPError");
const DiscordRESTError = require("../errors/DiscordRESTError");
const Endpoints = require("./Endpoints");
const HTTPS = require("https");
const MultipartData = require("../util/MultipartData");
const SequentialBucket = require("../util/SequentialBucket");
const Zlib = require("zlib");
/**
* Handles API requests
*/
class RequestHandler {
constructor(client, options) {
// [DEPRECATED] Previously forceQueueing
if(typeof options === "boolean") {
options = {
forceQueueing: options
};
}
this.options = options = Object.assign({
agent: client.options.agent || null,
baseURL: Endpoints.BASE_URL,
decodeReasons: true,
disableLatencyCompensation: false,
domain: "discord.com",
latencyThreshold: client.options.latencyThreshold || 30000,
ratelimiterOffset: client.options.ratelimiterOffset || 0,
requestTimeout: client.options.requestTimeout || 15000
}, options);
this._client = client;
this.userAgent = `DiscordBot (https://github.com/abalabahaha/eris, ${require("../../package.json").version})`;
this.ratelimits = {};
this.latencyRef = {
latency: this.options.ratelimiterOffset,
raw: new Array(10).fill(this.options.ratelimiterOffset),
timeOffset: 0,
timeOffsets: new Array(10).fill(0),
lastTimeOffsetCheck: 0
};
this.globalBlock = false;
this.readyQueue = [];
if(this.options.forceQueueing) {
this.globalBlock = true;
this._client.once("shardPreReady", () => this.globalUnblock());
}
}
globalUnblock() {
this.globalBlock = false;
while(this.readyQueue.length > 0) {
this.readyQueue.shift()();
}
}
/**
* Make an API request
* @arg {String} method Uppercase HTTP method
* @arg {String} url URL of the endpoint
* @arg {Boolean} [auth] Whether to add the Authorization header and token or not
* @arg {Object} [body] Request payload
* @arg {Object} [file] File object
* @arg {Buffer} file.file A buffer containing file data
* @arg {String} file.name What to name the file
* @returns {Promise<Object>} Resolves with the returned JSON data
*/
request(method, url, auth, body, file, _route, short) {
const route = _route || this.routefy(url, method);
const _stackHolder = {}; // Preserve async stack
Error.captureStackTrace(_stackHolder);
return new Promise((resolve, reject) => {
let attempts = 0;
const actualCall = (cb) => {
const headers = {
"User-Agent": this.userAgent,
"Accept-Encoding": "gzip,deflate"
};
let data;
let finalURL = url;
try {
if(auth) {
headers.Authorization = this._client._token;
}
if(body && body.reason) { // Audit log reason sniping
let unencodedReason = body.reason;
if(this.options.decodeReasons) {
try {
if(unencodedReason.includes("%") && !unencodedReason.includes(" ")) {
unencodedReason = decodeURIComponent(unencodedReason);
}
} catch(err) {
this._client.emit("error", err);
}
}
headers["X-Audit-Log-Reason"] = encodeURIComponent(unencodedReason);
if((method !== "PUT" || !url.includes("/bans")) && (method !== "POST" || !url.includes("/prune"))) {
delete body.reason;
} else {
body.reason = unencodedReason;
}
}
if(file) {
if(Array.isArray(file)) {
data = new MultipartData();
headers["Content-Type"] = "multipart/form-data; boundary=" + data.boundary;
file.forEach(function(f) {
if(!f.file) {
return;
}
data.attach(f.name, f.file, f.name);
});
if(body) {
data.attach("payload_json", body);
}
data = data.finish();
} else if(file.file) {
data = new MultipartData();
headers["Content-Type"] = "multipart/form-data; boundary=" + data.boundary;
data.attach("file", file.file, file.name);
if(body) {
if(method === "POST" && url.endsWith("/stickers")) {
for(const key in body) {
data.attach(key, body[key]);
}
} else {
data.attach("payload_json", body);
}
}
data = data.finish();
} else {
throw new Error("Invalid file object");
}
} else if(body) {
if(method === "GET" || method === "DELETE") {
let qs = "";
Object.keys(body).forEach(function(key) {
if(body[key] != undefined) {
if(Array.isArray(body[key])) {
body[key].forEach(function(val) {
qs += `&${encodeURIComponent(key)}=${encodeURIComponent(val)}`;
});
} else {
qs += `&${encodeURIComponent(key)}=${encodeURIComponent(body[key])}`;
}
}
});
finalURL += "?" + qs.substring(1);
} else {
// Replacer function serializes bigints to strings, the format Discord uses
data = JSON.stringify(body, (k, v) => typeof v === "bigint" ? v.toString() : v);
headers["Content-Type"] = "application/json";
}
}
} catch(err) {
cb();
reject(err);
return;
}
let req;
try {
req = HTTPS.request({
method: method,
host: this.options.domain,
path: this.options.baseURL + finalURL,
headers: headers,
agent: this.options.agent
});
} catch(err) {
cb();
reject(err);
return;
}
let reqError;
req.once("abort", () => {
cb();
reqError = reqError || new Error(`Request aborted by client on ${method} ${url}`);
reqError.req = req;
reject(reqError);
}).once("error", (err) => {
reqError = err;
req.abort();
});
let latency = Date.now();
req.once("response", (resp) => {
latency = Date.now() - latency;
if(!this.options.disableLatencyCompensation) {
this.latencyRef.raw.push(latency);
this.latencyRef.latency = this.latencyRef.latency - ~~(this.latencyRef.raw.shift() / 10) + ~~(latency / 10);
}
if(this._client.listeners("rawREST").length) {
/**
* Fired when the Client's RequestHandler receives a response
* @event Client#rawREST
* @prop {Object} [request] The data for the request.
* @prop {Boolean} request.auth True if the request required an authorization token
* @prop {Object} [request.body] The request payload
* @prop {Object} [request.file] The file object sent in the request
* @prop {Buffer} request.file.file A buffer containing file data
* @prop {String} request.file.name The name of the file
* @prop {Number} request.latency The HTTP response latency
* @prop {String} request.method Uppercase HTTP method
* @prop {IncomingMessage} request.resp The HTTP response to the request
* @prop {String} request.route The calculated ratelimiting route for the request
* @prop {Boolean} request.short Whether or not the request was prioritized in its ratelimiting queue
* @prop {String} request.url URL of the endpoint
*/
this._client.emit("rawREST", {method, url, auth, body, file, route, short, resp, latency});
}
const headerNow = Date.parse(resp.headers["date"]);
if(this.latencyRef.lastTimeOffsetCheck < Date.now() - 5000) {
const timeOffset = headerNow + 500 - (this.latencyRef.lastTimeOffsetCheck = Date.now());
if(this.latencyRef.timeOffset - this.latencyRef.latency >= this.options.latencyThreshold && timeOffset - this.latencyRef.latency >= this.options.latencyThreshold) {
this._client.emit("warn", new Error(`Your clock is ${this.latencyRef.timeOffset}ms behind Discord's server clock. Please check your connection and system time.`));
}
this.latencyRef.timeOffset = this.latencyRef.timeOffset - ~~(this.latencyRef.timeOffsets.shift() / 10) + ~~(timeOffset / 10);
this.latencyRef.timeOffsets.push(timeOffset);
}
resp.once("aborted", () => {
cb();
reqError = reqError || new Error(`Request aborted by server on ${method} ${url}`);
reqError.req = req;
reject(reqError);
});
let response = "";
let _respStream = resp;
if(resp.headers["content-encoding"]) {
if(resp.headers["content-encoding"].includes("gzip")) {
_respStream = resp.pipe(Zlib.createGunzip());
} else if(resp.headers["content-encoding"].includes("deflate")) {
_respStream = resp.pipe(Zlib.createInflate());
}
}
_respStream.on("data", (str) => {
response += str;
}).on("error", (err) => {
reqError = err;
req.abort();
}).once("end", () => {
const now = Date.now();
if(resp.headers["x-ratelimit-limit"]) {
this.ratelimits[route].limit = +resp.headers["x-ratelimit-limit"];
}
if(method !== "GET" && (resp.headers["x-ratelimit-remaining"] == undefined || resp.headers["x-ratelimit-limit"] == undefined) && this.ratelimits[route].limit !== 1) {
this._client.emit("debug", `Missing ratelimit headers for SequentialBucket(${this.ratelimits[route].remaining}/${this.ratelimits[route].limit}) with non-default limit\n`
+ `${resp.statusCode} ${resp.headers["content-type"]}: ${method} ${route} | ${resp.headers["cf-ray"]}\n`
+ "content-type = " + + "\n"
+ "x-ratelimit-remaining = " + resp.headers["x-ratelimit-remaining"] + "\n"
+ "x-ratelimit-limit = " + resp.headers["x-ratelimit-limit"] + "\n"
+ "x-ratelimit-reset = " + resp.headers["x-ratelimit-reset"] + "\n"
+ "x-ratelimit-global = " + resp.headers["x-ratelimit-global"]);
}
this.ratelimits[route].remaining = resp.headers["x-ratelimit-remaining"] === undefined ? 1 : +resp.headers["x-ratelimit-remaining"] || 0;
const retryAfter = Number(resp.headers["x-ratelimit-reset-after"] || resp.headers["retry-after"]) * 1000;
if(retryAfter >= 0) {
if(resp.headers["x-ratelimit-global"]) {
this.globalBlock = true;
setTimeout(() => this.globalUnblock(), retryAfter || 1);
} else {
this.ratelimits[route].reset = (retryAfter || 1) + now;
}
} else if(resp.headers["x-ratelimit-reset"]) {
let resetTime = +resp.headers["x-ratelimit-reset"] * 1000;
if(route.endsWith("/reactions/:id") && (+resp.headers["x-ratelimit-reset"] * 1000 - headerNow) === 1000) {
resetTime = now + 250;
}
this.ratelimits[route].reset = Math.max(resetTime - this.latencyRef.latency, now);
} else {
this.ratelimits[route].reset = now;
}
if(resp.statusCode !== 429) {
const content = typeof body === "object" ? `${body.content} ` : "";
this._client.emit("debug", `${content}${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${this.ratelimits[route].reset} (${this.ratelimits[route].reset - now}ms left)`);
}
if(resp.statusCode >= 300) {
if(resp.statusCode === 429) {
const content = typeof body === "object" ? `${body.content} ` : "";
let delay = retryAfter;
if(resp.headers["x-ratelimit-scope"] === "shared") {
try {
delay = JSON.parse(response).retry_after * 1000;
} catch(err) {
reject(err);
return;
}
}
this._client.emit("debug", `${resp.headers["x-ratelimit-global"] ? "Global" : "Unexpected"} 429 (╯°□°)╯︵ ┻━┻: ${response}\n${content} ${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${delay} (${this.ratelimits[route].reset - now}ms left) | Scope ${resp.headers["x-ratelimit-scope"]}`);
if(delay) {
setTimeout(() => {
cb();
this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
}, delay);
return;
} else {
cb();
this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
return;
}
} else if(resp.statusCode === 502 && ++attempts < 4) {
this._client.emit("debug", "A wild 502 appeared! Thanks CloudFlare!");
setTimeout(() => {
this.request(method, url, auth, body, file, route, true).then(resolve).catch(reject);
}, Math.floor(Math.random() * 1900 + 100));
return cb();
}
cb();
if(response.length > 0) {
if(resp.headers["content-type"] === "application/json") {
try {
response = JSON.parse(response);
} catch(err) {
reject(err);
return;
}
}
}
let {stack} = _stackHolder;
if(stack.startsWith("Error\n")) {
stack = stack.substring(6);
}
let err;
if(response.code) {
err = new DiscordRESTError(req, resp, response, stack);
} else {
err = new DiscordHTTPError(req, resp, response, stack);
}
reject(err);
return;
}
if(response.length > 0) {
if(resp.headers["content-type"] === "application/json") {
try {
response = JSON.parse(response);
} catch(err) {
cb();
reject(err);
return;
}
}
}
cb();
resolve(response);
});
});
req.setTimeout(this.options.requestTimeout, () => {
reqError = new Error(`Request timed out (>${this.options.requestTimeout}ms) on ${method} ${url}`);
req.abort();
});
if(Array.isArray(data)) {
for(const chunk of data) {
req.write(chunk);
}
req.end();
} else {
req.end(data);
}
};
if(this.globalBlock && auth) {
this.readyQueue.push(() => {
if(!this.ratelimits[route]) {
this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
}
this.ratelimits[route].queue(actualCall, short);
});
} else {
if(!this.ratelimits[route]) {
this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
}
this.ratelimits[route].queue(actualCall, short);
}
});
}
routefy(url, method) {
let route = url.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function(match, p) {
return p === "channels" || p === "guilds" || p === "webhooks" ? match : `/${p}/:id`;
}).replace(/\/reactions\/[^/]+/g, "/reactions/:id").replace(/\/reactions\/:id\/[^/]+/g, "/reactions/:id/:userID").replace(/^\/webhooks\/(\d+)\/[A-Za-z0-9-_]{64,}/, "/webhooks/$1/:token");
if(method === "DELETE" && route.endsWith("/messages/:id")) {
const messageID = url.slice(url.lastIndexOf("/") + 1);
const createdAt = Base.getCreatedAt(messageID);
if(Date.now() - this.latencyRef.latency - createdAt >= 1000 * 60 * 60 * 24 * 14) {
method += "_OLD";
} else if(Date.now() - this.latencyRef.latency - createdAt <= 1000 * 10) {
method += "_NEW";
}
route = method + route;
} else if(method === "GET" && /\/guilds\/[0-9]+\/channels$/.test(route)) {
route = "/guilds/:id/channels";
}
if(method === "PUT" || method === "DELETE") {
const index = route.indexOf("/reactions");
if(index !== -1) {
route = "MODIFY" + route.slice(0, index + 10);
}
}
return route;
}
[util.inspect.custom]() {
return Base.prototype[util.inspect.custom].call(this);
}
toString() {
return "[RequestHandler]";
}
toJSON(props = []) {
return Base.prototype.toJSON.call(this, [
"globalBlock",
"latencyRef",
"options",
"ratelimits",
"readyQueue",
"userAgent",
...props
]);
}
}
module.exports = RequestHandler;