// forecast_endpoint.go defines the /forecast/hourly endpoint behavior. // Layer: adapters/inbound/httpapi forecast route. package httpapi import ( "context" "time" "gitea.maximumdirect.net/ejr/feedapi/endpoint" "gitea.maximumdirect.net/ejr/feedapi/render" "gitea.maximumdirect.net/ejr/feedapi/response" "gitea.maximumdirect.net/ejr/weatherapi/internal/adapters/inbound/httpapi/presenter" "gitea.maximumdirect.net/ejr/weatherfeeder/model" ) type forecastDaySlice int const ( forecastDaySliceAll forecastDaySlice = iota forecastDaySliceToday forecastDaySliceTomorrow ) var forecastNow = time.Now func forecastDefinitions(svc Service) []endpoint.Definition { return []endpoint.Definition{ forecastDefinition(svc, "/forecast/hourly", forecastDaySliceAll), forecastDefinition(svc, "/forecast/hourly/today", forecastDaySliceToday), forecastDefinition(svc, "/forecast/hourly/tomorrow", forecastDaySliceTomorrow), } } func forecastDefinition(svc Service, path string, daySlice forecastDaySlice) endpoint.Definition { return endpoint.GET( path, bindForecastPrecisionQuery, func(ctx context.Context, req precisionQueryRequest) (any, error) { run, err := svc.LatestHourlyForecast(ctx) if err != nil { return nil, err } if daySlice != forecastDaySliceAll { run = filterForecastRunByDaySlice(run, req.Timezone, daySlice) } return response.Envelope{Data: presenter.ForecastPayload(run, req.Units, req.Precision, req.Timezone)}, nil }, endpoint.WithProduces(render.FormatJSON, render.FormatXML, render.FormatText), endpoint.WithTemplate("forecast_hourly.txt.tmpl"), ) } func filterForecastRunByDaySlice(run *model.WeatherForecastRun, tz *time.Location, daySlice forecastDaySlice) *model.WeatherForecastRun { if run == nil { return nil } loc := tz if loc == nil { loc = time.UTC } now := forecastNow().In(loc) target := now if daySlice == forecastDaySliceTomorrow { target = target.AddDate(0, 0, 1) } year, month, day := target.Date() periods := make([]model.WeatherForecastPeriod, 0, len(run.Periods)) for _, period := range run.Periods { start := period.StartTime.In(loc) y, m, d := start.Date() if y == year && m == month && d == day { periods = append(periods, period) } } cloned := *run cloned.Periods = periods return &cloned }