mirror of
https://github.com/Xevion/banner.git
synced 2025-12-06 01:14:22 -06:00
Use bulk overwrite, use test server for command registration in dev
This commit is contained in:
40
main.go
40
main.go
@@ -100,7 +100,10 @@ func main() {
|
||||
log.Fatal().Err(lastPingErr).Msg("Reached ping limit while trying to connect")
|
||||
}
|
||||
|
||||
// Ping redis
|
||||
pong, err := kv.Ping(ctx).Result()
|
||||
|
||||
// Failed; log error and wait 2 seconds
|
||||
if err != nil {
|
||||
lastPingErr = err
|
||||
log.Warn().Err(err).Int("pings", pingCount).Int("remaining", totalPings-pingCount).Msg("Cannot ping redis")
|
||||
@@ -155,8 +158,43 @@ func main() {
|
||||
})
|
||||
log.Info().Array("commands", arr).Msg("Registering commands")
|
||||
|
||||
// In development, use test server, otherwise empty (global) for command registration
|
||||
guildTarget := ""
|
||||
if isDevelopment {
|
||||
guildTarget = os.Getenv("BOT_TARGET_GUILD")
|
||||
}
|
||||
|
||||
// Register commands
|
||||
Register()
|
||||
existingCommands, err := session.ApplicationCommands(session.State.User.ID, guildTarget)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Cannot get existing commands")
|
||||
}
|
||||
|
||||
newCommands, err := session.ApplicationCommandBulkOverwrite(session.State.User.ID, guildTarget, commandDefinitions)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Cannot register commands")
|
||||
}
|
||||
|
||||
// Compare existing commands with new commands
|
||||
for _, newCommand := range newCommands {
|
||||
existingCommand, found := lo.Find(existingCommands, func(cmd *discordgo.ApplicationCommand) bool {
|
||||
return cmd.Name == newCommand.Name
|
||||
})
|
||||
|
||||
// New command
|
||||
if !found {
|
||||
log.Info().Str("commandName", newCommand.Name).Msg("Registered new command")
|
||||
continue
|
||||
}
|
||||
|
||||
// Compare versions
|
||||
if newCommand.Version != existingCommand.Version {
|
||||
log.Info().Str("commandName", newCommand.Name).
|
||||
Str("oldVersion", existingCommand.Version).Str("newVersion", newCommand.Version).
|
||||
Msg("Command Updated")
|
||||
}
|
||||
}
|
||||
log.Info().Msg("Command registration complete")
|
||||
|
||||
// terms, _ := GetTerms("", 1, 25)
|
||||
|
||||
|
||||
139
register.go
139
register.go
@@ -1,139 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/cespare/xxhash/v2"
|
||||
"github.com/cnf/structhash"
|
||||
"github.com/redis/go-redis/v9"
|
||||
log "github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// Register registers all commands, and only registers commands that have changed.
|
||||
// It also unregisters old commands if they are known to exist and have changed.
|
||||
// This is to lower the cost of registering commands while iterating on the bot.
|
||||
// In the case of an ambiguous state, all current commands are deleted while all new commands are registered.
|
||||
func Register() ([]*discordgo.ApplicationCommand, error) {
|
||||
// Since we don't know what currentComands existed before, we can't unregister them if they're removed.
|
||||
// We also can't tell the difference between a command that was removed and one that was newly added.
|
||||
// Thus, if the number of currently active currentComands is not equal to the number of currentComands we're registering, we'll just re-register all of them.
|
||||
currentComands, err := session.ApplicationCommands(session.State.User.ID, "")
|
||||
if err != nil {
|
||||
log.Panic().Err(err).Msg("Cannot get commands")
|
||||
}
|
||||
log.Debug().Int("registered", len(currentComands)).Int("definitions", len(commandDefinitions)).Msg("Commands Counted")
|
||||
if len(currentComands) != len(commandDefinitions) {
|
||||
log.Info().Int("registered", len(currentComands)).Int("definitions", len(commandDefinitions)).Msg("Number of registered commands does not match number of command definitions, registering all commands")
|
||||
return SimpleRegister(currentComands)
|
||||
}
|
||||
|
||||
registeredCommands := make([]*discordgo.ApplicationCommand, len(commandDefinitions))
|
||||
for i, cmdDefinition := range commandDefinitions {
|
||||
// Create a hash of the command definition
|
||||
hash := xxhash.Sum64(structhash.Dump(cmdDefinition, 1))
|
||||
key := fmt.Sprintf("%s:command:%s:xxhash", environment, cmdDefinition.Name)
|
||||
|
||||
// Get the stored hash
|
||||
storedHash, err := kv.Get(ctx, key).Uint64()
|
||||
if err != nil {
|
||||
if err != redis.Nil {
|
||||
log.Err(err).Msg("Cannot get command hash from redis")
|
||||
} else {
|
||||
log.Debug().Str("command", cmdDefinition.Name).Str("key", key).Msg("Command hash not found in redis")
|
||||
}
|
||||
}
|
||||
|
||||
// If the hash is the same, skip registering the command
|
||||
if hash == storedHash {
|
||||
log.Debug().Str("command", cmdDefinition.Name).Str("key", key).Uint64("hash", hash).Msg("Command hash matches, skipping registration")
|
||||
continue
|
||||
}
|
||||
log.Info().Str("command", cmdDefinition.Name).Str("key", key).Uint64("hash", hash).Uint64("storedHash", storedHash).Msg("Command hash mismatch, registering command")
|
||||
|
||||
// Unregister the old command first (retrieve the ID from redis)
|
||||
oldCommandId, err := kv.Get(ctx, fmt.Sprintf("%s:command:%s:id", environment, cmdDefinition.Name)).Result()
|
||||
if err != nil {
|
||||
if err != redis.Nil {
|
||||
// Not really sure what to do here, something failed with redis. Best to just keep the old commad in place.
|
||||
log.Err(err).Str("name", cmdDefinition.Name).Str("key", key).Msg("Cannot get old command ID from redis (skipping registration/deletion)")
|
||||
continue
|
||||
} else {
|
||||
// It's an unlikely case, but if required, we could get the old command ID from discord to unregisstter it.
|
||||
log.Debug().Str("name", cmdDefinition.Name).Str("key", key).Msg("Old command ID not found in redis")
|
||||
}
|
||||
} else {
|
||||
err = session.ApplicationCommandDelete(session.State.User.ID, "", oldCommandId)
|
||||
if err != nil {
|
||||
// No panic - the command is probably still registered.
|
||||
log.Err(err).Str("name", cmdDefinition.Name).Str("key", key).Msg("Cannot unregister old command")
|
||||
continue
|
||||
} else {
|
||||
log.Info().Str("name", cmdDefinition.Name).Str("key", key).Msg("Unregistered old command")
|
||||
}
|
||||
}
|
||||
|
||||
// Register the command
|
||||
cmdInstance, err := session.ApplicationCommandCreate(session.State.User.ID, "", cmdDefinition)
|
||||
if err != nil {
|
||||
return nil, errors.Join(err, fmt.Errorf("cannot register command %s", cmdDefinition.Name))
|
||||
}
|
||||
registeredCommands[i] = cmdInstance
|
||||
log.Info().Str("name", cmdDefinition.Name).Str("key", key).Msg("Registered command")
|
||||
|
||||
// Store the hash for the new registered command
|
||||
err = kv.Set(ctx, key, hash, 0).Err()
|
||||
if err != nil {
|
||||
// No panic - the command is still registered, hash is only to prevent unnecessary registrations
|
||||
log.Err(err).Str("name", cmdDefinition.Name).Str("key", key).Msg("Cannot set command hash in redis")
|
||||
continue
|
||||
}
|
||||
|
||||
// Store the command ID to unregister later
|
||||
err = kv.Set(ctx, fmt.Sprintf("%s:command:%s:id", environment, cmdDefinition.Name), cmdInstance.ID, 0).Err()
|
||||
if err != nil {
|
||||
// No
|
||||
log.Err(err).Str("name", cmdDefinition.Name).Str("key", key).Msg("Cannot set command ID in redis")
|
||||
}
|
||||
}
|
||||
|
||||
return registeredCommands, nil
|
||||
}
|
||||
|
||||
func SimpleRegister(currentCommands []*discordgo.ApplicationCommand) ([]*discordgo.ApplicationCommand, error) {
|
||||
registeredCommands := make([]*discordgo.ApplicationCommand, len(commandDefinitions))
|
||||
|
||||
// Unregister all commands
|
||||
for _, cmd := range currentCommands {
|
||||
err := session.ApplicationCommandDelete(session.State.User.ID, "", cmd.ID)
|
||||
if err != nil {
|
||||
log.Err(err).Str("name", cmd.Name).Msg("Cannot unregister command")
|
||||
} else {
|
||||
log.Info().Str("name", cmd.Name).Msg("Unregistered command")
|
||||
}
|
||||
}
|
||||
|
||||
// Register all commands
|
||||
for i, cmdDefinition := range commandDefinitions {
|
||||
// Create a hash of the command definition
|
||||
hash := xxhash.Sum64(structhash.Dump(cmdDefinition, 1))
|
||||
key := fmt.Sprintf("%s:command:%s:xxhash", environment, cmdDefinition.Name)
|
||||
|
||||
cmdInstance, err := session.ApplicationCommandCreate(session.State.User.ID, "", cmdDefinition)
|
||||
if err != nil {
|
||||
log.Panic().Err(err).Str("name", cmdDefinition.Name).Msg("Cannot register command")
|
||||
}
|
||||
registeredCommands[i] = cmdInstance
|
||||
log.Info().Str("name", cmdDefinition.Name).Msg("Registered command")
|
||||
|
||||
// Store the hash for the new registered command
|
||||
err = kv.Set(ctx, key, hash, 0).Err()
|
||||
if err != nil {
|
||||
// No panic - the command is still registered, hash is only to prevent unnecessary registrations
|
||||
log.Err(err).Str("name", cmdDefinition.Name).Str("key", key).Msg("Cannot set command hash in redis")
|
||||
continue
|
||||
}
|
||||
}
|
||||
return registeredCommands, nil
|
||||
}
|
||||
Reference in New Issue
Block a user