package discord import ( "context" "fmt" "time" "gitea.dwysokinski.me/twhelp/dcbot/internal/domain" "github.com/bwmarrin/discordgo" "github.com/robfig/cron/v3" ) type GroupService interface { Create(ctx context.Context, params domain.CreateGroupParams) (domain.Group, error) SetChannelGains(ctx context.Context, id, serverID, channel string) (domain.Group, error) SetChannelLosses(ctx context.Context, id, serverID, channel string) (domain.Group, error) List(ctx context.Context, params domain.ListGroupsParams) ([]domain.Group, error) Delete(ctx context.Context, id, serverID string) error } type MonitorService interface { Create(ctx context.Context, groupID, serverID, tribeTag string) (domain.Monitor, error) List(ctx context.Context, groupID, serverID string) ([]domain.MonitorWithTribe, error) Execute(ctx context.Context) ([]domain.EnnoblementNotification, error) Delete(ctx context.Context, id, serverID string) error } type ChoiceService interface { Versions(ctx context.Context) ([]domain.Choice, error) } type Bot struct { s *discordgo.Session c *cron.Cron groupSvc GroupService monitorSvc MonitorService choiceSvc ChoiceService } func NewBot(token string, groupSvc GroupService, monitorSvc MonitorService, client ChoiceService) (*Bot, error) { s, err := discordgo.New("Bot " + token) if err != nil { return nil, fmt.Errorf("discordgo.New: %w", err) } s.Identify.Intents = discordgo.IntentsNone b := &Bot{ s: s, c: cron.New( cron.WithLocation(time.UTC), cron.WithChain( cron.SkipIfStillRunning(cron.DiscardLogger), ), ), groupSvc: groupSvc, monitorSvc: monitorSvc, choiceSvc: client, } b.s.AddHandler(b.handleSessionReady) return b, nil } func (b *Bot) Run() error { if err := b.initCron(); err != nil { return fmt.Errorf("initCron: %w", err) } if err := b.s.Open(); err != nil { return fmt.Errorf("s.Open: %w", err) } if err := b.registerCommands(); err != nil { _ = b.s.Close() return fmt.Errorf("couldn't register commands: %w", err) } b.c.Run() return nil } type command interface { name() string register(s *discordgo.Session) error } func (b *Bot) registerCommands() error { commands := []command{ &groupCommand{groupSvc: b.groupSvc, choiceSvc: b.choiceSvc}, &monitorCommand{svc: b.monitorSvc}, } for _, c := range commands { if err := b.registerCommand(c); err != nil { return err } } return nil } func (b *Bot) registerCommand(cmd command) error { if err := cmd.register(b.s); err != nil { return fmt.Errorf("couldn't register command '%s': %w", cmd.name(), err) } return nil } func (b *Bot) initCron() error { _, err := b.c.AddJob("@every 1m", &executeMonitorsJob{svc: b.monitorSvc, s: b.s}) if err != nil { return err } return nil } func (b *Bot) handleSessionReady(s *discordgo.Session, _ *discordgo.Ready) { _ = s.UpdateGameStatus(0, "Tribal Wars") } func (b *Bot) Close() error { <-b.c.Stop().Done() return b.s.Close() }