92 lines
2.7 KiB
Go
92 lines
2.7 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"predictor-refactored/internal/windviz"
|
|
apirest "predictor-refactored/pkg/rest"
|
|
)
|
|
|
|
// GetWindMeta implements GET /api/v1/wind/meta.
|
|
func (h *Handler) GetWindMeta(_ context.Context) (*apirest.WindMeta, error) {
|
|
field := h.mgr.Active()
|
|
if field == nil {
|
|
return nil, apiError(http.StatusServiceUnavailable, "no dataset loaded")
|
|
}
|
|
return &apirest.WindMeta{
|
|
Source: field.Source(),
|
|
Epoch: field.Epoch().UTC(),
|
|
DefaultStep: 1.0,
|
|
MinStep: 0.25,
|
|
SuggestedAltitudes: []int{0, 1000, 5000, 10000, 15000, 20000, 30000},
|
|
Bbox: apirest.Region{MinLat: -90, MaxLat: 90, MinLng: 0, MaxLng: 360},
|
|
}, nil
|
|
}
|
|
|
|
// GetWindField implements GET /api/v1/wind/field.
|
|
func (h *Handler) GetWindField(_ context.Context, params apirest.GetWindFieldParams) ([]apirest.WindComponent, error) {
|
|
field := h.mgr.Active()
|
|
if field == nil {
|
|
return nil, apiError(http.StatusServiceUnavailable, "no dataset loaded")
|
|
}
|
|
|
|
when := field.Epoch()
|
|
if t, ok := params.Time.Get(); ok {
|
|
when = t
|
|
}
|
|
req := windviz.Request{
|
|
Time: float64(when.Unix()),
|
|
Altitude: params.Altitude.Or(0),
|
|
MinLat: params.MinLat.Or(0),
|
|
MaxLat: params.MaxLat.Or(0),
|
|
MinLng: params.MinLng.Or(0),
|
|
MaxLng: params.MaxLng.Or(0),
|
|
Step: params.Step.Or(0),
|
|
}
|
|
|
|
key := fmt.Sprintf("%s|%v|%.3f|%.3f|%.3f|%.3f|%.3f|%.3f",
|
|
field.Source(), req.Time, req.Altitude, req.MinLat, req.MaxLat, req.MinLng, req.MaxLng, req.Step)
|
|
if h.cache != nil {
|
|
if cached, ok := h.cache.Get(key); ok {
|
|
return windFieldToAPI(cached), nil
|
|
}
|
|
}
|
|
|
|
out, err := windviz.Rasterize(field, req)
|
|
if err != nil {
|
|
return nil, apiError(http.StatusBadRequest, err.Error())
|
|
}
|
|
if h.cache != nil {
|
|
h.cache.Put(key, out)
|
|
}
|
|
return windFieldToAPI(out), nil
|
|
}
|
|
|
|
// windFieldToAPI maps a rasterized field to the generated component slice.
|
|
func windFieldToAPI(f windviz.Field) []apirest.WindComponent {
|
|
out := make([]apirest.WindComponent, 0, len(f))
|
|
for _, c := range f {
|
|
out = append(out, apirest.WindComponent{
|
|
Header: apirest.WindHeader{
|
|
ParameterCategory: c.Header.ParameterCategory,
|
|
ParameterNumber: c.Header.ParameterNumber,
|
|
ParameterNumberName: apirest.NewOptString(c.Header.ParameterNumberName),
|
|
ParameterUnit: apirest.NewOptString(c.Header.ParameterUnit),
|
|
Nx: c.Header.Nx,
|
|
Ny: c.Header.Ny,
|
|
Lo1: c.Header.Lo1,
|
|
La1: c.Header.La1,
|
|
Lo2: c.Header.Lo2,
|
|
La2: c.Header.La2,
|
|
Dx: c.Header.Dx,
|
|
Dy: c.Header.Dy,
|
|
RefTime: c.Header.RefTime,
|
|
ForecastTime: c.Header.ForecastTime,
|
|
},
|
|
Data: c.Data,
|
|
})
|
|
}
|
|
return out
|
|
}
|