refactor(rest): interaction handling (#2944)

* refactor(rest): interaction handling
Currently some interaction handling uses `sendRequest` directly.
This adds the `runThroughQueue` option, which prevents the request to be handled by a queue effectively giving the same effect as using `sendRequest` directly.
This prevents code repetition and supports future endpoints which might not have a rate limit too.

Further more all interaction related endpoints have now been set to not send the bots authorization header.

* fix invalid file

* fix eslint

* fix: followups have a rate limit

* fix awaiting
This commit is contained in:
ITOH
2023-04-02 16:27:48 +00:00
committed by GitHub
parent 66869ce00b
commit 7b5d99e5dd
2 changed files with 41 additions and 47 deletions
+27 -40
View File
@@ -924,7 +924,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return parts.join('/')
},
processRequest(request: SendRequestOptions) {
async processRequest(request: SendRequestOptions) {
const route = request.url.substring(request.url.indexOf('api/'))
const parts = route.split('/')
// Remove the api/
@@ -935,6 +935,13 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
request.url = `${rest.baseUrl}/v${rest.version}/${parts.join('/')}`
const url = rest.simplifyUrl(request.url, request.method)
if (request.runThroughQueue === false) {
await rest.sendRequest(request)
return
}
const queue = rest.queues.get(url)
if (queue !== undefined) {
@@ -964,22 +971,23 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return result.status !== 204 ? ((await result.json()) as any) : undefined
}
return await new Promise((resolve, reject) => {
return await new Promise(async (resolve, reject) => {
const payload: SendRequestOptions = {
url,
method,
requestBodyOptions: options,
retryCount: 0,
retryRequest: async function (payload: SendRequestOptions) {
rest.processRequest(payload)
await rest.processRequest(payload)
},
resolve: (data) => {
resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined)
},
reject,
runThroughQueue: options?.runThroughQueue,
}
rest.processRequest(payload)
await rest.processRequest(payload)
})
},
@@ -1127,7 +1135,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
},
async deleteFollowupMessage(token, messageId) {
await rest.delete(rest.routes.interactions.responses.message(rest.applicationId, token, messageId))
await rest.delete(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), { unauthorized: true })
},
async deleteGlobalApplicationCommand(commandId) {
@@ -1172,7 +1180,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
},
async deleteOriginalInteractionResponse(token) {
await rest.delete(rest.routes.interactions.responses.original(rest.applicationId, token))
await rest.delete(rest.routes.interactions.responses.original(rest.applicationId, token), { unauthorized: true })
},
async deleteOwnReaction(channelId, messageId, reaction) {
@@ -1268,6 +1276,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
return await rest.patch<DiscordMessage>(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), {
body,
files: body.files,
unauthorized: true,
})
},
@@ -1315,6 +1324,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
data: options,
},
files: options.files,
unauthorized: true,
})
},
@@ -1457,7 +1467,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
},
async getFollowupMessage(token, messageId) {
return await rest.get<DiscordMessage>(rest.routes.interactions.responses.message(rest.applicationId, token, messageId))
return await rest.get<DiscordMessage>(rest.routes.interactions.responses.message(rest.applicationId, token, messageId), { unauthorized: true })
},
async getGatewayBot() {
@@ -1525,7 +1535,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
},
async getOriginalInteractionResponse(token) {
return await rest.get<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token))
return await rest.get<DiscordMessage>(rest.routes.interactions.responses.original(rest.applicationId, token), { unauthorized: true })
},
async getPinnedMessages(channelId) {
@@ -1656,43 +1666,20 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage
await rest.delete(rest.routes.channels.threads.user(channelId, userId))
},
// TODO: why that
async sendFollowupMessage(token, options) {
return await new Promise((resolve, reject) => {
rest.sendRequest({
url: rest.routes.webhooks.webhook(rest.applicationId, token),
method: 'POST',
requestBodyOptions: { body: options, files: options.files },
retryCount: 0,
retryRequest: async function (options: SendRequestOptions) {
// TODO: should change to reprocess queue item
await rest.sendRequest(options)
},
resolve: (data) => {
resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined)
},
reject,
})
return await rest.post(rest.routes.webhooks.webhook(rest.applicationId, token), {
body: options,
files: options.files,
unauthorized: true,
})
},
// TODO: why that
async sendInteractionResponse(interactionId, token, options) {
await new Promise((resolve, reject) => {
rest.sendRequest({
url: rest.routes.interactions.responses.callback(interactionId, token),
method: 'POST',
requestBodyOptions: { body: options },
retryCount: 0,
retryRequest: async function (options: SendRequestOptions) {
// TODO: should change to reprocess queue item
await rest.sendRequest(options)
},
resolve: (data) => {
resolve(data.status !== 204 ? JSON.parse(data.body ?? '{}') : undefined)
},
reject,
})
return await rest.post(rest.routes.interactions.responses.callback(interactionId, token), {
body: options,
files: options.data?.files,
runThroughQueue: false,
unauthorized: true,
})
},
+14 -7
View File
@@ -169,19 +169,19 @@ export interface RestManager {
/** Split a url to separate rate limit buckets based on major/minor parameters. */
simplifyUrl: (url: string, method: RequestMethods) => string
/** Make a request to be sent to the api. */
makeRequest: <T = unknown>(method: RequestMethods, url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<T>
makeRequest: <T = unknown>(method: RequestMethods, url: string, options?: MakeRequestOptions) => Promise<T>
/** Takes a request and processes it into a queue. */
processRequest: (request: SendRequestOptions) => void
processRequest: (request: SendRequestOptions) => Promise<void>
/** Make a get request to the api */
get: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) => Promise<Camelize<T>>
get: <T = void>(url: string, options?: Omit<MakeRequestOptions, 'body'>) => Promise<Camelize<T>>
/** Make a post request to the api. */
post: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<Camelize<T>>
post: <T = void>(url: string, options?: MakeRequestOptions) => Promise<Camelize<T>>
/** Make a put request to the api. */
put: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<Camelize<T>>
put: <T = void>(url: string, options?: MakeRequestOptions) => Promise<Camelize<T>>
/** Make a delete request to the api. */
delete: (url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) => Promise<void>
delete: (url: string, options?: Omit<MakeRequestOptions, 'body'>) => Promise<void>
/** Make a patch request to the api. */
patch: <T = void>(url: string, options?: Omit<CreateRequestBodyOptions, 'method'>) => Promise<Camelize<T>>
patch: <T = void>(url: string, options?: MakeRequestOptions) => Promise<Camelize<T>>
/**
* Adds a reaction to a message.
*
@@ -2531,6 +2531,8 @@ export interface CreateRequestBodyOptions {
files?: FileContent[]
}
export type MakeRequestOptions = Omit<CreateRequestBodyOptions, 'method'> & Pick<SendRequestOptions, 'runThroughQueue'>
export interface RequestBody {
headers: Record<string, string>
body?: string | FormData
@@ -2554,6 +2556,11 @@ export interface SendRequestOptions {
bucketId?: string
/** Additional request options, used for things like overriding authorization header. */
requestBodyOptions?: CreateRequestBodyOptions
/**
* Whether the request should be run through the queue.
* Useful for routes which do not have any rate limits.
*/
runThroughQueue?: boolean
}
export interface RestRateLimitedPath {