From 7ba897827603dafd5e06b278e7602cfbf60cbf99 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Mon, 9 Nov 2020 16:33:57 +0530 Subject: [PATCH] feat(REST): Improved Error Handling. Now shows better Errors. --- src/managers/memberRoles.ts | 47 +++++++++++++++++++++++++++++++++++++ src/models/rest.ts | 35 +++++++++++++++------------ src/test/cmd.ts | 1 + 3 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 src/managers/memberRoles.ts diff --git a/src/managers/memberRoles.ts b/src/managers/memberRoles.ts new file mode 100644 index 0000000..6beefb0 --- /dev/null +++ b/src/managers/memberRoles.ts @@ -0,0 +1,47 @@ +import { Client } from '../models/client.ts' +import { CHANNEL } from '../types/endpoint.ts' +import { BaseChildManager } from './baseChild.ts' +import { RolePayload } from "../types/role.ts" +import { Role } from "../structures/role.ts" +import { Member } from "../structures/member.ts" +import { RolesManager } from "./roles.ts" +import { MemberPayload } from "../types/guild.ts" + +export class MemberRolesManager extends BaseChildManager< + RolePayload, + Role +> { + member: Member + + constructor (client: Client, parent: RolesManager, member: Member) { + super(client, parent as any) + this.member = member + } + + async get (id: string): Promise { + const res = await this.parent.get(id) + const mem = await (this.parent as any).guild.members.get(this.member.id) as MemberPayload + if (res !== undefined && mem.roles.includes(res.id) === true) return res + else return undefined + } + + async delete(id: string): Promise { + return this.client.rest.delete(CHANNEL(id)) + } + + async array (): Promise { + const arr = (await this.parent.array()) as Role[] + const mem = await (this.parent as any).guild.members.get(this.member.id) as MemberPayload + return arr.filter( + (c: any) => mem.roles.includes(c.id) + ) as any + } + + async flush (): Promise { + const arr = await this.array() + for (const elem of arr) { + this.parent.delete(elem.id) + } + return true + } +} diff --git a/src/models/rest.ts b/src/models/rest.ts index 24e468f..603b8ce 100644 --- a/src/models/rest.ts +++ b/src/models/rest.ts @@ -25,13 +25,13 @@ export interface RequestHeaders { } export interface QueuedItem { + bucket?: string | null + url: string onComplete: () => Promise<{ rateLimited: any bucket?: string | null before: boolean } | undefined> - bucket?: string | null - url: string } export interface RateLimit { @@ -93,10 +93,8 @@ export class RESTManager { request.bucket ) if (rateLimitResetIn !== false) { - // This request is still rate limited read to queue this.queue(request) } else { - // This request is not rate limited so it should be run const result = await request.onComplete() if (result?.rateLimited !== undefined) { this.queue({ @@ -107,10 +105,8 @@ export class RESTManager { } } else { if (rateLimitedURLResetIn !== false) { - // This URL is rate limited readd to queue this.queue(request) } else { - // This request has no bucket id so it should be processed const result = await request.onComplete() if (result?.rateLimited !== undefined) { this.queue({ @@ -253,27 +249,35 @@ export class RESTManager { } async handleStatusCode( - response: Response + response: Response, body: any, data: { [key: string]: any } ): Promise { const status = response.status - if ((status >= 200 && status < 400) || status === HttpResponseCode.TooManyRequests) return + if ( + (status >= 200 && status < 400) + || status === HttpResponseCode.NoContent + || status === HttpResponseCode.TooManyRequests + ) return - const body = await response.json() - const text = Deno.inspect(body.errors) + let text: undefined | string = Deno.inspect(body.errors === undefined ? body : body.errors) + if (text === 'undefined') text = undefined if (status === HttpResponseCode.Unauthorized) throw new Error(`Request was not successful (Unauthorized). Invalid Token.\n${text}`) + // At this point we know it is error + let error = { url: response.url, status, method: data.method, body: data.body } + if (body !== undefined) error = Object.assign(error, body) + if ([ HttpResponseCode.BadRequest, HttpResponseCode.NotFound, HttpResponseCode.Forbidden, HttpResponseCode.MethodNotAllowed ].includes(status)) { - throw new Error(`Request - Client Error. Code: ${status}\n${text}`) + throw new Error(Deno.inspect(error)) } else if (status === HttpResponseCode.GatewayUnavailable) { - throw new Error(`Request - Server Error. Code: ${status}\n${text}`) + throw new Error(Deno.inspect(error)) } else throw new Error('Request - Unknown Error') } @@ -319,12 +323,13 @@ export class RESTManager { const response = await fetch(urlToUse, requestData) const bucketFromHeaders = this.processHeaders(url, response.headers) - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.handleStatusCode(response) if (response.status === 204) return resolve(undefined) - const json = await response.json() + const json: any = await response.json() + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.handleStatusCode(response, json, requestData) + if ( json.retry_after !== undefined || json.message === 'You are being rate limited.' diff --git a/src/test/cmd.ts b/src/test/cmd.ts index d118a4a..4b27918 100644 --- a/src/test/cmd.ts +++ b/src/test/cmd.ts @@ -11,6 +11,7 @@ client.on('debug', console.log) client.on('ready', () => { console.log(`[Login] Logged in as ${client.user?.tag}!`) + client.rest.get('https://discord.com/api/v8/users/123') }) client.on('messageCreate', msg => console.log(`${msg.author.tag}: ${msg.content}`))