// FILE: ./internal/sources/common/config.go package common import ( "fmt" "strings" "gitea.maximumdirect.net/ejr/feedkit/config" ) // This file centralizes small, boring config-validation patterns shared across // weatherfeeder source drivers. // // Goal: keep driver constructors (New*Source) easy to read and consistent, while // keeping driver-specific options in cfg.Params (feedkit remains domain-agnostic). // HTTPSourceConfig is the standard "HTTP-polling source" config shape used across drivers. type HTTPSourceConfig struct { Name string URL string UserAgent string } // RequireHTTPSourceConfig enforces weatherfeeder's standard HTTP source config: // // - cfg.Name must be present // - cfg.Params must be present // - params.url must be present (accepts "url" or "URL") // - params.user_agent must be present (accepts "user_agent" or "userAgent") // // We intentionally require a User-Agent for *all* sources, even when upstreams // do not strictly require one. This keeps config uniform across providers. func RequireHTTPSourceConfig(driver string, cfg config.SourceConfig) (HTTPSourceConfig, error) { if strings.TrimSpace(cfg.Name) == "" { return HTTPSourceConfig{}, fmt.Errorf("%s: name is required", driver) } if cfg.Params == nil { return HTTPSourceConfig{}, fmt.Errorf("%s %q: params are required (need params.url and params.user_agent)", driver, cfg.Name) } url, ok := cfg.ParamString("url", "URL") if !ok { return HTTPSourceConfig{}, fmt.Errorf("%s %q: params.url is required", driver, cfg.Name) } ua, ok := cfg.ParamString("user_agent", "userAgent") if !ok { return HTTPSourceConfig{}, fmt.Errorf("%s %q: params.user_agent is required", driver, cfg.Name) } return HTTPSourceConfig{ Name: cfg.Name, URL: url, UserAgent: ua, }, nil } // --- The helpers below remain useful for future drivers; they are not required // --- by the observation sources after adopting RequireHTTPSourceConfig. // RequireName ensures cfg.Name is present and non-whitespace. func RequireName(driver string, cfg config.SourceConfig) error { if strings.TrimSpace(cfg.Name) == "" { return fmt.Errorf("%s: name is required", driver) } return nil } // RequireParams ensures cfg.Params is non-nil. The "want" string should be a short // description of required keys, e.g. "need params.url and params.user_agent". func RequireParams(driver string, cfg config.SourceConfig, want string) error { if cfg.Params == nil { return fmt.Errorf("%s %q: params are required (%s)", driver, cfg.Name, want) } return nil } // RequireURL returns the configured URL for a source. // Canonical key is "url"; we also accept "URL" as a convenience. func RequireURL(driver string, cfg config.SourceConfig) (string, error) { if cfg.Params == nil { return "", fmt.Errorf("%s %q: params are required (need params.url)", driver, cfg.Name) } u, ok := cfg.ParamString("url", "URL") if !ok { return "", fmt.Errorf("%s %q: params.url is required", driver, cfg.Name) } return u, nil } // RequireUserAgent returns the configured User-Agent for a source. // Canonical key is "user_agent"; we also accept "userAgent" as a convenience. func RequireUserAgent(driver string, cfg config.SourceConfig) (string, error) { if cfg.Params == nil { return "", fmt.Errorf("%s %q: params are required (need params.user_agent)", driver, cfg.Name) } ua, ok := cfg.ParamString("user_agent", "userAgent") if !ok { return "", fmt.Errorf("%s %q: params.user_agent is required", driver, cfg.Name) } return ua, nil }