From 1d189b98b7279ce46197a0b9d5c5bf461b681ef7 Mon Sep 17 00:00:00 2001 From: NovaFox161 Date: Sun, 13 Feb 2022 14:14:48 -0600 Subject: [PATCH] Update global command registrar to use bulk method --- .../network/discord/GlobalCommandRegistrar.kt | 157 +----------------- 1 file changed, 7 insertions(+), 150 deletions(-) diff --git a/server/src/main/kotlin/org/dreamexposure/discal/server/network/discord/GlobalCommandRegistrar.kt b/server/src/main/kotlin/org/dreamexposure/discal/server/network/discord/GlobalCommandRegistrar.kt index b4edc3dd..3b55cb40 100644 --- a/server/src/main/kotlin/org/dreamexposure/discal/server/network/discord/GlobalCommandRegistrar.kt +++ b/server/src/main/kotlin/org/dreamexposure/discal/server/network/discord/GlobalCommandRegistrar.kt @@ -2,13 +2,10 @@ package org.dreamexposure.discal.server.network.discord import com.fasterxml.jackson.module.kotlin.readValue import discord4j.common.JacksonResources -import discord4j.discordjson.json.ApplicationCommandData -import discord4j.discordjson.json.ApplicationCommandOptionChoiceData -import discord4j.discordjson.json.ApplicationCommandOptionData import discord4j.discordjson.json.ApplicationCommandRequest import discord4j.rest.RestClient +import org.dreamexposure.discal.core.`object`.BotSettings.DEFAULT_WEBHOOK import org.dreamexposure.discal.core.logger.LOGGER -import org.dreamexposure.discal.core.utils.GlobalVal.DEFAULT import org.springframework.boot.ApplicationArguments import org.springframework.boot.ApplicationRunner import org.springframework.core.io.support.PathMatchingResourcePatternResolver @@ -25,156 +22,16 @@ class GlobalCommandRegistrar( val matcher = PathMatchingResourcePatternResolver() val applicationService = restClient.applicationService val applicationId = restClient.applicationId.block()!! - val discordCommands = applicationService.getGlobalApplicationCommands(applicationId) - .collectMap(ApplicationCommandData::name) - .block()!! - var added = 0 - var removed = 0 - var updated = 0 - - val commands = mutableMapOf() + val commands = mutableListOf() for (res in matcher.getResources("commands/*.json")) { val request = d4jMapper.objectMapper.readValue(res.inputStream) - commands[request.name()] = request - - if (discordCommands[request.name()] == null) { - added++ - applicationService.createGlobalApplicationCommand(applicationId, request).block() - } + commands.add(request) } - for ((discordCommandName, discordCommand) in discordCommands) { - val discordCommandId = discordCommand.id().toLong() - val command = commands[discordCommandName] - if (command == null) { // Removed command.json, delete global command - removed++ - applicationService.deleteGlobalApplicationCommand(applicationId, discordCommandId).block() - continue - } - - if (hasChanged(discordCommand, command)) { - updated++ - applicationService.modifyGlobalApplicationCommand(applicationId, discordCommandId, command).block() - } - } - - //Send log message with details on changes... - LOGGER.info(DEFAULT, "Slash commands: $added Added | $updated Updated | $removed Removed") - } - - private fun hasChanged(discordCommand: ApplicationCommandData, command: ApplicationCommandRequest): Boolean { - //Check type - val dCommandType = discordCommand.type().toOptional().orElse(1) - val commandType = command.type().toOptional().orElse(1) - if (dCommandType != commandType) return true - - //Check description - if (discordCommand.description() != command.description().toOptional().orElse("")) return true - - //Check default perm - val dCommandPerm = discordCommand.defaultPermission().toOptional().orElse(true) - val commandPerm = command.defaultPermission().toOptional().orElse(true) - if (dCommandPerm != commandPerm) return true - - //Check options - val discordOptions = discordCommand.options().toOptional().orElse(emptyList()) - val commandOptions = command.options().toOptional().orElse(emptyList()) - - //This is messy and recursive but it should work - return !optionsEqual(discordOptions, commandOptions) - } - - private fun optionsEqual(options1: List, options2: List): Boolean { - if (options1.isEmpty() && options2.isEmpty()) return true // No sub-options, they're equal - if (options1.size != options2.size) return false // Lists are different sizes, must update - - //Loop through options and compare recursively - for ((index, opt1) in options1.withIndex()) { - if (!optionsEqual(opt1, options2[index])) return false // sub-opts don't match. needs to be updated - } - - //If we make it here, everything should be equal - return true - } - - //Returns false if not matching - private fun optionsEqual(option1: ApplicationCommandOptionData, option2: ApplicationCommandOptionData): Boolean { - //compare type - if (option1.type() != option2.type()) return false - - //compare name - if (option1.name() != option2.name()) return false - - //compare description - if (option1.description() != option2.description()) return false - - //compare required bool - if (option1.required().toOptional().orElse(false) != option2.required().toOptional().orElse(false)) return false - - //compare auto-complete - if (option1.autocomplete().toOptional().orElse(false) != option2.autocomplete().toOptional().orElse(false)) return false - - //compare channel types - val channels1 = option1.channelTypes().toOptional().orElse(emptyList()) - val channels2 = option2.channelTypes().toOptional().orElse(emptyList()) - if (!channelTypesMatch(channels1, channels2)) return false - - //compare min - val min1 = option1.minValue().toOptional().orElse(Double.MIN_VALUE) - val min2 = option2.minValue().toOptional().orElse(Double.MIN_VALUE) - if (min1 != min2) return false - - //compare max - val max1 = option1.maxValue().toOptional().orElse(Double.MAX_VALUE) - val max2 = option2.maxValue().toOptional().orElse(Double.MAX_VALUE) - if (max1 != max2) return false - - - //compare choices - val choices1 = option1.choices().toOptional().orElse(emptyList()) - val choices2 = option2.choices().toOptional().orElse(emptyList()) - - if (!choicesEqual(choices1, choices2)) return false - - //compare sub-options - val subOpts1 = option1.options().toOptional().orElse(emptyList()) - val subOpts2 = option2.options().toOptional().orElse(emptyList()) - - //Recursive!!!!!!! - return optionsEqual(subOpts1, subOpts2) - } - - private fun choicesEqual(choices1: List, choices2: List): Boolean { - if (choices1.isEmpty() && choices2.isEmpty()) return true //both empty, both equal - - if (choices1.size != choices2.size) return false //sizes don't match, needs updating - - //Compare the choices one-by-one... - for ((index, c1) in choices1.withIndex()) { - val c2 = choices2[index] - - if (c1.name() != c2.name()) return false //names not equal - if (c1.value() != c2.value()) return false //values not equal - } - - //If we get here, they must be equal - return true - } - - private fun channelTypesMatch(channels1: List, channels2: List): Boolean { - if (channels1.isEmpty() && channels2.isEmpty()) return true //both empty, both equal - - if (channels1.size != channels2.size) return false //sizes don't match, needs updating - - //Compare the channels one-by-one... - for ((index, c1) in channels1.withIndex()) { - val c2 = channels2[index] - - if (c1 != c2) return false //values not equal - } - - //If we get here, they must be equal - return true + applicationService.bulkOverwriteGlobalApplicationCommand(applicationId, commands) + .doOnNext { LOGGER.debug("Bulk overwrite read: ${it.name()}") } + .doOnError { LOGGER.error(DEFAULT_WEBHOOK.get(), "Bulk overwrite failed", it) } + .subscribe() } }