Skip to content

Commit

Permalink
Expose sharding builder, allow for skipping of slash command registra…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
gdude2002 committed Jul 30, 2021
1 parent 615ad37 commit 77a2270
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ public open class ExtensibleBot(public val settings: ExtensibleBotBuilder, priva
this.intents = Intents(settings.intentsBuilder!!)
}

if (settings.shardingBuilder != null) {
sharding(settings.shardingBuilder!!)
}

enableShutdownHook = settings.hooksBuilder.kordShutdownHook
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import dev.kord.core.Kord
import dev.kord.core.behavior.GuildBehavior
import dev.kord.core.behavior.UserBehavior
import dev.kord.core.behavior.channel.ChannelBehavior
import dev.kord.core.builder.kord.Shards
import dev.kord.core.cache.KordCacheBuilder
import dev.kord.core.event.interaction.InteractionCreateEvent
import dev.kord.core.event.message.MessageCreateEvent
Expand Down Expand Up @@ -79,6 +80,9 @@ public open class ExtensibleBotBuilder {
/** @suppress Builder that shouldn't be set directly by the user. **/
public var presenceBuilder: PresenceBuilder.() -> Unit = { status = PresenceStatus.Online }

/** @suppress Builder that shouldn't be set directly by the user. **/
public var shardingBuilder: ((recommended: Int) -> Shards)? = null

/** @suppress Builder that shouldn't be set directly by the user. **/
public val slashCommandsBuilder: SlashCommandsBuilder = SlashCommandsBuilder()

Expand Down Expand Up @@ -175,6 +179,16 @@ public open class ExtensibleBotBuilder {
this.presenceBuilder = builder
}

/**
* DSL function used to configure the bot's sharding settings.
*
* @see dev.kord.core.builder.kord.KordBuilder.shardsBuilder
*/
@BotBuilderDSL
public fun sharding(shards: (recommended: Int) -> Shards) {
this.shardingBuilder = shards
}

/** @suppress Internal function used to initially set up Koin. **/
public open fun setupKoin() {
startKoin {
Expand Down Expand Up @@ -824,6 +838,9 @@ public open class ExtensibleBotBuilder {
/** The guild ID to use for all global slash commands. Intended for testing. **/
public var defaultGuild: Snowflake? = null

/** Whether to attempt to register the bot's slash commands. Intended for multi-instance sharded bots. **/
public var register: Boolean = true

/** @suppress Builder that shouldn't be set directly by the user. **/
public var slashRegistryBuilder: () -> SlashCommandRegistry = { SlashCommandRegistry() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public open class SlashCommandRegistry : KoinComponent {
public open suspend fun syncAll() {
logger.info { "Synchronising slash commands. This may take some time." }

if (!bot.settings.slashCommandsBuilder.register) {
logger.debug {
"Slash command registration is disabled, pairing existing commands with extension commands."
}
}

try {
sync(null)
} catch (t: Throwable) {
Expand Down Expand Up @@ -137,92 +143,105 @@ public open class SlashCommandRegistry : KoinComponent {
api.getGuildApplicationCommands(guild).map { Pair(it.name, it.id) }.toList()
}

val toAdd = registered.filter { r -> existing.all { it.first != r.getTranslatedName(locale) } }
val toUpdate = registered.filter { r -> existing.any { it.first == r.getTranslatedName(locale) } }
val toRemove = existing.filter { e -> registered.all { it.getTranslatedName(locale) != e.first } }
if (!bot.settings.slashCommandsBuilder.register) {
registered.forEach { r ->
val existingCommand = existing.firstOrNull { it.first == r.getTranslatedName(locale) }

logger.info {
if (guild == null) {
"Global slash commands: ${toAdd.size} to add / ${toUpdate.size} to update / ${toRemove.size} to remove"
} else {
"Slash commands for guild ${guildObj?.name}: ${toAdd.size} to add / ${toUpdate.size} to update / " +
"${toRemove.size} to remove"
if (existingCommand != null) {
commandMap[existingCommand.second] = r
}
}
}

val toCreate = toAdd + toUpdate

if (guild == null) {
val response = api.createGlobalApplicationCommands {
toCreate.forEach {
val translatedName = it.getTranslatedName(locale)

logger.debug { "Adding/updating global slash command $translatedName" }

command(
translatedName,
translationsProvider.translate(it.description, it.extension.bundle, locale = locale)
) { register(it) }
} else {
val toAdd = registered.filter { r -> existing.all { it.first != r.getTranslatedName(locale) } }
val toUpdate = registered.filter { r -> existing.any { it.first == r.getTranslatedName(locale) } }
val toRemove = existing.filter { e -> registered.all { it.getTranslatedName(locale) != e.first } }

logger.info {
if (guild == null) {
"Global slash commands: ${toAdd.size} to add / " +
"${toUpdate.size} to update / " +
"${toRemove.size} to remove"
} else {
"Slash commands for guild ${guildObj?.name}: ${toAdd.size} to add / " +
"${toUpdate.size} to update / " +
"${toRemove.size} to remove"
}
}.toList().associate { it.name to it.id }

toCreate.forEach {
commandMap[response[it.getTranslatedName(locale)]!!] = it
}

api.getGlobalApplicationCommands().filter { e -> toRemove.any { it.second == e.id } }
.toList()
.forEach {
logger.debug { "Removing global slash command ${it.name}" }
it.delete()
}
} else {
toCreate.groupBy { it.guild!! }.forEach { (snowflake, commands) ->
val response = api.createGuildApplicationCommands(snowflake) {
commands.forEach {
val toCreate = toAdd + toUpdate

if (guild == null) {
val response = api.createGlobalApplicationCommands {
toCreate.forEach {
val translatedName = it.getTranslatedName(locale)

logger.debug { "Adding/updating global slash command $translatedName" }

command(
translatedName,
translationsProvider.translate(it.description, it.extension.bundle)
translationsProvider.translate(it.description, it.extension.bundle, locale = locale)
) { register(it) }
}
}.toList().associate { it.name to it.id }

commands.forEach {
toCreate.forEach {
commandMap[response[it.getTranslatedName(locale)]!!] = it
}
}

api.getGuildApplicationCommands(guild).filter { e -> toRemove.any { it.second == e.id } }
.toList()
.forEach {
logger.debug { "Removing guild slash command ${it.name}" }
it.delete()
api.getGlobalApplicationCommands().filter { e -> toRemove.any { it.second == e.id } }
.toList()
.forEach {
logger.debug { "Removing global slash command ${it.name}" }
it.delete()
}
} else {
toCreate.groupBy { it.guild!! }.forEach { (snowflake, commands) ->
val response = api.createGuildApplicationCommands(snowflake) {
commands.forEach {
val translatedName = it.getTranslatedName(locale)

logger.debug { "Adding/updating global slash command $translatedName" }

command(
translatedName,
translationsProvider.translate(it.description, it.extension.bundle)
) { register(it) }
}
}.toList().associate { it.name to it.id }

commands.forEach {
commandMap[response[it.getTranslatedName(locale)]!!] = it
}
}
}

val commandsWithPerms = commandMap.filterValues { !it.allowByDefault }.toList().groupBy {
it.second.guild
}
api.getGuildApplicationCommands(guild).filter { e -> toRemove.any { it.second == e.id } }
.toList()
.forEach {
logger.debug { "Removing guild slash command ${it.name}" }
it.delete()
}
}

commandsWithPerms.forEach { (guild, commands) ->
if (guild != null) {
api.bulkEditApplicationCommandPermissions(api.applicationId, guild) {
commands.forEach { (id, commandObj) ->
command(id) {
commandObj.allowedUsers.map { user(it, true) }
commandObj.disallowedUsers.map { user(it, false) }
val commandsWithPerms = commandMap.filterValues { !it.allowByDefault }.toList().groupBy {
it.second.guild
}

commandsWithPerms.forEach { (guild, commands) ->
if (guild != null) {
api.bulkEditApplicationCommandPermissions(api.applicationId, guild) {
commands.forEach { (id, commandObj) ->
command(id) {
commandObj.allowedUsers.map { user(it, true) }
commandObj.disallowedUsers.map { user(it, false) }

commandObj.allowedRoles.map { role(it, true) }
commandObj.disallowedRoles.map { role(it, false) }
commandObj.allowedRoles.map { role(it, true) }
commandObj.disallowedRoles.map { role(it, false) }
}
}
}
} else {
logger.warn { "Applying permissions to global slash commands is currently not supported." }
}
} else {
logger.warn { "Applying permissions to global slash commands is currently not supported." }
}
}

Expand Down

0 comments on commit 77a2270

Please sign in to comment.