Skip to content

Commit f8a6ad5

Browse files
authoredApr 6, 2024··
feat: add option to retry bulk overwrites (#741)
* feat: add option to retry bulk overwrites
1 parent 65a91c7 commit f8a6ad5

File tree

2 files changed

+90
-45
lines changed

2 files changed

+90
-45
lines changed
 

‎src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import {
22
acquire,
3+
getBulkOverwriteRetries,
34
getDefaultBehaviorWhenNotIdentical,
45
getDefaultGuildIds,
56
registries,
7+
setBulkOverwriteRetries,
68
setDefaultBehaviorWhenNotIdentical,
79
setDefaultGuildIds
810
} from './lib/utils/application-commands/ApplicationCommandRegistries';
@@ -27,8 +29,10 @@ const ApplicationCommandRegistries = {
2729
acquire,
2830
setDefaultBehaviorWhenNotIdentical,
2931
setDefaultGuildIds,
32+
setBulkOverwriteRetries,
3033
getDefaultGuildIds,
3134
getDefaultBehaviorWhenNotIdentical,
35+
getBulkOverwriteRetries,
3236
get registries(): ReadonlyMap<string, ApplicationCommandRegistry> {
3337
return registries;
3438
}

‎src/lib/utils/application-commands/ApplicationCommandRegistries.ts

+86-45
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/dot-notation */
22
import { container } from '@sapphire/pieces';
3+
import { retry } from '@sapphire/utilities';
34
import type { RESTPostAPIApplicationCommandsJSONBody } from 'discord-api-types/v10';
45
import { ApplicationCommandType, type ApplicationCommandManager } from 'discord.js';
56
import type { Command } from '../../structures/Command';
@@ -13,6 +14,7 @@ import { bulkOverwriteDebug, bulkOverwriteInfo, bulkOverwriteWarn } from './regi
1314

1415
export let defaultBehaviorWhenNotIdentical = RegisterBehavior.Overwrite;
1516
export let defaultGuildIds: ApplicationCommandRegistry.RegisterOptions['guildIds'] = undefined;
17+
let bulkOVerwriteRetries = 1;
1618

1719
export const registries = new Map<string, ApplicationCommandRegistry>();
1820

@@ -62,6 +64,24 @@ export function getDefaultGuildIds() {
6264
return defaultGuildIds;
6365
}
6466

67+
/**
68+
* Sets the amount of retries for when registering commands, only applies when {@link defaultBehaviorWhenNotIdentical}
69+
* is set to {@link RegisterBehavior.BulkOverwrite}. This is used if registering the commands times out.
70+
* The default value is `1`, which means no retries are performed.
71+
* @param newAmountOfRetries The new amount of retries to set. Set this to `null` to reset it to the default
72+
*/
73+
export function setBulkOverwriteRetries(newAmountOfRetries: number | null) {
74+
newAmountOfRetries ??= 1;
75+
76+
if (newAmountOfRetries <= 0) throw new RangeError('The amount of retries must be greater than 0');
77+
78+
bulkOVerwriteRetries = newAmountOfRetries;
79+
}
80+
81+
export function getBulkOverwriteRetries() {
82+
return bulkOVerwriteRetries;
83+
}
84+
6585
export async function handleRegistryAPICalls() {
6686
container.client.emit(Events.ApplicationCommandRegistriesInitialising);
6787

@@ -115,6 +135,21 @@ export async function handleBulkOverwrite(commandStore: CommandStore, applicatio
115135
}
116136

117137
// Handle global commands
138+
await retry(() => handleBulkOverwriteGlobalCommands(commandStore, applicationCommands, foundGlobalCommands), bulkOVerwriteRetries);
139+
140+
// Handle guild commands
141+
for (const [guildId, guildCommands] of Object.entries(foundGuildCommands)) {
142+
await retry(() => handleBulkOverwriteGuildCommands(commandStore, applicationCommands, guildId, guildCommands), bulkOVerwriteRetries);
143+
}
144+
145+
container.client.emit(Events.ApplicationCommandRegistriesRegistered, registries, Date.now() - now);
146+
}
147+
148+
async function handleBulkOverwriteGlobalCommands(
149+
commandStore: CommandStore,
150+
applicationCommands: ApplicationCommandManager,
151+
foundGlobalCommands: BulkOverwriteData[]
152+
) {
118153
try {
119154
bulkOverwriteDebug(`Overwriting global application commands, now at ${foundGlobalCommands.length} commands`);
120155
const result = await applicationCommands.set(foundGlobalCommands.map((x) => x.data));
@@ -150,59 +185,65 @@ export async function handleBulkOverwrite(commandStore: CommandStore, applicatio
150185

151186
bulkOverwriteInfo(`Successfully overwrote global application commands. The application now has ${result.size} global commands`);
152187
} catch (error) {
188+
if (error instanceof Error && error.name === 'AbortError') throw error;
189+
153190
emitBulkOverwriteError(error, null);
154191
}
192+
}
155193

156-
// Handle guild commands
157-
for (const [guildId, guildCommands] of Object.entries(foundGuildCommands)) {
158-
try {
159-
bulkOverwriteDebug(`Overwriting guild application commands for guild ${guildId}, now at ${guildCommands.length} commands`);
160-
const result = await applicationCommands.set(
161-
guildCommands.map((x) => x.data),
162-
guildId
163-
);
164-
165-
// Go through each registered command, find its piece and alias it
166-
for (const [id, guildCommand] of result.entries()) {
167-
// I really hope nobody has a guild command with the same name as another command -.-
168-
// Not like they could anyways as Discord would throw an error for duplicate names
169-
// But yknow... If you're reading this and you did this... Why?
170-
const piece = guildCommands.find((x) => x.data.name === guildCommand.name)?.piece;
171-
172-
if (piece) {
173-
const registry = piece.applicationCommandRegistry;
174-
175-
switch (guildCommand.type) {
176-
case ApplicationCommandType.ChatInput: {
177-
registry['handleIdAddition'](InternalRegistryAPIType.ChatInput, id, guildId);
178-
break;
179-
}
180-
case ApplicationCommandType.User:
181-
case ApplicationCommandType.Message: {
182-
registry['handleIdAddition'](InternalRegistryAPIType.ContextMenu, id, guildId);
183-
break;
184-
}
185-
}
194+
async function handleBulkOverwriteGuildCommands(
195+
commandStore: CommandStore,
196+
applicationCommands: ApplicationCommandManager,
197+
guildId: string,
198+
guildCommands: BulkOverwriteData[]
199+
) {
200+
try {
201+
bulkOverwriteDebug(`Overwriting guild application commands for guild ${guildId}, now at ${guildCommands.length} commands`);
202+
const result = await applicationCommands.set(
203+
guildCommands.map((x) => x.data),
204+
guildId
205+
);
206+
207+
// Go through each registered command, find its piece and alias it
208+
for (const [id, guildCommand] of result.entries()) {
209+
// I really hope nobody has a guild command with the same name as another command -.-
210+
// Not like they could anyways as Discord would throw an error for duplicate names
211+
// But yknow... If you're reading this and you did this... Why?
212+
const piece = guildCommands.find((x) => x.data.name === guildCommand.name)?.piece;
186213

187-
// idHints are useless, and any manually added ids or names could no longer be valid if you use bulk overwrites.
188-
// That said, this might be an issue, so we might need to do it like `handleAppendOrUpdate`
189-
commandStore.aliases.set(id, piece);
190-
} else {
191-
bulkOverwriteWarn(
192-
`Registered guild command "${guildCommand.name}" (${id}) but failed to find the piece in the command store. This should not happen`
193-
);
214+
if (piece) {
215+
const registry = piece.applicationCommandRegistry;
216+
217+
switch (guildCommand.type) {
218+
case ApplicationCommandType.ChatInput: {
219+
registry['handleIdAddition'](InternalRegistryAPIType.ChatInput, id, guildId);
220+
break;
221+
}
222+
case ApplicationCommandType.User:
223+
case ApplicationCommandType.Message: {
224+
registry['handleIdAddition'](InternalRegistryAPIType.ContextMenu, id, guildId);
225+
break;
226+
}
194227
}
195-
}
196228

197-
bulkOverwriteInfo(
198-
`Successfully overwrote guild application commands for guild ${guildId}. The application now has ${result.size} guild commands for guild ${guildId}`
199-
);
200-
} catch (error) {
201-
emitBulkOverwriteError(error, guildId);
229+
// idHints are useless, and any manually added ids or names could no longer be valid if you use bulk overwrites.
230+
// That said, this might be an issue, so we might need to do it like `handleAppendOrUpdate`
231+
commandStore.aliases.set(id, piece);
232+
} else {
233+
bulkOverwriteWarn(
234+
`Registered guild command "${guildCommand.name}" (${id}) but failed to find the piece in the command store. This should not happen`
235+
);
236+
}
202237
}
203-
}
204238

205-
container.client.emit(Events.ApplicationCommandRegistriesRegistered, registries, Date.now() - now);
239+
bulkOverwriteInfo(
240+
`Successfully overwrote guild application commands for guild ${guildId}. The application now has ${result.size} guild commands for guild ${guildId}`
241+
);
242+
} catch (error) {
243+
if (error instanceof Error && error.name === 'AbortError') throw error;
244+
245+
emitBulkOverwriteError(error, guildId);
246+
}
206247
}
207248

208249
async function handleAppendOrUpdate(

0 commit comments

Comments
 (0)
Please sign in to comment.