diff --git a/discord/commands/handler.go b/discord/commands/handler.go index 0f03afa..751865d 100644 --- a/discord/commands/handler.go +++ b/discord/commands/handler.go @@ -28,6 +28,7 @@ func InitializeBot() { service.Discord.AddHandler(OnGuildMemberUpdate) service.Discord.AddHandler(OnGuildMemberRemove) service.Discord.AddHandler(OnUserUpdate) + service.Discord.AddHandler(OnThreadUpdate) service.Discord.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAll) err := service.Discord.Open() if err != nil { @@ -166,6 +167,24 @@ func OnUserUpdate(s *discordgo.Session, u *discordgo.UserUpdate) { service.SyncDiscordUserAvatar(u.ID, member.AvatarURL("256")) } +// OnThreadUpdate keeps guild threads alive indefinitely. Discord doesn't +// allow disabling thread auto-archival (7-day window at most), so when a +// thread flips to archived we immediately flip it back. Unarchiving emits +// another ThreadUpdate with Archived=false, which falls through the guard +// below — no loop. Locked threads are left alone: locking is an explicit +// moderator "this thread is closed" signal, and force-unarchiving those +// would fight moderation. +func OnThreadUpdate(s *discordgo.Session, t *discordgo.ThreadUpdate) { + if t.GuildID != config.DiscordGuild { + return + } + if t.ThreadMetadata == nil || !t.ThreadMetadata.Archived || t.ThreadMetadata.Locked { + return + } + logger.SugarLogger.Infof("ThreadUpdate: thread %s (%s) was archived, keeping alive", t.ID, t.Name) + service.KeepThreadAlive(t.Channel) +} + func diffRoles(before, after []string) (added, removed []string) { beforeSet := make(map[string]struct{}, len(before)) for _, r := range before { diff --git a/discord/service/thread_keepalive.go b/discord/service/thread_keepalive.go new file mode 100644 index 0000000..7ddfb59 --- /dev/null +++ b/discord/service/thread_keepalive.go @@ -0,0 +1,24 @@ +package service + +import ( + "github.com/bwmarrin/discordgo" + "github.com/gaucho-racing/sentinel/discord/pkg/logger" +) + +// KeepThreadAlive unarchives a thread that Discord just auto-archived and +// bumps its auto-archive window to the maximum (7 days) so the gateway only +// re-archives it weekly instead of on the channel's default window. The +// unarchive is silent — no message is posted and members aren't notified. +// Requires the bot to have MANAGE_THREADS in the guild. +func KeepThreadAlive(thread *discordgo.Channel) { + archived := false + _, err := Discord.ChannelEdit(thread.ID, &discordgo.ChannelEdit{ + Archived: &archived, + AutoArchiveDuration: 10080, + }) + if err != nil { + logger.SugarLogger.Errorf("thread keepalive: failed to unarchive thread %s (%s): %v", thread.ID, thread.Name, err) + return + } + logger.SugarLogger.Infof("thread keepalive: unarchived thread %s (%s)", thread.ID, thread.Name) +}