diff --git a/main.go b/main.go index de42767..c3cd2de 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( "time" "github.com/bwmarrin/discordgo" - _ "github.com/mattn/go-sqlite3" // SQLite3-Treiber importieren + _ "modernc.org/sqlite" // SQLite3-Treiber importieren ) // ===== Defaults / Names (pro Guild per Commands konfigurierbar) ===== @@ -46,10 +46,14 @@ type GuildConfig struct { var db *sql.DB +// ===== Global variables for sync.Map ===== +var guildCfgs sync.Map // Für Guild-Konfigurationen +var createdCmds sync.Map // Für erstellte Commands + // Initialize DB func initDB() { var err error - db, err = sql.Open("sqlite3", dbPath) + db, err = sql.Open("sqlite", dbPath) if err != nil { log.Fatalf("Datenbank-Fehler: %v", err) } @@ -88,11 +92,11 @@ func loadGuildCfgs() error { if err := rows.Scan(&guildID, &lobbyName, &categoryName, &timeoutMin); err != nil { return err } - guildCfgs[guildID] = &GuildConfig{ + guildCfgs.Store(guildID, &GuildConfig{ LobbyName: lobbyName, CategoryName: categoryName, TimeoutMin: timeoutMin, - } + }) } return nil @@ -106,8 +110,10 @@ func saveGuildCfgs() error { } defer tx.Rollback() - for guildID, cfg := range guildCfgs { - // UPDATE oder INSERT, je nachdem, ob es bereits eine Konfiguration gibt + guildCfgs.Range(func(key, value interface{}) bool { + guildID := key.(string) + cfg := value.(*GuildConfig) + _, err := tx.Exec(` INSERT INTO guild_config (guild_id, lobby_name, category_name, timeout_min) VALUES (?, ?, ?, ?) @@ -118,46 +124,35 @@ func saveGuildCfgs() error { timeout_min = excluded.timeout_min `, guildID, cfg.LobbyName, cfg.CategoryName, cfg.TimeoutMin) if err != nil { - return err + log.Printf("Fehler beim Speichern der Guild-Konfiguration: %v", err) } - } + return true + }) // Transaktion abschließen return tx.Commit() } -var ( - cfgMu sync.Mutex - guildCfgs = map[string]*GuildConfig{} - createdCmds = map[string][]*discordgo.ApplicationCommand{} // guildID -> cmds -) - +// Guild-Konfiguration laden oder Standardwerte zurückgeben func getCfg(guildID string) *GuildConfig { - cfgMu.Lock() - c, ok := guildCfgs[guildID] - cfgMu.Unlock() - if ok { - return c + if cfg, ok := guildCfgs.Load(guildID); ok { + return cfg.(*GuildConfig) } - - // Falls nicht vorhanden, Daten aus DB laden var guildCfg GuildConfig err := db.QueryRow("SELECT lobby_name, category_name, timeout_min FROM guild_config WHERE guild_id = ?", guildID).Scan(&guildCfg.LobbyName, &guildCfg.CategoryName, &guildCfg.TimeoutMin) if err != nil { - if err != sql.ErrNoRows { - log.Printf("Fehler beim Abrufen der Guild-Konfiguration: %v", err) + if err == sql.ErrNoRows { + log.Printf("Guild-Konfiguration für %s nicht gefunden, verwenden der Standardwerte", guildID) + } else { + log.Printf("Fehler beim Abrufen der Guild-Konfiguration für %s: %v", guildID, err) } - // Fallback-Werte, falls die Guild nicht in der DB existiert guildCfg = GuildConfig{ LobbyName: defaultLobbyName, CategoryName: defaultCategory, TimeoutMin: envTimeoutDefault(1), } } - - cfgMu.Lock() - guildCfgs[guildID] = &guildCfg - cfgMu.Unlock() + guildCfgs.Store(guildID, &guildCfg) return &guildCfg } @@ -520,9 +515,7 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter } // speichern - cfgMu.Lock() getCfg(guildID).LobbyName = name - cfgMu.Unlock() if err := saveGuildCfgs(); err != nil { log.Printf("saveGuildCfgs failed: %v", err) _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ @@ -577,9 +570,7 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter } // speichern - cfgMu.Lock() getCfg(guildID).CategoryName = name - cfgMu.Unlock() if err := saveGuildCfgs(); err != nil { log.Printf("saveGuildCfgs failed: %v", err) _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ @@ -627,10 +618,8 @@ func onInteractionCreate(_ string) func(s *discordgo.Session, i *discordgo.Inter log.Printf("Setting timeout for %d minutes", minutes) // speichern - cfgMu.Lock() getCfg(guildID).TimeoutMin = int(minutes) log.Println("1-0815") - cfgMu.Unlock() if err := saveGuildCfgs(); err != nil { log.Printf("saveGuildCfgs failed: %v", err) _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ @@ -760,9 +749,13 @@ func onGuildCreate(s *discordgo.Session, g *discordgo.GuildCreate) { log.Printf("Command-Registrierung in %s fehlgeschlagen: %v", g.Name, err) continue } - cfgMu.Lock() - createdCmds[g.ID] = append(createdCmds[g.ID], c) - cfgMu.Unlock() + + // Commands für die Guild speichern + // Wir verwenden sync.Map, also müssen wir die 'Load' und 'Store' Methoden verwenden. + commands, _ := createdCmds.LoadOrStore(g.ID, []*discordgo.ApplicationCommand{}) + commands = append(commands.([]*discordgo.ApplicationCommand), c) + createdCmds.Store(g.ID, commands) + log.Printf("Command-Registrierung in %s", g.Name) } } @@ -855,33 +848,7 @@ func main() { s.AddHandler(onVoiceStateUpdate) s.AddHandler(onGuildCreate) - /*s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) { - for _, g := range s.State.Guilds { - registerCommandsForGuild(s, g.ID) - } - }) - s.AddHandler(func(s *discordgo.Session, g *discordgo.GuildCreate) { - registerCommandsForGuild(s, g.ID) - })*/ s.AddHandler(onInteractionCreate("")) - /*s.AddHandler(func(s *discordgo.Session, r *discordgo.Ready) { - log.Printf("Eingeloggt als %s", r.User.Username) - registerOnce.Do(func() { - appID := s.State.User.ID - for _, g := range s.State.Guilds { - log.Printf("Registriere Commands in Guild: %s (%s)", g.Name, g.ID) - for _, cmd := range slashCommands { - c, err := s.ApplicationCommandCreate(appID, g.ID, cmd) - if err != nil { - log.Printf("Command-Registrierung in %s fehlgeschlagen: %v", g.Name, err) - continue - } - createdCmds[g.ID] = append(createdCmds[g.ID], c) - } - } - log.Printf("Defaults → Lobby: %q | Kategorie: %q | Timeout: %d min", defaultLobbyName, defaultCategory, envTimeoutDefault(60)) - }) - })*/ if err := s.Open(); err != nil { log.Fatalf("Gateway-Start fehlgeschlagen: %v", err) @@ -894,15 +861,17 @@ func main() { log.Println("Fahre herunter…") appID := s.State.User.ID - for guildID, cmds := range createdCmds { - for _, c := range cmds { - if delErr := s.ApplicationCommandDelete(appID, guildID, c.ID); delErr != nil { - log.Printf("Cmd-Delete (%s/%s) fehlgeschlagen: %v", guildID, c.Name, delErr) + createdCmds.Range(func(key, value interface{}) bool { + for _, c := range value.([]*discordgo.ApplicationCommand) { + if delErr := s.ApplicationCommandDelete(appID, key.(string), c.ID); delErr != nil { + log.Printf("Cmd-Delete (%s/%s) fehlgeschlagen: %v", key, c.Name, delErr) } else { - log.Printf("Cmd-Delete (%s/%s) ok", guildID, c.Name) + log.Printf("Cmd-Delete (%s/%s) ok", key, c.Name) } } - } + return true + }) + if err := saveGuildCfgs(); err != nil { log.Printf("Speichern zum Shutdown fehlgeschlagen: %v", err) }