Inject Config as dependency for database, routing table, and snapshotter

- Remove old database Config struct and related functions
- Update database.New() to accept config.Config parameter
- Update routingtable.New() to accept config.Config parameter
- Update snapshotter.New() to accept config.Config parameter
- Simplify fx module providers in app.go
- Fix truthiness check for environment variables
- Handle empty state directory gracefully in routing table and snapshotter
- Update all tests to use empty state directory for testing
This commit is contained in:
2025-07-28 00:55:09 +02:00
parent 1a0622efaa
commit d15a5e91b9
7 changed files with 174 additions and 174 deletions

View File

@@ -10,16 +10,16 @@ import (
"log/slog"
"os"
"path/filepath"
"runtime"
"sync"
"time"
"git.eeqj.de/sneak/routewatch/internal/config"
"git.eeqj.de/sneak/routewatch/internal/routingtable"
)
const (
snapshotInterval = 10 * time.Minute
snapshotFilename = "routewatch-snapshot.json.gz"
snapshotFilename = "routingtable.json.gz"
tempFileSuffix = ".tmp"
)
@@ -36,16 +36,15 @@ type Snapshotter struct {
}
// New creates a new Snapshotter instance
func New(rt *routingtable.RoutingTable, logger *slog.Logger) (*Snapshotter, error) {
stateDir, err := getStateDirectory()
if err != nil {
return nil, fmt.Errorf("failed to determine state directory: %w", err)
}
func New(rt *routingtable.RoutingTable, cfg *config.Config, logger *slog.Logger) (*Snapshotter, error) {
stateDir := cfg.GetStateDir()
// Ensure state directory exists
const stateDirPerms = 0750
if err := os.MkdirAll(stateDir, stateDirPerms); err != nil {
return nil, fmt.Errorf("failed to create state directory: %w", err)
// If state directory is specified, ensure it exists
if stateDir != "" {
const stateDirPerms = 0750
if err := os.MkdirAll(stateDir, stateDirPerms); err != nil {
return nil, fmt.Errorf("failed to create snapshot directory: %w", err)
}
}
s := &Snapshotter{
@@ -76,38 +75,6 @@ func (s *Snapshotter) Start(ctx context.Context) {
go s.periodicSnapshot()
}
// getStateDirectory returns the appropriate state directory based on the OS
func getStateDirectory() (string, error) {
switch runtime.GOOS {
case "darwin":
// macOS: Use ~/Library/Application Support/routewatch
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, "Library", "Application Support", "routewatch"), nil
case "linux", "freebsd", "openbsd", "netbsd":
// Unix-like: Use /var/lib/routewatch if running as root, otherwise use XDG_STATE_HOME
if os.Geteuid() == 0 {
return "/var/lib/routewatch", nil
}
// Check XDG_STATE_HOME first
if xdgState := os.Getenv("XDG_STATE_HOME"); xdgState != "" {
return filepath.Join(xdgState, "routewatch"), nil
}
// Fall back to ~/.local/state/routewatch
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".local", "state", "routewatch"), nil
default:
return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
}
}
// periodicSnapshot runs periodic snapshots
func (s *Snapshotter) periodicSnapshot() {
defer s.wg.Done()
@@ -130,6 +97,11 @@ func (s *Snapshotter) periodicSnapshot() {
// TakeSnapshot creates a snapshot of the current routing table state
func (s *Snapshotter) TakeSnapshot() error {
// Can't take snapshot without a state directory
if s.stateDir == "" {
return nil
}
// Ensure only one snapshot runs at a time
s.mu.Lock()
defer s.mu.Unlock()