discord: retry auth/command register, do latter in bulk

re-use the auth retry options from the config for initial d.bot.Open and
for registering commands. The latetr is now done with the BulkOverwrite
    method, since it seems to work now. For #427.
This commit is contained in:
Harvey Tindall
2025-08-03 20:05:22 +01:00
parent aab8d6ed77
commit db1e812190
3 changed files with 70 additions and 12 deletions
+9
View File
@@ -11,6 +11,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"time"
lm "github.com/hrfee/jfa-go/logmessages" lm "github.com/hrfee/jfa-go/logmessages"
) )
@@ -155,3 +156,11 @@ func decodeResp(resp *http.Response) (string, error) {
} }
return buf.String(), nil return buf.String(), nil
} }
// MustAuthenticateOptions is used to control the behaviour of the MustAuthenticate-like methods.
type MustAuthenticateOptions struct {
RetryCount int // Number of Retries before failure.
RetryGap time.Duration // Duration to wait between tries.
LogFailures bool // Whether or not to print failures to the log.
Counter int // The current retry count.
}
+60 -11
View File
@@ -8,6 +8,7 @@ import (
"time" "time"
dg "github.com/bwmarrin/discordgo" dg "github.com/bwmarrin/discordgo"
"github.com/hrfee/jfa-go/common"
lm "github.com/hrfee/jfa-go/logmessages" lm "github.com/hrfee/jfa-go/logmessages"
"github.com/timshannon/badgerhold/v4" "github.com/timshannon/badgerhold/v4"
) )
@@ -28,6 +29,7 @@ type DiscordDaemon struct {
commandHandlers map[string]func(s *dg.Session, i *dg.InteractionCreate, lang string) commandHandlers map[string]func(s *dg.Session, i *dg.InteractionCreate, lang string)
commandIDs []string commandIDs []string
commandDescriptions []*dg.ApplicationCommand commandDescriptions []*dg.ApplicationCommand
retryOpts *common.MustAuthenticateOptions
} }
func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) { func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
@@ -59,6 +61,16 @@ func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
dd.users[user.ID] = user dd.users[user.ID] = user
} }
dd.retryOpts = &common.MustAuthenticateOptions{
RetryCount: app.config.Section("advanced").Key("auth_retry_count").MustInt(6),
RetryGap: time.Duration(app.config.Section("advanced").Key("auth_retry_gap").MustInt(10)) * time.Second,
LogFailures: true,
}
dd.bot.AddHandler(dd.commandHandler)
dd.bot.Identify.Intents = dg.IntentsGuildMessages | dg.IntentsDirectMessages | dg.IntentsGuildMembers | dg.IntentsGuildInvites
return dd, nil return dd, nil
} }
@@ -99,13 +111,27 @@ func (d *DiscordDaemon) MustGetUser(channelID, userID, discrim, username string)
return d.NewUnknownUser(channelID, userID, discrim, username) return d.NewUnknownUser(channelID, userID, discrim, username)
} }
func (d *DiscordDaemon) run() { func (d *DiscordDaemon) Run() {
d.bot.AddHandler(d.commandHandler) ro := common.MustAuthenticateOptions{}
ro = *d.retryOpts
ro.Counter = 0
d.run(&ro)
}
d.bot.Identify.Intents = dg.IntentsGuildMessages | dg.IntentsDirectMessages | dg.IntentsGuildMembers | dg.IntentsGuildInvites func (d *DiscordDaemon) run(retry *common.MustAuthenticateOptions) {
if err := d.bot.Open(); err != nil { if err := d.bot.Open(); err != nil {
d.app.err.Printf(lm.FailedStartDaemon, lm.Discord, err) if retry == nil || retry.LogFailures {
return d.app.err.Printf(lm.FailedStartDaemon, lm.Discord, err)
}
if retry != nil {
retry.Counter += 1
if retry.Counter >= retry.RetryCount {
return
}
time.Sleep(retry.RetryGap)
d.run(retry)
return
}
} }
// Wait for everything to populate, it's slow sometimes. // Wait for everything to populate, it's slow sometimes.
for d.bot.State == nil { for d.bot.State == nil {
@@ -135,15 +161,18 @@ func (d *DiscordDaemon) run() {
d.InviteChannel.Name = invChannel d.InviteChannel.Name = invChannel
} }
} }
err = d.bot.UpdateGameStatus(0, "/"+d.app.config.Section("discord").Key("start_command").MustString("start")) d.bot.UpdateGameStatus(0, "/"+d.app.config.Section("discord").Key("start_command").MustString("start"))
defer d.deregisterCommands() defer d.deregisterCommands()
defer d.bot.Close() defer d.bot.Close()
go d.registerCommands() ro := common.MustAuthenticateOptions{}
ro = *(d.retryOpts)
ro.Counter = 0
go d.registerCommands(&ro)
<-d.ShutdownChannel <-d.ShutdownChannel
d.ShutdownChannel <- "Down" d.ShutdownChannel <- "Down"
return
} }
// ListRoles returns a list of available (excluding bot and @everyone) roles in a guild as a list of containing an array of the guild ID and its name. // ListRoles returns a list of available (excluding bot and @everyone) roles in a guild as a list of containing an array of the guild ID and its name.
@@ -333,7 +362,7 @@ func (d *DiscordDaemon) Shutdown() {
close(d.ShutdownChannel) close(d.ShutdownChannel)
} }
func (d *DiscordDaemon) registerCommands() { func (d *DiscordDaemon) registerCommands(retry *common.MustAuthenticateOptions) {
d.commandDescriptions = []*dg.ApplicationCommand{ d.commandDescriptions = []*dg.ApplicationCommand{
{ {
Name: d.app.config.Section("discord").Key("start_command").MustString("start"), Name: d.app.config.Section("discord").Key("start_command").MustString("start"),
@@ -430,7 +459,27 @@ func (d *DiscordDaemon) registerCommands() {
// if err != nil { // if err != nil {
// d.app.err.Printf("Discord: Cannot create commands: %v", err) // d.app.err.Printf("Discord: Cannot create commands: %v", err)
// } // }
for i, cmd := range d.commandDescriptions {
cCommands, err := d.bot.ApplicationCommandBulkOverwrite(d.bot.State.User.ID, d.guildID, d.commandDescriptions)
if err != nil {
if retry == nil || retry.LogFailures {
d.app.err.Printf(lm.FailedRegisterDiscordCommand, "*", err)
}
if retry != nil {
retry.Counter += 1
if retry.Counter >= retry.RetryCount {
return
}
time.Sleep(retry.RetryGap)
d.registerCommands(retry)
}
} else {
for i := range len(d.commandDescriptions) {
d.commandIDs[i] = cCommands[i].ID
}
d.app.debug.Printf(lm.RegisterDiscordCommand, "*")
}
/* for i, cmd := range d.commandDescriptions {
command, err := d.bot.ApplicationCommandCreate(d.bot.State.User.ID, d.guildID, cmd) command, err := d.bot.ApplicationCommandCreate(d.bot.State.User.ID, d.guildID, cmd)
if err != nil { if err != nil {
d.app.err.Printf(lm.FailedRegisterDiscordCommand, cmd.Name, err) d.app.err.Printf(lm.FailedRegisterDiscordCommand, cmd.Name, err)
@@ -438,7 +487,7 @@ func (d *DiscordDaemon) registerCommands() {
d.app.debug.Printf(lm.RegisterDiscordCommand, cmd.Name) d.app.debug.Printf(lm.RegisterDiscordCommand, cmd.Name)
d.commandIDs[i] = command.ID d.commandIDs[i] = command.ID
} }
} } */
} }
func (d *DiscordDaemon) deregisterCommands() { func (d *DiscordDaemon) deregisterCommands() {
+1 -1
View File
@@ -542,7 +542,7 @@ func start(asDaemon, firstCall bool) {
discordEnabled = false discordEnabled = false
} else { } else {
app.debug.Println(lm.InitDiscord) app.debug.Println(lm.InitDiscord)
go app.discord.run() go app.discord.Run()
defer app.discord.Shutdown() defer app.discord.Shutdown()
app.contactMethods = append(app.contactMethods, app.discord) app.contactMethods = append(app.contactMethods, app.discord)
} }