Files
insertr/internal/config/loader.go
Joakim 38c2897ece Refactor configuration system with centralized type-safe config package
- Create internal/config package with unified config structs and validation
- Abstract viper dependency behind config.Loader interface for better testability
- Replace manual config parsing and type assertions with type-safe loading
- Consolidate AuthConfig, SiteConfig, and DiscoveryConfig into single package
- Add comprehensive validation with clear error messages
- Remove ~200 lines of duplicate config handling code
- Maintain backward compatibility with existing config files
2025-10-08 17:58:03 +02:00

107 lines
2.0 KiB
Go

package config
import (
"fmt"
"github.com/spf13/viper"
)
type Loader interface {
Load(configFile string) (*Config, error)
LoadWithDefaults() (*Config, error)
LoadWithFlags(dbPath, apiURL, apiKey, siteID string) (*Config, error)
}
type viperLoader struct{}
func NewLoader() Loader {
return &viperLoader{}
}
func (l *viperLoader) Load(configFile string) (*Config, error) {
v := viper.New()
if configFile != "" {
v.SetConfigFile(configFile)
} else {
v.AddConfigPath(".")
v.SetConfigName("insertr")
v.SetConfigType("yaml")
}
v.SetEnvPrefix("INSERTR")
v.AutomaticEnv()
if err := v.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
}
config := &Config{}
if err := v.Unmarshal(config); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
if err := l.setDefaults(config); err != nil {
return nil, err
}
return config, validate(config)
}
func (l *viperLoader) LoadWithDefaults() (*Config, error) {
return l.Load("")
}
func (l *viperLoader) LoadWithFlags(dbPath, apiURL, apiKey, siteID string) (*Config, error) {
config, err := l.LoadWithDefaults()
if err != nil {
return nil, err
}
if dbPath != "" {
config.Database.Path = dbPath
}
if apiURL != "" {
config.API.URL = apiURL
}
if apiKey != "" {
config.API.Key = apiKey
}
if siteID != "" {
config.CLI.SiteID = siteID
}
return config, validate(config)
}
func (l *viperLoader) setDefaults(config *Config) error {
if config.Database.Path == "" {
config.Database.Path = "./insertr.db"
}
if config.CLI.SiteID == "" {
config.CLI.SiteID = "demo"
}
if config.Server.Port == 0 {
config.Server.Port = 8080
}
if config.Server.Host == "" {
config.Server.Host = "localhost"
}
if config.Auth.Provider == "" {
config.Auth.Provider = "mock"
}
if config.Auth.JWTSecret == "" {
config.Auth.JWTSecret = "dev-secret-change-in-production"
config.Auth.DevMode = true
}
return nil
}