// FILE: ./internal/sources/common/http_source.go package common import ( "context" "encoding/json" "fmt" "net/http" "gitea.maximumdirect.net/ejr/feedkit/config" "gitea.maximumdirect.net/ejr/feedkit/transport" ) // HTTPSource is a tiny, reusable "HTTP polling spine" for weatherfeeder sources. // // It centralizes the boring parts: // - standard config shape (url + user_agent) via RequireHTTPSourceConfig // - a default http.Client with timeout // - FetchBody / headers / max-body safety limit // - consistent error wrapping (driver + source name) // // Individual drivers remain responsible for: // - decoding minimal metadata (for Event.ID / EffectiveAt) // - constructing the event envelope (kind/schema/payload) type HTTPSource struct { Driver string Name string URL string UserAgent string Accept string Client *http.Client } // NewHTTPSource builds an HTTPSource using weatherfeeder's standard HTTP source // config (params.url + params.user_agent) and a default HTTP client. func NewHTTPSource(driver string, cfg config.SourceConfig, accept string) (*HTTPSource, error) { c, err := RequireHTTPSourceConfig(driver, cfg) if err != nil { return nil, err } return &HTTPSource{ Driver: driver, Name: c.Name, URL: c.URL, UserAgent: c.UserAgent, Accept: accept, Client: transport.NewHTTPClient(transport.DefaultHTTPTimeout), }, nil } // FetchBytes fetches the URL and returns the raw response body bytes. func (s *HTTPSource) FetchBytes(ctx context.Context) ([]byte, error) { client := s.Client if client == nil { // Defensive: allow tests or callers to nil out Client; keep behavior sane. client = transport.NewHTTPClient(transport.DefaultHTTPTimeout) } b, err := transport.FetchBody(ctx, client, s.URL, s.UserAgent, s.Accept) if err != nil { return nil, fmt.Errorf("%s %q: %w", s.Driver, s.Name, err) } return b, nil } // FetchJSON fetches the URL and returns the raw body as json.RawMessage. // json.Unmarshal accepts json.RawMessage directly, so callers can decode minimal // metadata without keeping both []byte and RawMessage in their own structs. func (s *HTTPSource) FetchJSON(ctx context.Context) (json.RawMessage, error) { b, err := s.FetchBytes(ctx) if err != nil { return nil, err } return json.RawMessage(b), nil }