diff --git a/cmd/ntech/main.go b/cmd/ntech/main.go index 874ca5f..c878b5f 100644 --- a/cmd/ntech/main.go +++ b/cmd/ntech/main.go @@ -109,28 +109,6 @@ func main() { napraviBackup(db, putanjaBaze) - // periodični automatski backup — interval se čita iz podešavanja u svakom ciklusu, - // tako da izmena u podešavanjima stupa na snagu bez restarta (od sledećeg ciklusa) - go func() { - for { - sati := procitajIntPodesavanje(db, "backup_interval_sati", 24) - time.Sleep(time.Duration(sati) * time.Hour) - napraviBackup(db, putanjaBaze) - } - }() - - // periodično brisanje isteklih sesija i starih pokušaja prijave - go func() { - ticker := time.NewTicker(time.Hour) - defer ticker.Stop() - sesijeRepo := sqlite.NoviSesijeRepo(db) - pokusajiRepo := sqlite.NoviPokusajiPrijaveRepo(db) - for range ticker.C { - _ = sesijeRepo.ObrisiIstekle(context.Background()) - _ = pokusajiRepo.ObrisiStare(context.Background(), time.Now().Add(-24*time.Hour)) - } - }() - os.MkdirAll("web/static/uploads", 0755) h := handler.Novi(db, totpKljuc) @@ -151,6 +129,36 @@ func main() { log.Printf("Keš šablona kreiran: %d šablona", len(kes)) } + // Pozadinske gorutine se pokreću posle kreiranja h i rade preko h.SaBazom, + // pa uvek koriste TRENUTNU konekciju baze (posle obnove backupa h.DB se menja). + + // periodični automatski backup — interval se čita iz podešavanja u svakom + // ciklusu, pa izmena stupa na snagu bez restarta (od sledećeg ciklusa) + go func() { + for { + sati := 24 + h.SaBazom(func(db *sql.DB) { + sati = procitajIntPodesavanje(db, "backup_interval_sati", 24) + }) + time.Sleep(time.Duration(sati) * time.Hour) + h.SaBazom(func(db *sql.DB) { + napraviBackup(db, putanjaBaze) + }) + } + }() + + // periodično brisanje isteklih sesija i starih pokušaja prijave + go func() { + ticker := time.NewTicker(time.Hour) + defer ticker.Stop() + for range ticker.C { + h.SaBazom(func(db *sql.DB) { + _ = sqlite.NoviSesijeRepo(db).ObrisiIstekle(context.Background()) + _ = sqlite.NoviPokusajiPrijaveRepo(db).ObrisiStare(context.Background(), time.Now().Add(-24*time.Hour)) + }) + } + }() + r := chi.NewRouter() r.Use(ntechmw.BezbednostHeaders()) r.Use(ntechmw.CsrfMiddleware) diff --git a/internal/handler/handler.go b/internal/handler/handler.go index 85e7d4f..53a2705 100644 --- a/internal/handler/handler.go +++ b/internal/handler/handler.go @@ -57,6 +57,17 @@ func (h *Handler) ZakljucajCitanje(next http.Handler) http.Handler { }) } +// SaBazom izvršava fn sa TRENUTNOM konekcijom baze, pod deljenim zaključavanjem. +// Namenjeno pozadinskim gorutinama (auto-backup, čišćenje): posle obnove backupa +// h.DB se menja, pa gorutine moraju da čitaju aktuelni handle, a ne zatvoreni. +// Zaključavanje se drži samo za vreme fn — ne pozivaj iz njega operacije koje +// dugo blokiraju (npr. time.Sleep), da ne bi nepotrebno odlagao obnovu. +func (h *Handler) SaBazom(fn func(*sql.DB)) { + h.mu.RLock() + defer h.mu.RUnlock() + fn(h.DB) +} + // Novi kreira novi Handler sa datom bazom. // totpKljuc je 32-bajtni ključ za šifrovanje TOTP tajni u mirovanju. func Novi(baza *sql.DB, totpKljuc []byte) *Handler {