package migrations import ( "encoding/json" "errors" "fmt" "log/slog" "git.sr.ht/~ashkeel/strimertul/twitch/eventsub" "git.sr.ht/~ashkeel/strimertul/database" "git.sr.ht/~ashkeel/strimertul/twitch/alerts" "git.sr.ht/~ashkeel/strimertul/twitch/chat" "git.sr.ht/~ashkeel/strimertul/twitch/timers" "github.com/nicklaw5/helix/v2" ) func migrateToV4(db database.Database, logger *slog.Logger) error { logger.Info("Migrating database from v3 to v4") // Rename keys that have no schema changes for oldKey, newKey := range map[string]string{ "twitch/bot-modules/timers/config": timers.ConfigKey, "twitch/bot-modules/alerts/config": alerts.ConfigKey, "twitch/bot-custom-commands": chat.CustomCommandsKey, } { if err := renameKey(db, oldKey, newKey, true); err != nil { return fmt.Errorf("failed to rename key '%s' to '%s': %w", oldKey, newKey, err) } } // Clear old event keys and IRC-related keys for _, key := range []string{ "twitch/chat-activity", "twitch/chat-history", "twitch/@send-chat-message", "twitch/bot/@send-message", "twitch/ev/chat-message", "twitch/ev/eventsub-event", } { if err := db.RemoveKey(key); err != nil { return fmt.Errorf("failed to remove key '%s': %w", key, err) } } // Migrate bot config to chat config var botConfig struct { CommandCooldown int `json:"command_cooldown"` } if err := db.GetJSON("twitch/bot-config", &botConfig); err != nil { if errors.Is(err, database.ErrEmptyKey) { botConfig.CommandCooldown = 0 } else { return fmt.Errorf("failed to get bot config: %w", err) } } if err := db.PutJSON(chat.ConfigKey, chat.Config{ CommandCooldown: botConfig.CommandCooldown, }); err != nil { return fmt.Errorf("failed to put chat config to new key: %w", err) } // Migrate eventsub history to their new keys type eventSubNotification struct { Subscription helix.EventSubSubscription `json:"subscription"` Event json.RawMessage `json:"event"` } var eventsubHistory []eventSubNotification if err := db.GetJSON("twitch/eventsub-history", &eventsubHistory); err != nil { if !errors.Is(err, database.ErrEmptyKey) { return fmt.Errorf("failed to get eventsub history: %w", err) } eventsubHistory = []eventSubNotification{} } eventsubHistoryMap := make(map[string][]eventSubNotification) for _, notification := range eventsubHistory { key := eventsub.HistoryKeyPrefix + notification.Subscription.Type eventsubHistoryMap[key] = append(eventsubHistoryMap[key], notification) } for key, notifications := range eventsubHistoryMap { if err := db.PutJSON(key, notifications); err != nil { return fmt.Errorf("failed to put eventsub history to new key '%s': %w", key, err) } } // Clear old eventsub history key if err := db.RemoveKey("twitch/eventsub-history"); err != nil { return fmt.Errorf("failed to remove key 'twitch/eventsub-history': %w", err) } return nil }