hdmistat/internal/config/config.go
2025-07-24 14:32:50 +02:00

131 lines
3.0 KiB
Go

// Package config provides configuration management for hdmistat
package config
import (
"context"
"log/slog"
"os"
"time"
"git.eeqj.de/sneak/smartconfig"
)
const (
defaultWidth = 1920
defaultHeight = 1080
)
// Config holds the application configuration
type Config struct {
FramebufferDevice string
RotationInterval string
UpdateInterval string
Screens []string
LogLevel string
Width int
Height int
// Parsed durations (not from config)
rotationDuration time.Duration
updateDuration time.Duration
}
// Load loads configuration from all available sources
func Load(_ context.Context) (*Config, error) {
// Start with defaults
cfg := &Config{
FramebufferDevice: "/dev/fb0",
RotationInterval: "10s",
UpdateInterval: "1s",
Screens: []string{"overview", "top_cpu", "top_memory"},
LogLevel: "info",
Width: defaultWidth,
Height: defaultHeight,
}
// Try to load from the default location for hdmistat
sc, err := smartconfig.NewFromAppName("hdmistat")
if err == nil {
// Override defaults with config file values if they exist
if val, err := sc.GetString("framebuffer_device"); err == nil && val != "" {
cfg.FramebufferDevice = val
}
if val, err := sc.GetString("rotation_interval"); err == nil && val != "" {
cfg.RotationInterval = val
}
if val, err := sc.GetString("update_interval"); err == nil && val != "" {
cfg.UpdateInterval = val
}
if val, err := sc.GetString("log_level"); err == nil && val != "" {
cfg.LogLevel = val
}
if val, err := sc.GetInt("width"); err == nil && val > 0 {
cfg.Width = val
}
if val, err := sc.GetInt("height"); err == nil && val > 0 {
cfg.Height = val
}
// Load screens array
if screensRaw, exists := sc.Get("screens"); exists {
if screens, ok := screensRaw.([]interface{}); ok && len(screens) > 0 {
cfg.Screens = make([]string, 0, len(screens))
for _, s := range screens {
if str, ok := s.(string); ok {
cfg.Screens = append(cfg.Screens, str)
}
}
}
}
}
// Override with environment variables if set
if envLogLevel := os.Getenv("HDMISTAT_LOG_LEVEL"); envLogLevel != "" {
cfg.LogLevel = envLogLevel
}
// Parse durations
cfg.rotationDuration, err = time.ParseDuration(cfg.RotationInterval)
if err != nil {
return nil, err
}
cfg.updateDuration, err = time.ParseDuration(cfg.UpdateInterval)
if err != nil {
return nil, err
}
return cfg, nil
}
// GetRotationDuration returns the parsed rotation interval
func (c *Config) GetRotationDuration() time.Duration {
return c.rotationDuration
}
// GetUpdateDuration returns the parsed update interval
func (c *Config) GetUpdateDuration() time.Duration {
return c.updateDuration
}
// GetLogLevel returns the slog level
func (c *Config) GetLogLevel() slog.Level {
switch c.LogLevel {
case "debug":
return slog.LevelDebug
case "info":
return slog.LevelInfo
case "warn":
return slog.LevelWarn
case "error":
return slog.LevelError
default:
return slog.LevelInfo
}
}