feat: removed comments and uses the passed whitelists
This commit is contained in:
70
watcher.go
70
watcher.go
@@ -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)
|
}
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user