package nws import ( "context" "encoding/json" "strings" "time" "gitea.maximumdirect.net/ejr/feedkit/config" "gitea.maximumdirect.net/ejr/feedkit/event" fksources "gitea.maximumdirect.net/ejr/feedkit/sources" nwscommon "gitea.maximumdirect.net/ejr/weatherfeeder/internal/providers/nws" ) const nwsForecastAccept = "application/geo+json, application/json" type forecastSource struct { http *fksources.HTTPSource rawSchema string } type forecastMeta struct { Properties struct { GeneratedAt string `json:"generatedAt"` UpdateTime string `json:"updateTime"` Updated string `json:"updated"` } `json:"properties"` ParsedGeneratedAt time.Time `json:"-"` ParsedUpdateTime time.Time `json:"-"` } func newForecastSource(cfg config.SourceConfig, driver, rawSchema string) (*forecastSource, error) { hs, err := fksources.NewHTTPSource(driver, cfg, nwsForecastAccept) if err != nil { return nil, err } return &forecastSource{ http: hs, rawSchema: rawSchema, }, nil } func (s *forecastSource) Name() string { return s.http.Name } func (s *forecastSource) Kinds() []event.Kind { return []event.Kind{event.Kind("forecast")} } func (s *forecastSource) Poll(ctx context.Context) ([]event.Event, error) { raw, meta, changed, err := s.fetchRaw(ctx) if err != nil { return nil, err } if !changed { return nil, nil } var effectiveAt *time.Time switch { case !meta.ParsedGeneratedAt.IsZero(): t := meta.ParsedGeneratedAt.UTC() effectiveAt = &t case !meta.ParsedUpdateTime.IsZero(): t := meta.ParsedUpdateTime.UTC() effectiveAt = &t } emittedAt := time.Now().UTC() eventID := fksources.DefaultEventID("", s.http.Name, effectiveAt, emittedAt) return fksources.SingleEvent( event.Kind("forecast"), s.http.Name, s.rawSchema, eventID, emittedAt, effectiveAt, raw, ) } func (s *forecastSource) fetchRaw(ctx context.Context) (json.RawMessage, forecastMeta, bool, error) { raw, changed, err := s.http.FetchJSONIfChanged(ctx) if err != nil { return nil, forecastMeta{}, false, err } if !changed { return nil, forecastMeta{}, false, nil } var meta forecastMeta if err := json.Unmarshal(raw, &meta); err != nil { return raw, forecastMeta{}, true, nil } genStr := strings.TrimSpace(meta.Properties.GeneratedAt) if genStr != "" { if t, err := nwscommon.ParseTime(genStr); err == nil { meta.ParsedGeneratedAt = t.UTC() } } updStr := strings.TrimSpace(meta.Properties.UpdateTime) if updStr == "" { updStr = strings.TrimSpace(meta.Properties.Updated) } if updStr != "" { if t, err := nwscommon.ParseTime(updStr); err == nil { meta.ParsedUpdateTime = t.UTC() } } return raw, meta, true, nil }