This repository has been archived by the owner on Apr 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
177 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { DiscordFetchOptions } from './Fetch'; | ||
import type { Rest } from '../struct'; | ||
|
||
export interface BucketConstructor { | ||
makeRoute(method: string, url: string): string; | ||
new (rest: Rest, route: string): BaseBucket; | ||
} | ||
|
||
/** | ||
* Base bucket class - used to deal with all of the HTTP semantics | ||
*/ | ||
export abstract class BaseBucket { | ||
/** | ||
* Time after a Bucket is destroyed if unused | ||
*/ | ||
public static readonly BUCKET_TTL = 1e4; | ||
|
||
/** | ||
* Creates a simple API route representation (e.g. /users/:id), used as an identifier for each bucket. | ||
* | ||
* Credit to https://github.com/abalabahaha/eris | ||
*/ | ||
public static makeRoute(method: string, url: string) { | ||
let route = url | ||
.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, (match, p) => (['channels', 'guilds', 'webhook'].includes(p) ? match : `/${p}/:id`)) | ||
.replace(/\/invites\/[\w\d-]{2,}/g, '/invites/:code') | ||
.replace(/\/reactions\/[^/]+/g, '/reactions/:id') | ||
.replace(/^\/webhooks\/(\d+)\/[A-Za-z0-9-_]{64,}/, '/webhooks/$1/:token') | ||
.replace(/\?.*$/, ''); | ||
|
||
// Message deletes have their own rate limit | ||
if (method === 'delete' && route.endsWith('/messages/:id')) { | ||
route = method + route; | ||
} | ||
|
||
// In this case, /channels/[idHere]/messages is correct, | ||
// however /channels/[idHere] is not. we need "/channels/:id" | ||
if (/^\/channels\/[0-9]{17,19}$/.test(route)) { | ||
route = route.replace(/[0-9]{17,19}/, ':id'); | ||
} | ||
|
||
return route; | ||
} | ||
|
||
protected readonly _destroyTimeout: NodeJS.Timeout; | ||
|
||
public ['constructor']!: typeof BaseBucket; | ||
|
||
public constructor( | ||
public readonly rest: Rest, | ||
public readonly route: string | ||
) { | ||
// This is in the base constructor for backwards compatibility - in the future it'll be only in the Bucket class | ||
this._destroyTimeout = setTimeout(() => this.rest.buckets.delete(this.route), this.constructor.BUCKET_TTL).unref(); | ||
} | ||
|
||
/** | ||
* Shortcut for the manager mutex | ||
*/ | ||
public get mutex() { | ||
return this.rest.mutex; | ||
} | ||
|
||
/** | ||
* Makes a request to Discord | ||
* @param req Request options | ||
*/ | ||
public abstract make<T, D, Q>(req: DiscordFetchOptions<D, Q>): Promise<T>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { discordFetch, DiscordFetchOptions } from './Fetch'; | ||
import { CordisRestError, HTTPError } from '../Error'; | ||
import { BaseBucket } from './BaseBucket'; | ||
import type { Rest } from '../struct'; | ||
|
||
/** | ||
* Data held to represent ratelimit state for a Bucket | ||
*/ | ||
export interface RatelimitData { | ||
global: boolean; | ||
limit: number; | ||
timeout: number; | ||
remaining: number; | ||
} | ||
|
||
/** | ||
* Unconventional Bucket implementation that will hijack all requests (i.e. there is no seperate bucket depending on the route) | ||
* | ||
* This is meant for proxying requests, but will not handle any ratelimiting and will entirely ignore mutexes | ||
*/ | ||
export class ProxyBucket extends BaseBucket { | ||
public static override makeRoute() { | ||
return 'proxy'; | ||
} | ||
|
||
public constructor( | ||
rest: Rest, | ||
route: string | ||
) { | ||
super(rest, route); | ||
// This shouldn't be needed - but for backwards compatibility BaseBucket sets this timeout still | ||
clearTimeout(this._destroyTimeout); | ||
} | ||
|
||
public async make<T, D, Q>(req: DiscordFetchOptions<D, Q>): Promise<T> { | ||
let timeout: NodeJS.Timeout; | ||
if (req.implicitAbortBehavior) { | ||
timeout = setTimeout(() => req.controller.abort(), this.rest.abortAfter); | ||
} | ||
|
||
const res = await discordFetch(req).finally(() => clearTimeout(timeout)); | ||
|
||
if (res.status === 429) { | ||
return Promise.reject(new CordisRestError('rateLimited', `${req.method.toUpperCase()} ${req.path}`)); | ||
} else if (res.status >= 500 && res.status < 600) { | ||
return Promise.reject(new CordisRestError('internal', `${req.method.toUpperCase()} ${req.path}`)); | ||
} else if (!res.ok) { | ||
return Promise.reject(new HTTPError(res.clone(), await res.text())); | ||
} | ||
|
||
if (res.headers.get('content-type')?.startsWith('application/json')) { | ||
return res.json() as Promise<T>; | ||
} | ||
|
||
return res.blob() as Promise<unknown> as Promise<T>; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from './BaseBucket'; | ||
export * from './Bucket'; | ||
export * from './Fetch'; | ||
export * from './ProxyBucket'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
export * from './fetcher'; | ||
export * from './mutex'; | ||
export * from './struct'; | ||
export * from './Constants'; | ||
export * from './Error'; | ||
export * from './Fetch'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters