Skip to content

Commit 696d617

Browse files
committed
Global commands upserted only if it differs
1 parent af4a096 commit 696d617

File tree

1 file changed

+66
-21
lines changed

1 file changed

+66
-21
lines changed

discord/bot.py

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -217,37 +217,82 @@ async def register_commands(self) -> None:
217217
218218
Registers all commands that have been added through :meth:`.add_application_command`.
219219
This method cleans up all commands over the API and should sync them with the internal cache of commands.
220+
This will only be rolled out to Discord if :meth:`.http.get_global_commands` has certain keys that differ from :data:`.pending_application_commands`
220221
221222
By default, this coroutine is called inside the :func:`.on_connect`
222223
event. If you choose to override the :func:`.on_connect` event, then
223224
you should invoke this coroutine as well.
224225
225226
.. versionadded:: 2.0
226227
"""
227-
commands = []
228+
commands_to_bulk = []
229+
230+
needs_bulk = False
228231

229232
# Global Command Permissions
230233
global_permissions: List = []
231234

232235
registered_commands = await self.http.get_global_commands(self.user.id)
233-
for command in [
234-
cmd for cmd in self.pending_application_commands if cmd.guild_ids is None
235-
]:
236-
as_dict = command.to_dict()
237-
if len(registered_commands) > 0:
238-
matches = [
239-
x
240-
for x in registered_commands
241-
if x["name"] == command.name and x["type"] == command.type
242-
]
243-
# TODO: rewrite this, it seems inefficient
244-
if matches:
245-
as_dict["id"] = matches[0]["id"]
246-
commands.append(as_dict)
247-
248-
cmds = await self.http.bulk_upsert_global_commands(self.user.id, commands)
249-
250-
for i in cmds:
236+
# 'Your app cannot have two global commands with the same name. Your app cannot have two guild commands within the same name on the same guild.'
237+
# We can therefore safely use the name of the command in our global slash commands as a unique identifier
238+
registered_commands_dict = {cmd["name"]:cmd for cmd in registered_commands}
239+
global_pending_application_commands_dict = {}
240+
241+
if len(registered_commands) > 0:
242+
for command in [
243+
cmd for cmd in self.pending_application_commands if cmd.guild_ids is None
244+
]:
245+
as_dict = command.to_dict()
246+
247+
global_pending_application_commands_dict[command.name] = as_dict
248+
if command.name in registered_commands_dict:
249+
match = registered_commands_dict[command.name]
250+
else:
251+
match = None
252+
# TODO: There is probably a far more efficient way of doing this
253+
# We want to check if the registered global command on Discord servers matches the given global commands
254+
if match:
255+
as_dict["id"] = match["id"]
256+
257+
keys_to_check = {"default_permission": True, "name": True, "description": True, "options": ["type", "name", "description"]}
258+
for key, more_keys in {
259+
key:more_keys
260+
for key, more_keys in keys_to_check.items()
261+
if key in as_dict.keys()
262+
if key in match.keys()
263+
}.items():
264+
if key == "options":
265+
for i, option_dict in enumerate(as_dict[key]):
266+
for key2_change in [
267+
key2
268+
for key2 in more_keys
269+
if key2 in option_dict.keys() and key2 in match[key][i].keys()
270+
if option_dict[key2] != match[key][i][key2]
271+
]:
272+
print(f"A change in the '{key2_change}' property of '{key}' in the '{command.name}' global command was noticed, will send to Discord to update")
273+
needs_bulk = True
274+
else:
275+
if as_dict[key] != match[key]:
276+
print(f"A change in the '{key}' property of '{command.name}' global command was noticed, will send to Discord to update")
277+
needs_bulk = True
278+
else:
279+
print(f"A pending global command '{command.name}' is not registered in Discord servers, will send to Discord to update")
280+
needs_bulk = True
281+
282+
commands_to_bulk.append(as_dict)
283+
284+
if len(registered_commands_dict) > 0:
285+
for name, command in registered_commands_dict.items():
286+
if not name in global_pending_application_commands_dict.keys():
287+
print(f"A registered global command '{name}' is not found in the pending global commands, will send to Discord to update")
288+
needs_bulk
289+
290+
if needs_bulk:
291+
commands = await self.http.bulk_upsert_global_commands(self.user.id, commands_to_bulk)
292+
else:
293+
commands = registered_commands
294+
295+
for i in commands:
251296
cmd = get(
252297
self.pending_application_commands,
253298
name=i["name"],
@@ -275,7 +320,7 @@ async def register_commands(self) -> None:
275320

276321
for guild_id, guild_data in update_guild_commands.items():
277322
try:
278-
cmds = await self.http.bulk_upsert_guild_commands(
323+
commands = await self.http.bulk_upsert_guild_commands(
279324
self.user.id, guild_id, update_guild_commands[guild_id]
280325
)
281326

@@ -287,7 +332,7 @@ async def register_commands(self) -> None:
287332
print(f"Failed to add command to guild {guild_id}", file=sys.stderr)
288333
raise
289334
else:
290-
for i in cmds:
335+
for i in commands:
291336
cmd = find(lambda cmd: cmd.name == i["name"] and cmd.type == i["type"] and int(i["guild_id"]) in cmd.guild_ids, self.pending_application_commands)
292337
cmd.id = i["id"]
293338
self._application_commands[cmd.id] = cmd

0 commit comments

Comments
 (0)