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

@@ -8,9 +8,9 @@ import (
"log/slog"
"os"
"path/filepath"
"runtime"
"time"
"git.eeqj.de/sneak/routewatch/internal/config"
"git.eeqj.de/sneak/routewatch/pkg/asinfo"
"github.com/google/uuid"
_ "github.com/mattn/go-sqlite3" // CGO SQLite driver
@@ -28,77 +28,22 @@ type Database struct {
path string
}
// Config holds database configuration
type Config struct {
Path string
}
// getDefaultDatabasePath returns the appropriate database path for the OS
func getDefaultDatabasePath() string {
const dbFilename = "db.sqlite"
switch runtime.GOOS {
case "darwin":
// macOS: ~/Library/Application Support/berlin.sneak.app.routewatch/db.sqlite
home, err := os.UserHomeDir()
if err != nil {
return dbFilename
}
appSupport := filepath.Join(home, "Library", "Application Support", "berlin.sneak.app.routewatch")
if err := os.MkdirAll(appSupport, dirPermissions); err != nil {
return dbFilename
}
return filepath.Join(appSupport, dbFilename)
default:
// Linux and others: /var/lib/routewatch/db.sqlite
dbDir := "/var/lib/routewatch"
if err := os.MkdirAll(dbDir, dirPermissions); err != nil {
// Fall back to user's home directory if can't create system directory
home, err := os.UserHomeDir()
if err != nil {
return dbFilename
}
userDir := filepath.Join(home, ".local", "share", "routewatch")
if err := os.MkdirAll(userDir, dirPermissions); err != nil {
return dbFilename
}
return filepath.Join(userDir, dbFilename)
}
return filepath.Join(dbDir, dbFilename)
}
}
// NewConfig provides default database configuration
func NewConfig() Config {
return Config{
Path: getDefaultDatabasePath(),
}
}
// New creates a new database connection and initializes the schema.
func New(logger *slog.Logger) (*Database, error) {
config := NewConfig()
func New(cfg *config.Config, logger *slog.Logger) (*Database, error) {
dbPath := filepath.Join(cfg.GetStateDir(), "db.sqlite")
return NewWithConfig(config, logger)
}
// NewWithConfig creates a new database connection with custom configuration
func NewWithConfig(config Config, logger *slog.Logger) (*Database, error) {
// Log database path
logger.Info("Opening database", "path", config.Path)
logger.Info("Opening database", "path", dbPath)
// Ensure directory exists
dir := filepath.Dir(config.Path)
dir := filepath.Dir(dbPath)
if err := os.MkdirAll(dir, dirPermissions); err != nil {
return nil, fmt.Errorf("failed to create database directory: %w", err)
}
// Add connection parameters for go-sqlite3
// Enable WAL mode and other performance optimizations
dsn := fmt.Sprintf("file:%s?_busy_timeout=5000&_journal_mode=WAL&_synchronous=NORMAL&cache=shared", config.Path)
dsn := fmt.Sprintf("file:%s?_busy_timeout=5000&_journal_mode=WAL&_synchronous=NORMAL&cache=shared", dbPath)
db, err := sql.Open("sqlite3", dsn)
if err != nil {
return nil, fmt.Errorf("failed to open database: %w", err)
@@ -113,7 +58,7 @@ func NewWithConfig(config Config, logger *slog.Logger) (*Database, error) {
db.SetMaxIdleConns(1)
db.SetConnMaxLifetime(0)
database := &Database{db: db, logger: logger, path: config.Path}
database := &Database{db: db, logger: logger, path: dbPath}
if err := database.Initialize(); err != nil {
return nil, fmt.Errorf("failed to initialize database: %w", err)