From f122b3603a160f2006c1161d5a135be9aa2ff314 Mon Sep 17 00:00:00 2001 From: Will Hoskings Date: Wed, 26 Feb 2020 20:09:16 +0000 Subject: [PATCH] Fiddle with the Request stuff --- module/discord-request-manager.ts | 15 +++++--- module/routed-request-manager.ts | 30 +++++++++++++++ structures/queue.ts | 61 +++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 module/routed-request-manager.ts create mode 100644 structures/queue.ts diff --git a/module/discord-request-manager.ts b/module/discord-request-manager.ts index f9d7452f1..45eb7d337 100644 --- a/module/discord-request-manager.ts +++ b/module/discord-request-manager.ts @@ -3,10 +3,10 @@ import { RequestMethod } from "../types/fetch.ts" // type RequestBody = string | Blob | ArrayBufferView | ArrayBuffer | FormData | URLSearchParams | null | undefined -export default class DiscordDiscordRequestManager { - constructor(public client: Client, public token: string) { +export default class DiscordRequestManager { + token = this.client.token; + constructor(public client: Client) { this.client = client; - this.token = token; } async get(url: string, body?: unknown) { @@ -35,18 +35,23 @@ export default class DiscordDiscordRequestManager { protected async runMethod (method: RequestMethod, url: string, body?: unknown) { const headers = this.getDiscordHeaders(); - return fetch(url, { + return fetch(this.resolveURL(url), { method, headers, body: body ? JSON.stringify(body) : undefined }); } + // A hook for the RouteAwareRequestManager to override URLs. + protected resolveURL (url: string) { + return url; + } + // The Record type here plays nice with Deno's `fetch.headers` expected type. getDiscordHeaders(): Record { return { Authorization: this.token, - "User-Agent": `DiscordBot (https://github.com/skillz4killz/discordeno, 0.0.1)` + "User-Agent": `Discordeno (https://github.com/skillz4killz/discordeno, 0.0.1)` } } } diff --git a/module/routed-request-manager.ts b/module/routed-request-manager.ts new file mode 100644 index 000000000..751dc04af --- /dev/null +++ b/module/routed-request-manager.ts @@ -0,0 +1,30 @@ +import DiscordRequestManager from "./discord-request-manager.ts"; +import Client from "./client"; +import { resolveURLs } from './url.ts'; +import { baseEndpoints } from '../constants/discord.ts'; + +export class RouteAwareDiscordRequestManager extends DiscordRequestManager{ + constructor (public client: Client, public routeName: string) { + super(client); + } + + protected resolveURL (url: string) { + return resolveURLs(baseEndpoints.BASE_URL, this.routeName, url); + } +} + +export class RoutedDiscordRequestManager { + protected routeMap = new Map(); + + constructor (public client: Client) {} + + forRoute (routeName: string) { + if (this.routeMap.has(routeName)) { + return this.routeMap.get(routeName); + } + + const routeRequestManager = new RouteAwareDiscordRequestManager(this.client, routeName); + this.routeMap.set(routeName, routeRequestManager); + return routeRequestManager; + } +} \ No newline at end of file diff --git a/structures/queue.ts b/structures/queue.ts new file mode 100644 index 000000000..f8004ad68 --- /dev/null +++ b/structures/queue.ts @@ -0,0 +1,61 @@ +import { DiscordPayload } from "../types/discord"; +import Gateway from "../module/gateway.ts"; + +export abstract class ActionQueue { + protected actions: Action[] = []; + + push (action: Action) { + if (this.shouldDispatchImmediately(action)) { + this.dispatch(action); + } else { + this.actions.push(action); + } + } + + async dispatchAll () { + let index = 0; + for (const action of this.actions) { + if (this.shouldDispatchImmediately(action)) { + this.actions.splice(index, 1); + await this.dispatch(action); + index++; + } + } + } + + abstract dispatch (action: Action): void | Promise; + abstract shouldDispatchImmediately (action: Action): boolean; +} + +export interface RatelimitDetails { + /** The number of requests that can be made */ + limit: number; + + /** The number of remaining requests that can be made */ + remaining: number; + + /** Epoch time (seconds since 00:00:00 UTC on January 1, 1970) at which the rate limit resets */ + reset: number; + + /** A unique string denoting the rate limit being encountered (non-inclusive of major parameters in the route path) */ + bucket: string; + + /** Total time (in seconds) of when the current rate limit bucket will reset. */ + resetAfter: number; +} + +export class RatelimitedActionQueue extends ActionQueue { + protected lastRatelimitDetails?: RatelimitDetails; + + constructor (protected gateway: Gateway) { + super(); + } + + dispatch (action: DiscordPayload) { + this.gateway.sendObject(action); + } + + shouldDispatchImmediately () { + return this.lastRatelimitDetails?.limit !== 0; + } +} \ No newline at end of file