package api import ( "log" "os" "path/filepath" "github.com/jfraeys/fetch_ml/internal/auth" "github.com/jfraeys/fetch_ml/internal/config" "github.com/jfraeys/fetch_ml/internal/logging" "gopkg.in/yaml.v3" ) // ServerConfig holds all server configuration type ServerConfig struct { BasePath string `yaml:"base_path"` Auth auth.Config `yaml:"auth"` Server ServerSection `yaml:"server"` Security SecurityConfig `yaml:"security"` Redis RedisConfig `yaml:"redis"` Database DatabaseConfig `yaml:"database"` Logging logging.Config `yaml:"logging"` Resources config.ResourceConfig `yaml:"resources"` } // ServerSection holds server-specific configuration type ServerSection struct { Address string `yaml:"address"` TLS TLSConfig `yaml:"tls"` } // TLSConfig holds TLS configuration type TLSConfig struct { Enabled bool `yaml:"enabled"` CertFile string `yaml:"cert_file"` KeyFile string `yaml:"key_file"` } // SecurityConfig holds security-related configuration type SecurityConfig struct { RateLimit RateLimitConfig `yaml:"rate_limit"` IPWhitelist []string `yaml:"ip_whitelist"` FailedLockout LockoutConfig `yaml:"failed_login_lockout"` } // RateLimitConfig holds rate limiting configuration type RateLimitConfig struct { Enabled bool `yaml:"enabled"` RequestsPerMinute int `yaml:"requests_per_minute"` BurstSize int `yaml:"burst_size"` } // LockoutConfig holds failed login lockout configuration type LockoutConfig struct { Enabled bool `yaml:"enabled"` MaxAttempts int `yaml:"max_attempts"` LockoutDuration string `yaml:"lockout_duration"` } // RedisConfig holds Redis connection configuration type RedisConfig struct { Addr string `yaml:"addr"` Password string `yaml:"password"` DB int `yaml:"db"` URL string `yaml:"url"` } // DatabaseConfig holds database connection configuration type DatabaseConfig struct { Type string `yaml:"type"` Connection string `yaml:"connection"` Host string `yaml:"host"` Port int `yaml:"port"` Username string `yaml:"username"` Password string `yaml:"password"` Database string `yaml:"database"` } // LoadServerConfig loads and validates server configuration func LoadServerConfig(path string) (*ServerConfig, error) { resolvedConfig, err := config.ResolveConfigPath(path) if err != nil { return nil, err } cfg, err := loadConfigFromFile(resolvedConfig) if err != nil { return nil, err } cfg.Resources.ApplyDefaults() return cfg, nil } // loadConfigFromFile loads configuration from a YAML file func loadConfigFromFile(path string) (*ServerConfig, error) { data, err := secureFileRead(path) if err != nil { return nil, err } var cfg ServerConfig if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, err } return &cfg, nil } // secureFileRead safely reads a file func secureFileRead(path string) ([]byte, error) { // This would use the fileutil.SecureFileRead function // For now, implement basic file reading return os.ReadFile(path) } // EnsureLogDirectory creates the log directory if needed func (c *ServerConfig) EnsureLogDirectory() error { if c.Logging.File == "" { return nil } logDir := filepath.Dir(c.Logging.File) log.Printf("Creating log directory: %s", logDir) return os.MkdirAll(logDir, 0750) } // BuildAuthConfig creates the auth configuration func (c *ServerConfig) BuildAuthConfig() *auth.Config { if !c.Auth.Enabled { return nil } log.Printf("Authentication enabled with %d API keys", len(c.Auth.APIKeys)) return &c.Auth } // Validate performs basic configuration validation func (c *ServerConfig) Validate() error { // Add validation logic here if c.Server.Address == "" { c.Server.Address = ":8080" } if c.BasePath == "" { c.BasePath = "/tmp/ml-experiments" } return nil }