package config import ( "fmt" "os" "strconv" "strings" ) type envReader struct { err error } func (reader *envReader) fail(name string, err error) { if reader.err == nil { reader.err = fmt.Errorf("%s: %w", name, err) } } func (reader *envReader) text(name, fallback string) string { value := strings.TrimSpace(os.Getenv(name)) if value == "" { return fallback } return value } func (reader *envReader) boolean(name string, fallback bool) bool { raw := reader.text(name, "") if raw == "" { return fallback } value, err := strconv.ParseBool(raw) if err != nil { reader.fail(name, err) return fallback } return value } func (reader *envReader) integer(name string, fallback int) int { raw := reader.text(name, "") if raw == "" { return fallback } value, err := strconv.Atoi(raw) if err != nil { reader.fail(name, err) return fallback } return value } func (reader *envReader) ports(name, fallback string) []uint16 { raw := reader.text(name, fallback) if raw == "*" { return nil } var ports []uint16 for _, part := range strings.Split(raw, ",") { part = strings.TrimSpace(part) if part == "" { continue } value, err := strconv.ParseUint(part, 10, 16) if err != nil || value == 0 { reader.fail(name, fmt.Errorf("invalid port %q", part)) return nil } ports = append(ports, uint16(value)) } if len(ports) == 0 { reader.fail(name, fmt.Errorf("no ports listed, use * to allow any port")) } return ports }