diff --git a/db_management/db_management.go b/db_management/db_management.go index e3ea62c..ff22ce2 100644 --- a/db_management/db_management.go +++ b/db_management/db_management.go @@ -2,6 +2,8 @@ package db_management import ( "database/sql" + "log" + "os" "time" _ "modernc.org/sqlite" @@ -90,3 +92,18 @@ func GetTopUsers(limit int) []UserStats { return result } + +func CleanupOldEntries() { + query := `DELETE FROM voice_sessions WHERE created_at < datetime('now', '-40 days)` + + result, err := DB.Exec(query) + if err != nil { + log.Printf("Fehler beim DB-Cleanup: %v", err) + return + } + + rowsAffected, _ := result.RowsAffected() + if rowsAffected > 0 { + log.Printf("DB Cleanup erfolgreich: %d alte Einträge gelöscht.", rowsAffected) + } +} diff --git a/docker-compose.yaml b/docker-compose.yaml index 1d04fe4..ea7bb29 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -15,6 +15,7 @@ services: environment: - DB_PATH=/app/data/bot.db + - DISCORD_TOKEN=${DISCORD_TOKEN} deploy: resources: diff --git a/go.mod b/go.mod index 8646adc..23165f6 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/ncruces/go-strftime v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect golang.org/x/sys v0.42.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 8517d5a..dac07c4 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= diff --git a/main.go b/main.go index 3b64b32..3d6fbc5 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "github.com/bwmarrin/discordgo" "github.com/joho/godotenv" + "github.com/robfig/cron/v3" "heydeman/vc-stat-bot-discord/db_management" ) @@ -38,22 +39,39 @@ func main() { log.Fatal(err) } - // Handler + // Handler & Intents discord.AddHandler(interactionCreate) discord.AddHandler(voiceUpdate) - - // Intents - discord.Identify.Intents = discordgo.IntentsGuilds | - discordgo.IntentsGuildVoiceStates + discord.Identify.Intents = discordgo.IntentsGuilds | discordgo.IntentsGuildVoiceStates err = discord.Open() if err != nil { log.Fatal("Error opening connection:", err) } - // Slash Commands registrieren registerCommands(discord) - go autoSaveSessions() + + // ========================================== + // 🕒 CRON SCHEDULER SETUP + // ========================================== + c := cron.New() + + // Alle 5 Minuten: Aktuellen Stand in die DB schieben + _, _ = c.AddFunc("*/5 * * * *", func() { + fmt.Println("🔄 Cron Auto-Save: Speichere Zwischenstände...") + for uid, sess := range sessions { + processAndSave(uid, sess) + } + }) + + // Jeden Tag um 00:00 Uhr: Alte Daten (40+ Tage) löschen + _, _ = c.AddFunc("0 0 * * *", func() { + fmt.Println("🧹 Cron Cleanup: Lösche Daten älter als 40 Tage...") + db_management.CleanupOldEntries() + }) + + c.Start() + defer c.Stop() fmt.Println("Bot läuft stabil. CTRL+C zum Beenden.") @@ -62,22 +80,10 @@ func main() { signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM) <-stop - fmt.Println("Speichere aktive Sessions...") - - // 🔥 NEUE Shutdown-Logik (wichtig!) + fmt.Println("Speichere aktive Sessions vor Shutdown...") + // Beim Beenden alles wegschreiben, was noch im RAM ist for uid, sess := range sessions { - - var total time.Duration - - // bereits gesammelte Zeit - total += sess.Accum - - // wenn NICHT pausiert → aktuelle Zeit dazu - if !sess.Paused { - total += time.Since(sess.Start) - } - - db_management.SaveSession(uid, int(total.Seconds())) + processAndSave(uid, sess) } discord.Close() @@ -266,29 +272,34 @@ func formatDuration(d time.Duration) string { } func autoSaveSessions() { - - ticker := time.NewTicker(5 * time.Minute) // ⏱ Intervall anpassen + ticker := time.NewTicker(5 * time.Minute) defer ticker.Stop() for range ticker.C { - - fmt.Println("🔄 Auto-Save: speichere Sessions...") + fmt.Println("Auto-Save") for uid, sess := range sessions { - - var total time.Duration - - total += sess.Accum - - if !sess.Paused { - total += time.Since(sess.Start) - } - - // Zwischenspeichern (ADD statt replace!) - db_management.SaveSession(uid, int(total.Seconds())) - - // ⚠️ Wichtig: - // NICHT löschen → Session läuft weiter + processAndSave(uid, sess) + } + } +} + +// Hilfsfunktion, die die Zeit berechnet, speichert und den Timer resettet +func processAndSave(uid string, sess *Session) { + var totalToSave time.Duration + + totalToSave += sess.Accum + + if !sess.Paused { + totalToSave += time.Since(sess.Start) + } + + if totalToSave.Seconds() >= 1 { + db_management.SaveSession(uid, int(totalToSave.Seconds())) + + sess.Accum = 0 + if !sess.Paused { + sess.Start = time.Now() } } }