Add structhash, hash command definition with xxhash, store & compare with redis

This commit is contained in:
2023-12-24 21:59:03 -06:00
parent 5d8130c3a4
commit a545cf2b1c
3 changed files with 46 additions and 12 deletions

1
go.mod
View File

@@ -8,6 +8,7 @@ require github.com/joho/godotenv v1.5.1
require (
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect

2
go.sum
View File

@@ -4,6 +4,8 @@ github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4Ho
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

57
main.go
View File

@@ -1,13 +1,18 @@
package main
import (
"context"
"encoding/base64"
"flag"
"fmt"
"net/http"
"net/http/cookiejar"
"os"
"os/signal"
"github.com/bwmarrin/discordgo"
"github.com/cespare/xxhash/v2"
"github.com/cnf/structhash"
"github.com/joho/godotenv"
"github.com/redis/go-redis/v9"
"github.com/rs/zerolog"
@@ -20,6 +25,7 @@ var (
baseURL string
client http.Client
kv *redis.Client
ctx context.Context
cookies http.CookieJar
session *discordgo.Session
RemoveCommands = flag.Bool("rmcmd", true, "Remove all commands after shutdowning or not")
@@ -50,6 +56,8 @@ func (l logOut) WriteLevel(level zerolog.Level, p []byte) (n int, err error) {
}
func init() {
ctx = context.Background()
// Try to grab the environment variable, or default to development
env := os.Getenv("ENVIRONMENT")
if env == "" {
@@ -83,6 +91,13 @@ func main() {
}
kv = redis.NewClient(options)
// Test the redis instance
pong, err := kv.Ping(ctx).Result()
if err != nil {
log.Fatal().Err(err).Msg("Cannot connect to redis")
}
log.Debug().Str("ping", pong).Msg("Redis connection successful")
// Create cookie jar
cookies, err = cookiejar.New(nil)
if err != nil {
@@ -128,14 +143,39 @@ func main() {
// Register commands
registeredCommands := make([]*discordgo.ApplicationCommand, len(commandDefinitions))
for i, cmdDefinition := range commandDefinitions {
cmdInstance, err := session.ApplicationCommandCreate(session.State.User.ID, os.Getenv("BOT_TARGET_GUILD"), cmdDefinition)
// Compare the hash to the hash stored in redis
hash := xxhash.Sum64(structhash.Dump(cmdDefinition, 1))
key := fmt.Sprintf("command:%s:xxhash", cmdDefinition.Name)
keyB64 := base64.StdEncoding.EncodeToString([]byte(key))
storedHash, err := kv.Get(ctx, key).Uint64()
if err != nil {
log.Panic().Err(err).Str("name", cmdDefinition.Name).Msgf("Cannot register command")
if err != redis.Nil {
log.Err(err).Msg("Cannot get command hash from redis")
} else {
log.Debug().Str("command", cmdDefinition.Name).Str("key", keyB64).Msg("Command hash not found in redis")
}
registeredCommands[i] = cmdInstance
}
// Cloes session, ensure
// If the hash is the same, skip registering the command
if hash == storedHash {
log.Debug().Str("command", cmdDefinition.Name).Str("key", keyB64).Msg("Command hash matches, skipping registration")
continue
}
// Register the command
cmdInstance, err := session.ApplicationCommandCreate(session.State.User.ID, "", cmdDefinition)
if err != nil {
log.Panic().Err(err).Str("name", cmdDefinition.Name).Str("key", keyB64).Msg("Cannot register command")
}
err = kv.Set(ctx, key, hash, 0).Err()
if err != nil {
log.Err(err).Str("name", cmdDefinition.Name).Str("key", keyB64).Msg("Cannot set command hash in redis")
}
registeredCommands[i] = cmdInstance
log.Info().Str("name", cmdDefinition.Name).Str("key", keyB64).Msg("Registered command")
}
// Cloes session, ensure http client closes idle connections
defer session.Close()
defer client.CloseIdleConnections()
@@ -144,15 +184,6 @@ func main() {
log.Info().Msg("Press Ctrl+C to exit")
<-stop
if *RemoveCommands {
for _, cmd := range registeredCommands {
err := session.ApplicationCommandDelete(session.State.User.ID, os.Getenv("BOT_TARGET_GUILD"), cmd.ID)
if err != nil {
log.Err(err).Str("command", cmd.Name)
}
}
}
log.Warn().Msg("Gracefully shutting down")
}