package main import ( "bufio" "log/slog" "os" "time" ) type watcher struct { path string interval time.Duration store *PermanentWhitelist lastMod time.Time } func newPermanentWhitelistWatcher(path string, interval time.Duration, store *PermanentWhitelist) *watcher { w := &watcher{ path: path, interval: interval, store: store, } w.reload() return w } func (w *watcher) start() { go func() { ticker := time.NewTicker(w.interval) defer ticker.Stop() for range ticker.C { w.reload() } }() } func (w *watcher) reload() { info, err := os.Stat(w.path) if err != nil { return } if info.ModTime().Equal(w.lastMod) { return } w.lastMod = info.ModTime() entries := make(map[string]struct{}) f, err := os.Open(w.path) if err != nil { slog.Error("failed to open whitelist file", "error", err) return } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() if line == "" || line[0] == '#' { continue } entries[line] = struct{}{} } w.store.mu.Lock() w.store.entries = entries w.store.mu.Unlock() slog.Info("reloaded permanent whitelist", "count", len(entries)) }