feat: removed comments and uses the passed whitelists

This commit is contained in:
2026-05-04 08:13:25 +03:30
parent 820cb88447
commit 145980ba0f

View File

@@ -1,37 +1,19 @@
// watcher.go — permanent whitelist file watcher
//
// The watcher polls the permanent whitelist file every cfg.WatchInterval
// seconds and reloads the in-memory store if the file has changed.
//
// Why poll instead of inotify?
//
// - Polling is simpler and works inside Docker containers where inotify
// may not be available (no host filesystem access).
// - The polling interval (30s default) is fast enough for admin
// whitelisting operations.
// - If you want inotify, add it later.
//
// We only reload when the file's mtime changes, so frequent touch-
// operations don't cause unnecessary reloads.
//
// The watcher uses a mutex to protect the in-memory store. This is
// necessary because the watcher runs in a separate goroutine and the
// auth handler reads from the same store.
package main package main
import ( import (
"bufio" "bufio"
"log" "log/slog"
"os" "os"
"time" "time"
) )
// newPermanentWhitelistWatcher creates a watcher that reloads the type watcher struct {
// permanent whitelist file from disk. path string
// interval time.Duration
// The watcher loads the file once immediately on creation, then polls store *PermanentWhitelist
// every interval. lastMod time.Time
}
func newPermanentWhitelistWatcher(path string, interval time.Duration, store *PermanentWhitelist) *watcher { func newPermanentWhitelistWatcher(path string, interval time.Duration, store *PermanentWhitelist) *watcher {
w := &watcher{ w := &watcher{
path: path, path: path,
@@ -42,55 +24,32 @@ func newPermanentWhitelistWatcher(path string, interval time.Duration, store *Pe
return w return w
} }
// watcher polls a file and reloads the whitelist when it changes.
type watcher struct {
path string
interval time.Duration
store *PermanentWhitelist
lastMod time.Time
}
// start begins the polling loop.
func (w *watcher) start() { func (w *watcher) start() {
go func() { go func() {
ticker := time.NewTicker(w.interval) ticker := time.NewTicker(w.interval)
defer ticker.Stop() defer ticker.Stop()
for range ticker.C {
for { w.reload()
select {
case <-ticker.C:
w.reload()
}
} }
}() }()
} }
// reload reads the whitelist file and updates the in-memory store.
//
// We only reload if the file has changed (mtime). This prevents
// unnecessary reloads when the file is touched frequently.
func (w *watcher) reload() { func (w *watcher) reload() {
info, err := os.Stat(w.path) info, err := os.Stat(w.path)
if err != nil { if err != nil {
// File doesn't exist yet — skip.
return return
} }
// Only reload if the file has changed.
if info.ModTime().Equal(w.lastMod) { if info.ModTime().Equal(w.lastMod) {
return return
} }
w.lastMod = info.ModTime() w.lastMod = info.ModTime()
// Read and parse the file.
entries := make(map[string]struct{}) entries := make(map[string]struct{})
f, err := os.Open(w.path) f, err := os.Open(w.path)
if err != nil { if err != nil {
log.Printf("failed to open whitelist file: %v", err) slog.Error("failed to open whitelist file", "error", err)
return return
} }
defer f.Close() defer f.Close()
scanner := bufio.NewScanner(f) scanner := bufio.NewScanner(f)
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
@@ -99,11 +58,8 @@ func (w *watcher) reload() {
} }
entries[line] = struct{}{} entries[line] = struct{}{}
} }
// Update the store.
w.store.mu.Lock() w.store.mu.Lock()
w.store.entries = entries w.store.entries = entries
w.store.mu.Unlock() w.store.mu.Unlock()
slog.Info("reloaded permanent whitelist", "count", len(entries))
log.Printf("loaded %d entries from %s", len(entries), w.path) }
}