package main import ( "context" "flag" "log/slog" "os" "os/signal" "syscall" "github.com/disgoorg/disgo" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/discord" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgo/gateway" "github.com/disgoorg/snowflake/v2" "github.com/elisiei/unbot/config" "github.com/elisiei/unbot/db" "github.com/elisiei/unbot/features" ) func main() { configPath := flag.String("config", "config.toml", "path to config file") flag.Parse() cfg, err := config.Load(*configPath) if err != nil { slog.Error("failed to load config", slog.Any("err", err)) os.Exit(1) } database, err := db.Open("unbot.db") if err != nil { slog.Error("failed to open database", slog.Any("err", err)) os.Exit(1) } dict := features.NewDictionary(database, cfg.Features.Dictionary.Enabled) starboard, err := features.NewStarboard( database, cfg.Features.Starboard.WebhookURL, cfg.Features.Starboard.ChannelID, cfg.Features.Starboard.Threshold, cfg.Features.Starboard.Enabled, ) if err != nil { slog.Error("failed to create starboard", slog.Any("err", err)) os.Exit(1) } client, err := disgo.New(cfg.Bot.Token, bot.WithGatewayConfigOpts( gateway.WithIntents( gateway.IntentGuilds, gateway.IntentGuildMessages, gateway.IntentMessageContent, gateway.IntentGuildMessageReactions, ), ), bot.WithEventListenerFunc(func(e *events.AutocompleteInteractionCreate) { if cfg.Features.Dictionary.Enabled { dict.HandleAutocomplete(e) } }), bot.WithEventListenerFunc(func(e *events.GuildMessageReactionAdd) { if cfg.Features.Starboard.Enabled { starboard.HandleReactionAdd(e) } }), bot.WithEventListenerFunc(func(e *events.GuildMessageReactionRemove) { if cfg.Features.Starboard.Enabled { starboard.HandleReactionRemove(e) } }), ) if err != nil { slog.Error("failed to create client", slog.Any("err", err)) os.Exit(1) } xdTracker := features.NewXDTracker( database, client, snowflake.ID(cfg.Bot.GuildID), cfg.Features.XDTracker.Enabled, ) client.AddEventListeners( bot.NewListenerFunc(func(e *events.ApplicationCommandInteractionCreate) { handleCommand(e, dict, xdTracker, cfg) }), bot.NewListenerFunc(func(e *events.MessageCreate) { if cfg.Features.XDTracker.Enabled { xdTracker.HandleMessage(e) } }), ) iconChanger := features.NewIconChanger( client, cfg.Bot.GuildID, cfg.Features.IconChanger.ChannelID, cfg.Features.IconChanger.Interval, cfg.Features.IconChanger.Enabled, ) client.AddEventListeners(bot.NewListenerFunc(func(e *events.MessageCreate) { iconChanger.HandleMessage(e) })) iconChanger.Start() guildID := snowflake.ID(cfg.Bot.GuildID) var commands []discord.ApplicationCommandCreate if cfg.Features.Dictionary.Enabled { commands = append(commands, dict.Command()) } if cfg.Features.XDTracker.Enabled { commands = append(commands, xdTracker.Command()) } if len(commands) > 0 { if _, err := client.Rest.SetGuildCommands(client.ApplicationID, guildID, commands); err != nil { slog.Error("failed to register commands", slog.Any("err", err)) os.Exit(1) } slog.Info("registered commands") } if err := client.OpenGateway(context.TODO()); err != nil { slog.Error("failed to open gateway", slog.Any("err", err)) os.Exit(1) } slog.Info("bot is running") go xdTracker.BackfillHistory() go iconChanger.BackfillHistory() s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-s iconChanger.Stop() client.Close(context.TODO()) } func handleCommand(e *events.ApplicationCommandInteractionCreate, dict *features.Dictionary, xd *features.XDTracker, cfg *config.Config) { data := e.SlashCommandInteractionData() switch data.CommandName() { case "dict": if !cfg.Features.Dictionary.Enabled { return } opts := data.All() if len(opts) == 0 { return } subCmd := opts[0].Name switch subCmd { case "add": dict.HandleAdd(e) case "get": dict.HandleGet(e) case "remove": dict.HandleRemove(e) case "list": dict.HandleList(e) } case "xd": if !cfg.Features.XDTracker.Enabled { return } opts := data.All() if len(opts) == 0 { xd.HandleStats(e) return } subCmd := opts[0].Name switch subCmd { case "leaderboard": xd.HandleLeaderboard(e) case "stats": xd.HandleStats(e) } } }