From 5158c5d7c924acc721e183566417c11af2e027f3 Mon Sep 17 00:00:00 2001 From: "a.antonov" Date: Sat, 21 Jun 2025 21:34:22 +0300 Subject: [PATCH 1/4] feat: generated pkg/rest --- api/rest/predictor.swagger.yml | 60 +- pkg/rest/oas_cfg_gen.go | 283 ++++++ pkg/rest/oas_client_gen.go | 179 ++++ pkg/rest/oas_defaults_gen.go | 15 + pkg/rest/oas_handlers_gen.go | 195 ++++ pkg/rest/oas_json_gen.go | 1190 +++++++++++++++++++++++++ pkg/rest/oas_labeler_gen.go | 42 + pkg/rest/oas_middleware_gen.go | 10 + pkg/rest/oas_operations_gen.go | 10 + pkg/rest/oas_parameters_gen.go | 80 ++ pkg/rest/oas_request_decoders_gen.go | 97 ++ pkg/rest/oas_request_encoders_gen.go | 32 + pkg/rest/oas_response_decoders_gen.go | 107 +++ pkg/rest/oas_response_encoders_gen.go | 55 ++ pkg/rest/oas_router_gen.go | 178 ++++ pkg/rest/oas_schemas_gen.go | 767 ++++++++++++++++ pkg/rest/oas_server_gen.go | 40 + pkg/rest/oas_unimplemented_gen.go | 31 + pkg/rest/oas_uri_gen.go | 535 +++++++++++ pkg/rest/oas_validators_gen.go | 294 ++++++ 20 files changed, 4199 insertions(+), 1 deletion(-) create mode 100644 pkg/rest/oas_cfg_gen.go create mode 100644 pkg/rest/oas_client_gen.go create mode 100644 pkg/rest/oas_defaults_gen.go create mode 100644 pkg/rest/oas_handlers_gen.go create mode 100644 pkg/rest/oas_json_gen.go create mode 100644 pkg/rest/oas_labeler_gen.go create mode 100644 pkg/rest/oas_middleware_gen.go create mode 100644 pkg/rest/oas_operations_gen.go create mode 100644 pkg/rest/oas_parameters_gen.go create mode 100644 pkg/rest/oas_request_decoders_gen.go create mode 100644 pkg/rest/oas_request_encoders_gen.go create mode 100644 pkg/rest/oas_response_decoders_gen.go create mode 100644 pkg/rest/oas_response_encoders_gen.go create mode 100644 pkg/rest/oas_router_gen.go create mode 100644 pkg/rest/oas_schemas_gen.go create mode 100644 pkg/rest/oas_server_gen.go create mode 100644 pkg/rest/oas_unimplemented_gen.go create mode 100644 pkg/rest/oas_uri_gen.go create mode 100644 pkg/rest/oas_validators_gen.go diff --git a/api/rest/predictor.swagger.yml b/api/rest/predictor.swagger.yml index f6a8feb..d44f7fa 100644 --- a/api/rest/predictor.swagger.yml +++ b/api/rest/predictor.swagger.yml @@ -23,9 +23,31 @@ paths: application/json: schema: $ref: '#/components/schemas/Prediction/Parameters' + responses: + "200": + description: "Prediction response" + content: + application/json: + schema: + $ref: '#/components/schemas/Prediction/Result' + default: + description: Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" components: schemas: + Error: + type: object + required: + - message + properties: + message: + type: string + details: + type: string Prediction: Parameters: type: object @@ -68,4 +90,40 @@ components: default: json dataset: type: string - format: date-time \ No newline at end of file + format: date-time + Result: # + type: object + required: + - metadata + - prediction + properties: + metadata: + type: object + required: + - complete_datetime + - start_datetime + properties: + complete_datetime: + type: string + format: date-time + start_datetime: + type: string + format: date-time + prediction: + type: array + items: + type: object + required: + - stage + - trajectory + properties: + stage: + type: string + enum: ["ascent", "descent"] + trajectory: + type: array + items: + type: object + required: + - datetime + - latitude \ No newline at end of file diff --git a/pkg/rest/oas_cfg_gen.go b/pkg/rest/oas_cfg_gen.go new file mode 100644 index 0000000..1845c4f --- /dev/null +++ b/pkg/rest/oas_cfg_gen.go @@ -0,0 +1,283 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "net/http" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/otelogen" +) + +var ( + // Allocate option closure once. + clientSpanKind = trace.WithSpanKind(trace.SpanKindClient) + // Allocate option closure once. + serverSpanKind = trace.WithSpanKind(trace.SpanKindServer) +) + +type ( + optionFunc[C any] func(*C) + otelOptionFunc func(*otelConfig) +) + +type otelConfig struct { + TracerProvider trace.TracerProvider + Tracer trace.Tracer + MeterProvider metric.MeterProvider + Meter metric.Meter +} + +func (cfg *otelConfig) initOTEL() { + if cfg.TracerProvider == nil { + cfg.TracerProvider = otel.GetTracerProvider() + } + if cfg.MeterProvider == nil { + cfg.MeterProvider = otel.GetMeterProvider() + } + cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name, + trace.WithInstrumentationVersion(otelogen.SemVersion()), + ) + cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name, + metric.WithInstrumentationVersion(otelogen.SemVersion()), + ) +} + +// ErrorHandler is error handler. +type ErrorHandler = ogenerrors.ErrorHandler + +type serverConfig struct { + otelConfig + NotFound http.HandlerFunc + MethodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string) + ErrorHandler ErrorHandler + Prefix string + Middleware Middleware + MaxMultipartMemory int64 +} + +// ServerOption is server config option. +type ServerOption interface { + applyServer(*serverConfig) +} + +var _ ServerOption = (optionFunc[serverConfig])(nil) + +func (o optionFunc[C]) applyServer(c *C) { + o(c) +} + +var _ ServerOption = (otelOptionFunc)(nil) + +func (o otelOptionFunc) applyServer(c *serverConfig) { + o(&c.otelConfig) +} + +func newServerConfig(opts ...ServerOption) serverConfig { + cfg := serverConfig{ + NotFound: http.NotFound, + MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) { + status := http.StatusMethodNotAllowed + if r.Method == "OPTIONS" { + w.Header().Set("Access-Control-Allow-Methods", allowed) + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + status = http.StatusNoContent + } else { + w.Header().Set("Allow", allowed) + } + w.WriteHeader(status) + }, + ErrorHandler: ogenerrors.DefaultErrorHandler, + Middleware: nil, + MaxMultipartMemory: 32 << 20, // 32 MB + } + for _, opt := range opts { + opt.applyServer(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseServer struct { + cfg serverConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) { + s.cfg.NotFound(w, r) +} + +func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) { + s.cfg.MethodNotAllowed(w, r, allowed) +} + +func (cfg serverConfig) baseServer() (s baseServer, err error) { + s = baseServer{cfg: cfg} + if s.requests, err = otelogen.ServerRequestCountCounter(s.cfg.Meter); err != nil { + return s, err + } + if s.errors, err = otelogen.ServerErrorsCountCounter(s.cfg.Meter); err != nil { + return s, err + } + if s.duration, err = otelogen.ServerDurationHistogram(s.cfg.Meter); err != nil { + return s, err + } + return s, nil +} + +type clientConfig struct { + otelConfig + Client ht.Client +} + +// ClientOption is client config option. +type ClientOption interface { + applyClient(*clientConfig) +} + +var _ ClientOption = (optionFunc[clientConfig])(nil) + +func (o optionFunc[C]) applyClient(c *C) { + o(c) +} + +var _ ClientOption = (otelOptionFunc)(nil) + +func (o otelOptionFunc) applyClient(c *clientConfig) { + o(&c.otelConfig) +} + +func newClientConfig(opts ...ClientOption) clientConfig { + cfg := clientConfig{ + Client: http.DefaultClient, + } + for _, opt := range opts { + opt.applyClient(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseClient struct { + cfg clientConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (cfg clientConfig) baseClient() (c baseClient, err error) { + c = baseClient{cfg: cfg} + if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil { + return c, err + } + if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil { + return c, err + } + if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil { + return c, err + } + return c, nil +} + +// Option is config option. +type Option interface { + ServerOption + ClientOption +} + +// WithTracerProvider specifies a tracer provider to use for creating a tracer. +// +// If none is specified, the global provider is used. +func WithTracerProvider(provider trace.TracerProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.TracerProvider = provider + } + }) +} + +// WithMeterProvider specifies a meter provider to use for creating a meter. +// +// If none is specified, the otel.GetMeterProvider() is used. +func WithMeterProvider(provider metric.MeterProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.MeterProvider = provider + } + }) +} + +// WithClient specifies http client to use. +func WithClient(client ht.Client) ClientOption { + return optionFunc[clientConfig](func(cfg *clientConfig) { + if client != nil { + cfg.Client = client + } + }) +} + +// WithNotFound specifies Not Found handler to use. +func WithNotFound(notFound http.HandlerFunc) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if notFound != nil { + cfg.NotFound = notFound + } + }) +} + +// WithMethodNotAllowed specifies Method Not Allowed handler to use. +func WithMethodNotAllowed(methodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if methodNotAllowed != nil { + cfg.MethodNotAllowed = methodNotAllowed + } + }) +} + +// WithErrorHandler specifies error handler to use. +func WithErrorHandler(h ErrorHandler) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if h != nil { + cfg.ErrorHandler = h + } + }) +} + +// WithPathPrefix specifies server path prefix. +func WithPathPrefix(prefix string) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + cfg.Prefix = prefix + }) +} + +// WithMiddleware specifies middlewares to use. +func WithMiddleware(m ...Middleware) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + switch len(m) { + case 0: + cfg.Middleware = nil + case 1: + cfg.Middleware = m[0] + default: + cfg.Middleware = middleware.ChainMiddlewares(m...) + } + }) +} + +// WithMaxMultipartMemory specifies limit of memory for storing file parts. +// File parts which can't be stored in memory will be stored on disk in temporary files. +func WithMaxMultipartMemory(max int64) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if max > 0 { + cfg.MaxMultipartMemory = max + } + }) +} diff --git a/pkg/rest/oas_client_gen.go b/pkg/rest/oas_client_gen.go new file mode 100644 index 0000000..8118041 --- /dev/null +++ b/pkg/rest/oas_client_gen.go @@ -0,0 +1,179 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "context" + "net/url" + "strings" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/otelogen" + "github.com/ogen-go/ogen/uri" +) + +func trimTrailingSlashes(u *url.URL) { + u.Path = strings.TrimRight(u.Path, "/") + u.RawPath = strings.TrimRight(u.RawPath, "/") +} + +// Invoker invokes operations described by OpenAPI v3 specification. +type Invoker interface { + // PerformPrediction invokes performPrediction operation. + // + // Perform preidction. + // + // POST /api/v1/prediction + PerformPrediction(ctx context.Context, request OptParameters, params PerformPredictionParams) (*Result, error) +} + +// Client implements OAS client. +type Client struct { + serverURL *url.URL + baseClient +} +type errorHandler interface { + NewError(ctx context.Context, err error) *ErrorStatusCode +} + +var _ Handler = struct { + errorHandler + *Client +}{} + +// NewClient initializes new Client defined by OAS. +func NewClient(serverURL string, opts ...ClientOption) (*Client, error) { + u, err := url.Parse(serverURL) + if err != nil { + return nil, err + } + trimTrailingSlashes(u) + + c, err := newClientConfig(opts...).baseClient() + if err != nil { + return nil, err + } + return &Client{ + serverURL: u, + baseClient: c, + }, nil +} + +type serverURLKey struct{} + +// WithServerURL sets context key to override server URL. +func WithServerURL(ctx context.Context, u *url.URL) context.Context { + return context.WithValue(ctx, serverURLKey{}, u) +} + +func (c *Client) requestURL(ctx context.Context) *url.URL { + u, ok := ctx.Value(serverURLKey{}).(*url.URL) + if !ok { + return c.serverURL + } + return u +} + +// PerformPrediction invokes performPrediction operation. +// +// Perform preidction. +// +// POST /api/v1/prediction +func (c *Client) PerformPrediction(ctx context.Context, request OptParameters, params PerformPredictionParams) (*Result, error) { + res, err := c.sendPerformPrediction(ctx, request, params) + return res, err +} + +func (c *Client) sendPerformPrediction(ctx context.Context, request OptParameters, params PerformPredictionParams) (res *Result, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("performPrediction"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/api/v1/prediction"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, PerformPredictionOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/api/v1/prediction" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "parameters" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "parameters", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + if val, ok := params.Parameters.Get(); ok { + return val.EncodeURI(e) + } + return nil + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodePerformPredictionRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodePerformPredictionResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} diff --git a/pkg/rest/oas_defaults_gen.go b/pkg/rest/oas_defaults_gen.go new file mode 100644 index 0000000..2f09154 --- /dev/null +++ b/pkg/rest/oas_defaults_gen.go @@ -0,0 +1,15 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +// setDefaults set default value of fields. +func (s *Parameters) setDefaults() { + { + val := bool(false) + s.Interpolate.SetTo(val) + } + { + val := ParametersFormat("json") + s.Format.SetTo(val) + } +} diff --git a/pkg/rest/oas_handlers_gen.go b/pkg/rest/oas_handlers_gen.go new file mode 100644 index 0000000..638947a --- /dev/null +++ b/pkg/rest/oas_handlers_gen.go @@ -0,0 +1,195 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "context" + "net/http" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/otelogen" +) + +type codeRecorder struct { + http.ResponseWriter + status int +} + +func (c *codeRecorder) WriteHeader(status int) { + c.status = status + c.ResponseWriter.WriteHeader(status) +} + +// handlePerformPredictionRequest handles performPrediction operation. +// +// Perform preidction. +// +// POST /api/v1/prediction +func (s *Server) handlePerformPredictionRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("performPrediction"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/api/v1/prediction"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), PerformPredictionOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code >= 100 && code < 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: PerformPredictionOperation, + ID: "performPrediction", + } + ) + params, err := decodePerformPredictionParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + request, close, err := s.decodePerformPredictionRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response *Result + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: PerformPredictionOperation, + OperationSummary: "Perform preidction", + OperationID: "performPrediction", + Body: request, + Params: middleware.Parameters{ + { + Name: "parameters", + In: "query", + }: params.Parameters, + }, + Raw: r, + } + + type ( + Request = OptParameters + Params = PerformPredictionParams + Response = *Result + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackPerformPredictionParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.PerformPrediction(ctx, request, params) + return response, err + }, + ) + } else { + response, err = s.h.PerformPrediction(ctx, request, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodePerformPredictionResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} diff --git a/pkg/rest/oas_json_gen.go b/pkg/rest/oas_json_gen.go new file mode 100644 index 0000000..9542a4e --- /dev/null +++ b/pkg/rest/oas_json_gen.go @@ -0,0 +1,1190 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "math/bits" + "strconv" + "time" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/json" + "github.com/ogen-go/ogen/validate" +) + +// Encode implements json.Marshaler. +func (s *Error) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Error) encodeFields(e *jx.Encoder) { + { + e.FieldStart("message") + e.Str(s.Message) + } + { + if s.Details.Set { + e.FieldStart("details") + s.Details.Encode(e) + } + } +} + +var jsonFieldsNameOfError = [2]string{ + 0: "message", + 1: "details", +} + +// Decode decodes Error from json. +func (s *Error) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Error to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "message": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Str() + s.Message = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"message\"") + } + case "details": + if err := func() error { + s.Details.Reset() + if err := s.Details.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"details\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Error") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000001, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfError) { + name = jsonFieldsNameOfError[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Error) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Error) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes bool as json. +func (o OptBool) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Bool(bool(o.Value)) +} + +// Decode decodes bool from json. +func (o *OptBool) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptBool to nil") + } + o.Set = true + v, err := d.Bool() + if err != nil { + return err + } + o.Value = bool(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptBool) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptBool) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes time.Time as json. +func (o OptDateTime) Encode(e *jx.Encoder, format func(*jx.Encoder, time.Time)) { + if !o.Set { + return + } + format(e, o.Value) +} + +// Decode decodes time.Time from json. +func (o *OptDateTime) Decode(d *jx.Decoder, format func(*jx.Decoder) (time.Time, error)) error { + if o == nil { + return errors.New("invalid: unable to decode OptDateTime to nil") + } + o.Set = true + v, err := format(d) + if err != nil { + return err + } + o.Value = v + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptDateTime) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e, json.EncodeDateTime) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptDateTime) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d, json.DecodeDateTime) +} + +// Encode encodes float64 as json. +func (o OptFloat64) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Float64(float64(o.Value)) +} + +// Decode decodes float64 from json. +func (o *OptFloat64) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptFloat64 to nil") + } + o.Set = true + v, err := d.Float64() + if err != nil { + return err + } + o.Value = float64(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptFloat64) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptFloat64) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes Parameters as json. +func (o OptParameters) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes Parameters from json. +func (o *OptParameters) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptParameters to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptParameters) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptParameters) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ParametersFormat as json. +func (o OptParametersFormat) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes ParametersFormat from json. +func (o *OptParametersFormat) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptParametersFormat to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptParametersFormat) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptParametersFormat) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ParametersProfile as json. +func (o OptParametersProfile) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes ParametersProfile from json. +func (o *OptParametersProfile) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptParametersProfile to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptParametersProfile) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptParametersProfile) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes string as json. +func (o OptString) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes string from json. +func (o *OptString) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptString to nil") + } + o.Set = true + v, err := d.Str() + if err != nil { + return err + } + o.Value = string(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptString) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptString) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Parameters) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Parameters) encodeFields(e *jx.Encoder) { + { + if s.LaunchLatitude.Set { + e.FieldStart("launch_latitude") + s.LaunchLatitude.Encode(e) + } + } + { + if s.LaunchLongitude.Set { + e.FieldStart("launch_longitude") + s.LaunchLongitude.Encode(e) + } + } + { + if s.LaunchDatetime.Set { + e.FieldStart("launch_datetime") + s.LaunchDatetime.Encode(e, json.EncodeDateTime) + } + } + { + if s.LaunchAltitude.Set { + e.FieldStart("launch_altitude") + s.LaunchAltitude.Encode(e) + } + } + { + if s.Profile.Set { + e.FieldStart("profile") + s.Profile.Encode(e) + } + } + { + if s.AscentRate.Set { + e.FieldStart("ascent_rate") + s.AscentRate.Encode(e) + } + } + { + if s.BurstAltitude.Set { + e.FieldStart("burst_altitude") + s.BurstAltitude.Encode(e) + } + } + { + if s.DescentRate.Set { + e.FieldStart("descent_rate") + s.DescentRate.Encode(e) + } + } + { + if s.FloatAltitude.Set { + e.FieldStart("float_altitude") + s.FloatAltitude.Encode(e) + } + } + { + if s.StopDatetime.Set { + e.FieldStart("stop_datetime") + s.StopDatetime.Encode(e, json.EncodeDateTime) + } + } + { + if s.AscentCurve.Set { + e.FieldStart("ascent_curve") + s.AscentCurve.Encode(e) + } + } + { + if s.DescentCurve.Set { + e.FieldStart("descent_curve") + s.DescentCurve.Encode(e) + } + } + { + if s.Interpolate.Set { + e.FieldStart("interpolate") + s.Interpolate.Encode(e) + } + } + { + if s.Format.Set { + e.FieldStart("format") + s.Format.Encode(e) + } + } + { + if s.Dataset.Set { + e.FieldStart("dataset") + s.Dataset.Encode(e, json.EncodeDateTime) + } + } +} + +var jsonFieldsNameOfParameters = [15]string{ + 0: "launch_latitude", + 1: "launch_longitude", + 2: "launch_datetime", + 3: "launch_altitude", + 4: "profile", + 5: "ascent_rate", + 6: "burst_altitude", + 7: "descent_rate", + 8: "float_altitude", + 9: "stop_datetime", + 10: "ascent_curve", + 11: "descent_curve", + 12: "interpolate", + 13: "format", + 14: "dataset", +} + +// Decode decodes Parameters from json. +func (s *Parameters) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Parameters to nil") + } + s.setDefaults() + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "launch_latitude": + if err := func() error { + s.LaunchLatitude.Reset() + if err := s.LaunchLatitude.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_latitude\"") + } + case "launch_longitude": + if err := func() error { + s.LaunchLongitude.Reset() + if err := s.LaunchLongitude.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_longitude\"") + } + case "launch_datetime": + if err := func() error { + s.LaunchDatetime.Reset() + if err := s.LaunchDatetime.Decode(d, json.DecodeDateTime); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_datetime\"") + } + case "launch_altitude": + if err := func() error { + s.LaunchAltitude.Reset() + if err := s.LaunchAltitude.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_altitude\"") + } + case "profile": + if err := func() error { + s.Profile.Reset() + if err := s.Profile.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"profile\"") + } + case "ascent_rate": + if err := func() error { + s.AscentRate.Reset() + if err := s.AscentRate.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ascent_rate\"") + } + case "burst_altitude": + if err := func() error { + s.BurstAltitude.Reset() + if err := s.BurstAltitude.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"burst_altitude\"") + } + case "descent_rate": + if err := func() error { + s.DescentRate.Reset() + if err := s.DescentRate.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"descent_rate\"") + } + case "float_altitude": + if err := func() error { + s.FloatAltitude.Reset() + if err := s.FloatAltitude.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"float_altitude\"") + } + case "stop_datetime": + if err := func() error { + s.StopDatetime.Reset() + if err := s.StopDatetime.Decode(d, json.DecodeDateTime); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"stop_datetime\"") + } + case "ascent_curve": + if err := func() error { + s.AscentCurve.Reset() + if err := s.AscentCurve.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ascent_curve\"") + } + case "descent_curve": + if err := func() error { + s.DescentCurve.Reset() + if err := s.DescentCurve.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"descent_curve\"") + } + case "interpolate": + if err := func() error { + s.Interpolate.Reset() + if err := s.Interpolate.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"interpolate\"") + } + case "format": + if err := func() error { + s.Format.Reset() + if err := s.Format.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"format\"") + } + case "dataset": + if err := func() error { + s.Dataset.Reset() + if err := s.Dataset.Decode(d, json.DecodeDateTime); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"dataset\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Parameters") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Parameters) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Parameters) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ParametersFormat as json. +func (s ParametersFormat) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes ParametersFormat from json. +func (s *ParametersFormat) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ParametersFormat to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch ParametersFormat(v) { + case ParametersFormatJSON: + *s = ParametersFormatJSON + default: + *s = ParametersFormat(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s ParametersFormat) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ParametersFormat) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ParametersProfile as json. +func (s ParametersProfile) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes ParametersProfile from json. +func (s *ParametersProfile) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ParametersProfile to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch ParametersProfile(v) { + case ParametersProfileStandardProfile: + *s = ParametersProfileStandardProfile + case ParametersProfileFloatProfile: + *s = ParametersProfileFloatProfile + case ParametersProfileReverseProfile: + *s = ParametersProfileReverseProfile + case ParametersProfileCustomProfile: + *s = ParametersProfileCustomProfile + default: + *s = ParametersProfile(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s ParametersProfile) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ParametersProfile) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *Result) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *Result) encodeFields(e *jx.Encoder) { + { + e.FieldStart("metadata") + s.Metadata.Encode(e) + } + { + e.FieldStart("prediction") + e.ArrStart() + for _, elem := range s.Prediction { + elem.Encode(e) + } + e.ArrEnd() + } +} + +var jsonFieldsNameOfResult = [2]string{ + 0: "metadata", + 1: "prediction", +} + +// Decode decodes Result from json. +func (s *Result) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Result to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "metadata": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + if err := s.Metadata.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"metadata\"") + } + case "prediction": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + s.Prediction = make([]ResultPredictionItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem ResultPredictionItem + if err := elem.Decode(d); err != nil { + return err + } + s.Prediction = append(s.Prediction, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"prediction\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Result") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfResult) { + name = jsonFieldsNameOfResult[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *Result) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *Result) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *ResultMetadata) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ResultMetadata) encodeFields(e *jx.Encoder) { + { + e.FieldStart("complete_datetime") + json.EncodeDateTime(e, s.CompleteDatetime) + } + { + e.FieldStart("start_datetime") + json.EncodeDateTime(e, s.StartDatetime) + } +} + +var jsonFieldsNameOfResultMetadata = [2]string{ + 0: "complete_datetime", + 1: "start_datetime", +} + +// Decode decodes ResultMetadata from json. +func (s *ResultMetadata) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ResultMetadata to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "complete_datetime": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := json.DecodeDateTime(d) + s.CompleteDatetime = v + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"complete_datetime\"") + } + case "start_datetime": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + v, err := json.DecodeDateTime(d) + s.StartDatetime = v + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"start_datetime\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ResultMetadata") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfResultMetadata) { + name = jsonFieldsNameOfResultMetadata[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *ResultMetadata) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ResultMetadata) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *ResultPredictionItem) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ResultPredictionItem) encodeFields(e *jx.Encoder) { + { + e.FieldStart("stage") + s.Stage.Encode(e) + } + { + e.FieldStart("trajectory") + e.ArrStart() + for _, elem := range s.Trajectory { + elem.Encode(e) + } + e.ArrEnd() + } +} + +var jsonFieldsNameOfResultPredictionItem = [2]string{ + 0: "stage", + 1: "trajectory", +} + +// Decode decodes ResultPredictionItem from json. +func (s *ResultPredictionItem) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ResultPredictionItem to nil") + } + var requiredBitSet [1]uint8 + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "stage": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + if err := s.Stage.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"stage\"") + } + case "trajectory": + requiredBitSet[0] |= 1 << 1 + if err := func() error { + s.Trajectory = make([]ResultPredictionItemTrajectoryItem, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem ResultPredictionItemTrajectoryItem + if err := elem.Decode(d); err != nil { + return err + } + s.Trajectory = append(s.Trajectory, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"trajectory\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ResultPredictionItem") + } + // Validate required fields. + var failures []validate.FieldError + for i, mask := range [1]uint8{ + 0b00000011, + } { + if result := (requiredBitSet[i] & mask) ^ mask; result != 0 { + // Mask only required fields and check equality to mask using XOR. + // + // If XOR result is not zero, result is not equal to expected, so some fields are missed. + // Bits of fields which would be set are actually bits of missed fields. + missed := bits.OnesCount8(result) + for bitN := 0; bitN < missed; bitN++ { + bitIdx := bits.TrailingZeros8(result) + fieldIdx := i*8 + bitIdx + var name string + if fieldIdx < len(jsonFieldsNameOfResultPredictionItem) { + name = jsonFieldsNameOfResultPredictionItem[fieldIdx] + } else { + name = strconv.Itoa(fieldIdx) + } + failures = append(failures, validate.FieldError{ + Name: name, + Error: validate.ErrFieldRequired, + }) + // Reset bit. + result &^= 1 << bitIdx + } + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *ResultPredictionItem) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ResultPredictionItem) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ResultPredictionItemStage as json. +func (s ResultPredictionItemStage) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes ResultPredictionItemStage from json. +func (s *ResultPredictionItemStage) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ResultPredictionItemStage to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch ResultPredictionItemStage(v) { + case ResultPredictionItemStageAscent: + *s = ResultPredictionItemStageAscent + case ResultPredictionItemStageDescent: + *s = ResultPredictionItemStageDescent + default: + *s = ResultPredictionItemStage(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s ResultPredictionItemStage) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ResultPredictionItemStage) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *ResultPredictionItemTrajectoryItem) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ResultPredictionItemTrajectoryItem) encodeFields(e *jx.Encoder) { +} + +var jsonFieldsNameOfResultPredictionItemTrajectoryItem = [0]string{} + +// Decode decodes ResultPredictionItemTrajectoryItem from json. +func (s *ResultPredictionItemTrajectoryItem) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ResultPredictionItemTrajectoryItem to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + default: + return d.Skip() + } + }); err != nil { + return errors.Wrap(err, "decode ResultPredictionItemTrajectoryItem") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *ResultPredictionItemTrajectoryItem) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ResultPredictionItemTrajectoryItem) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} diff --git a/pkg/rest/oas_labeler_gen.go b/pkg/rest/oas_labeler_gen.go new file mode 100644 index 0000000..47bce6a --- /dev/null +++ b/pkg/rest/oas_labeler_gen.go @@ -0,0 +1,42 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" +) + +// Labeler is used to allow adding custom attributes to the server request metrics. +type Labeler struct { + attrs []attribute.KeyValue +} + +// Add attributes to the Labeler. +func (l *Labeler) Add(attrs ...attribute.KeyValue) { + l.attrs = append(l.attrs, attrs...) +} + +// AttributeSet returns the attributes added to the Labeler as an attribute.Set. +func (l *Labeler) AttributeSet() attribute.Set { + return attribute.NewSet(l.attrs...) +} + +type labelerContextKey struct{} + +// LabelerFromContext retrieves the Labeler from the provided context, if present. +// +// If no Labeler was found in the provided context a new, empty Labeler is returned and the second +// return value is false. In this case it is safe to use the Labeler but any attributes added to +// it will not be used. +func LabelerFromContext(ctx context.Context) (*Labeler, bool) { + if l, ok := ctx.Value(labelerContextKey{}).(*Labeler); ok { + return l, true + } + return &Labeler{}, false +} + +func contextWithLabeler(ctx context.Context, l *Labeler) context.Context { + return context.WithValue(ctx, labelerContextKey{}, l) +} diff --git a/pkg/rest/oas_middleware_gen.go b/pkg/rest/oas_middleware_gen.go new file mode 100644 index 0000000..9d62f34 --- /dev/null +++ b/pkg/rest/oas_middleware_gen.go @@ -0,0 +1,10 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "github.com/ogen-go/ogen/middleware" +) + +// Middleware is middleware type. +type Middleware = middleware.Middleware diff --git a/pkg/rest/oas_operations_gen.go b/pkg/rest/oas_operations_gen.go new file mode 100644 index 0000000..ea78f42 --- /dev/null +++ b/pkg/rest/oas_operations_gen.go @@ -0,0 +1,10 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +// OperationName is the ogen operation name +type OperationName = string + +const ( + PerformPredictionOperation OperationName = "PerformPrediction" +) diff --git a/pkg/rest/oas_parameters_gen.go b/pkg/rest/oas_parameters_gen.go new file mode 100644 index 0000000..afefaf8 --- /dev/null +++ b/pkg/rest/oas_parameters_gen.go @@ -0,0 +1,80 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "net/http" + + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/uri" +) + +// PerformPredictionParams is parameters of performPrediction operation. +type PerformPredictionParams struct { + Parameters OptParameters +} + +func unpackPerformPredictionParams(packed middleware.Parameters) (params PerformPredictionParams) { + { + key := middleware.ParameterKey{ + Name: "parameters", + In: "query", + } + if v, ok := packed[key]; ok { + params.Parameters = v.(OptParameters) + } + } + return params +} + +func decodePerformPredictionParams(args [0]string, argsEscaped bool, r *http.Request) (params PerformPredictionParams, _ error) { + q := uri.NewQueryDecoder(r.URL.Query()) + // Decode query: parameters. + if err := func() error { + cfg := uri.QueryParameterDecodingConfig{ + Name: "parameters", + Style: uri.QueryStyleForm, + Explode: true, + Fields: []uri.QueryParameterObjectField{{Name: "launch_latitude", Required: false}, {Name: "launch_longitude", Required: false}, {Name: "launch_datetime", Required: false}, {Name: "launch_altitude", Required: false}, {Name: "profile", Required: false}, {Name: "ascent_rate", Required: false}, {Name: "burst_altitude", Required: false}, {Name: "descent_rate", Required: false}, {Name: "float_altitude", Required: false}, {Name: "stop_datetime", Required: false}, {Name: "ascent_curve", Required: false}, {Name: "descent_curve", Required: false}, {Name: "interpolate", Required: false}, {Name: "format", Required: false}, {Name: "dataset", Required: false}}, + } + + if err := q.HasParam(cfg); err == nil { + if err := q.DecodeParam(cfg, func(d uri.Decoder) error { + var paramsDotParametersVal Parameters + if err := func() error { + return paramsDotParametersVal.DecodeURI(d) + }(); err != nil { + return err + } + params.Parameters.SetTo(paramsDotParametersVal) + return nil + }); err != nil { + return err + } + if err := func() error { + if value, ok := params.Parameters.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "parameters", + In: "query", + Err: err, + } + } + return params, nil +} diff --git a/pkg/rest/oas_request_decoders_gen.go b/pkg/rest/oas_request_decoders_gen.go new file mode 100644 index 0000000..0f3e00d --- /dev/null +++ b/pkg/rest/oas_request_decoders_gen.go @@ -0,0 +1,97 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func (s *Server) decodePerformPredictionRequest(r *http.Request) ( + req OptParameters, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = errors.Join(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = errors.Join(rerr, close()) + } + }() + if _, ok := r.Header["Content-Type"]; !ok && r.ContentLength == 0 { + return req, close, nil + } + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, nil + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, nil + } + + d := jx.DecodeBytes(buf) + + var request OptParameters + if err := func() error { + request.Reset() + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + if err := func() error { + if value, ok := request.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + return req, close, errors.Wrap(err, "validate") + } + return request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} diff --git a/pkg/rest/oas_request_encoders_gen.go b/pkg/rest/oas_request_encoders_gen.go new file mode 100644 index 0000000..8b30faa --- /dev/null +++ b/pkg/rest/oas_request_encoders_gen.go @@ -0,0 +1,32 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "bytes" + "net/http" + + "github.com/go-faster/jx" + + ht "github.com/ogen-go/ogen/http" +) + +func encodePerformPredictionRequest( + req OptParameters, + r *http.Request, +) error { + const contentType = "application/json" + if !req.Set { + // Keep request with empty body if value is not set. + return nil + } + e := new(jx.Encoder) + { + if req.Set { + req.Encode(e) + } + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} diff --git a/pkg/rest/oas_response_decoders_gen.go b/pkg/rest/oas_response_decoders_gen.go new file mode 100644 index 0000000..22a6d75 --- /dev/null +++ b/pkg/rest/oas_response_decoders_gen.go @@ -0,0 +1,107 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func decodePerformPredictionResponse(resp *http.Response) (res *Result, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Result + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} diff --git a/pkg/rest/oas_response_encoders_gen.go b/pkg/rest/oas_response_encoders_gen.go new file mode 100644 index 0000000..456cb76 --- /dev/null +++ b/pkg/rest/oas_response_encoders_gen.go @@ -0,0 +1,55 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" +) + +func encodePerformPredictionResponse(response *Result, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeErrorResponse(response *ErrorStatusCode, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + code := response.StatusCode + if code == 0 { + // Set default status code. + code = http.StatusOK + } + w.WriteHeader(code) + if st := http.StatusText(code); code >= http.StatusBadRequest { + span.SetStatus(codes.Error, st) + } else { + span.SetStatus(codes.Ok, st) + } + + e := new(jx.Encoder) + response.Response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + if code >= http.StatusInternalServerError { + return errors.Wrapf(ht.ErrInternalServerErrorResponse, "code: %d, message: %s", code, http.StatusText(code)) + } + return nil + +} diff --git a/pkg/rest/oas_router_gen.go b/pkg/rest/oas_router_gen.go new file mode 100644 index 0000000..3ce0e08 --- /dev/null +++ b/pkg/rest/oas_router_gen.go @@ -0,0 +1,178 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "net/http" + "net/url" + "strings" + + "github.com/ogen-go/ogen/uri" +) + +func (s *Server) cutPrefix(path string) (string, bool) { + prefix := s.cfg.Prefix + if prefix == "" { + return path, true + } + if !strings.HasPrefix(path, prefix) { + // Prefix doesn't match. + return "", false + } + // Cut prefix from the path. + return strings.TrimPrefix(path, prefix), true +} + +// ServeHTTP serves http request as defined by OpenAPI v3 specification, +// calling handler that matches the path or returning not found error. +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + elem := r.URL.Path + elemIsEscaped := false + if rawPath := r.URL.RawPath; rawPath != "" { + if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok { + elem = normalized + elemIsEscaped = strings.ContainsRune(elem, '%') + } + } + + elem, ok := s.cutPrefix(elem) + if !ok || len(elem) == 0 { + s.notFound(w, r) + return + } + + // Static code generated router with unwrapped path search. + switch { + default: + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/api/v1/prediction" + + if l := len("/api/v1/prediction"); len(elem) >= l && elem[0:l] == "/api/v1/prediction" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handlePerformPredictionRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + } + } + s.notFound(w, r) +} + +// Route is route object. +type Route struct { + name string + summary string + operationID string + pathPattern string + count int + args [0]string +} + +// Name returns ogen operation name. +// +// It is guaranteed to be unique and not empty. +func (r Route) Name() string { + return r.name +} + +// Summary returns OpenAPI summary. +func (r Route) Summary() string { + return r.summary +} + +// OperationID returns OpenAPI operationId. +func (r Route) OperationID() string { + return r.operationID +} + +// PathPattern returns OpenAPI path. +func (r Route) PathPattern() string { + return r.pathPattern +} + +// Args returns parsed arguments. +func (r Route) Args() []string { + return r.args[:r.count] +} + +// FindRoute finds Route for given method and path. +// +// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead. +func (s *Server) FindRoute(method, path string) (Route, bool) { + return s.FindPath(method, &url.URL{Path: path}) +} + +// FindPath finds Route for given method and URL. +func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { + var ( + elem = u.Path + args = r.args + ) + if rawPath := u.RawPath; rawPath != "" { + if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok { + elem = normalized + } + defer func() { + for i, arg := range r.args[:r.count] { + if unescaped, err := url.PathUnescape(arg); err == nil { + r.args[i] = unescaped + } + } + }() + } + + elem, ok := s.cutPrefix(elem) + if !ok { + return r, false + } + + // Static code generated router with unwrapped path search. + switch { + default: + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/api/v1/prediction" + + if l := len("/api/v1/prediction"); len(elem) >= l && elem[0:l] == "/api/v1/prediction" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = PerformPredictionOperation + r.summary = "Perform preidction" + r.operationID = "performPrediction" + r.pathPattern = "/api/v1/prediction" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + + } + } + return r, false +} diff --git a/pkg/rest/oas_schemas_gen.go b/pkg/rest/oas_schemas_gen.go new file mode 100644 index 0000000..5aa7de5 --- /dev/null +++ b/pkg/rest/oas_schemas_gen.go @@ -0,0 +1,767 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "fmt" + "time" + + "github.com/go-faster/errors" +) + +func (s *ErrorStatusCode) Error() string { + return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) +} + +// Ref: #/components/schemas/Error +type Error struct { + Message string `json:"message"` + Details OptString `json:"details"` +} + +// GetMessage returns the value of Message. +func (s *Error) GetMessage() string { + return s.Message +} + +// GetDetails returns the value of Details. +func (s *Error) GetDetails() OptString { + return s.Details +} + +// SetMessage sets the value of Message. +func (s *Error) SetMessage(val string) { + s.Message = val +} + +// SetDetails sets the value of Details. +func (s *Error) SetDetails(val OptString) { + s.Details = val +} + +// ErrorStatusCode wraps Error with StatusCode. +type ErrorStatusCode struct { + StatusCode int + Response Error +} + +// GetStatusCode returns the value of StatusCode. +func (s *ErrorStatusCode) GetStatusCode() int { + return s.StatusCode +} + +// GetResponse returns the value of Response. +func (s *ErrorStatusCode) GetResponse() Error { + return s.Response +} + +// SetStatusCode sets the value of StatusCode. +func (s *ErrorStatusCode) SetStatusCode(val int) { + s.StatusCode = val +} + +// SetResponse sets the value of Response. +func (s *ErrorStatusCode) SetResponse(val Error) { + s.Response = val +} + +// NewOptBool returns new OptBool with value set to v. +func NewOptBool(v bool) OptBool { + return OptBool{ + Value: v, + Set: true, + } +} + +// OptBool is optional bool. +type OptBool struct { + Value bool + Set bool +} + +// IsSet returns true if OptBool was set. +func (o OptBool) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBool) Reset() { + var v bool + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBool) SetTo(v bool) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBool) Get() (v bool, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBool) Or(d bool) bool { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptDateTime returns new OptDateTime with value set to v. +func NewOptDateTime(v time.Time) OptDateTime { + return OptDateTime{ + Value: v, + Set: true, + } +} + +// OptDateTime is optional time.Time. +type OptDateTime struct { + Value time.Time + Set bool +} + +// IsSet returns true if OptDateTime was set. +func (o OptDateTime) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptDateTime) Reset() { + var v time.Time + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptDateTime) SetTo(v time.Time) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptDateTime) Get() (v time.Time, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptDateTime) Or(d time.Time) time.Time { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptFloat64 returns new OptFloat64 with value set to v. +func NewOptFloat64(v float64) OptFloat64 { + return OptFloat64{ + Value: v, + Set: true, + } +} + +// OptFloat64 is optional float64. +type OptFloat64 struct { + Value float64 + Set bool +} + +// IsSet returns true if OptFloat64 was set. +func (o OptFloat64) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptFloat64) Reset() { + var v float64 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptFloat64) SetTo(v float64) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptFloat64) Get() (v float64, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptFloat64) Or(d float64) float64 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptParameters returns new OptParameters with value set to v. +func NewOptParameters(v Parameters) OptParameters { + return OptParameters{ + Value: v, + Set: true, + } +} + +// OptParameters is optional Parameters. +type OptParameters struct { + Value Parameters + Set bool +} + +// IsSet returns true if OptParameters was set. +func (o OptParameters) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptParameters) Reset() { + var v Parameters + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptParameters) SetTo(v Parameters) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptParameters) Get() (v Parameters, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptParameters) Or(d Parameters) Parameters { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptParametersFormat returns new OptParametersFormat with value set to v. +func NewOptParametersFormat(v ParametersFormat) OptParametersFormat { + return OptParametersFormat{ + Value: v, + Set: true, + } +} + +// OptParametersFormat is optional ParametersFormat. +type OptParametersFormat struct { + Value ParametersFormat + Set bool +} + +// IsSet returns true if OptParametersFormat was set. +func (o OptParametersFormat) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptParametersFormat) Reset() { + var v ParametersFormat + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptParametersFormat) SetTo(v ParametersFormat) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptParametersFormat) Get() (v ParametersFormat, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptParametersFormat) Or(d ParametersFormat) ParametersFormat { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptParametersProfile returns new OptParametersProfile with value set to v. +func NewOptParametersProfile(v ParametersProfile) OptParametersProfile { + return OptParametersProfile{ + Value: v, + Set: true, + } +} + +// OptParametersProfile is optional ParametersProfile. +type OptParametersProfile struct { + Value ParametersProfile + Set bool +} + +// IsSet returns true if OptParametersProfile was set. +func (o OptParametersProfile) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptParametersProfile) Reset() { + var v ParametersProfile + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptParametersProfile) SetTo(v ParametersProfile) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptParametersProfile) Get() (v ParametersProfile, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptParametersProfile) Or(d ParametersProfile) ParametersProfile { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptString returns new OptString with value set to v. +func NewOptString(v string) OptString { + return OptString{ + Value: v, + Set: true, + } +} + +// OptString is optional string. +type OptString struct { + Value string + Set bool +} + +// IsSet returns true if OptString was set. +func (o OptString) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptString) Reset() { + var v string + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptString) SetTo(v string) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptString) Get() (v string, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptString) Or(d string) string { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// Ref: #/components/schemas/Prediction/Parameters +type Parameters struct { + LaunchLatitude OptFloat64 `json:"launch_latitude"` + LaunchLongitude OptFloat64 `json:"launch_longitude"` + LaunchDatetime OptDateTime `json:"launch_datetime"` + LaunchAltitude OptFloat64 `json:"launch_altitude"` + Profile OptParametersProfile `json:"profile"` + AscentRate OptFloat64 `json:"ascent_rate"` + BurstAltitude OptFloat64 `json:"burst_altitude"` + DescentRate OptFloat64 `json:"descent_rate"` + FloatAltitude OptFloat64 `json:"float_altitude"` + StopDatetime OptDateTime `json:"stop_datetime"` + // Base64 encoded ascent curve. + AscentCurve OptString `json:"ascent_curve"` + // Base64 encoded descent curve. + DescentCurve OptString `json:"descent_curve"` + Interpolate OptBool `json:"interpolate"` + Format OptParametersFormat `json:"format"` + Dataset OptDateTime `json:"dataset"` +} + +// GetLaunchLatitude returns the value of LaunchLatitude. +func (s *Parameters) GetLaunchLatitude() OptFloat64 { + return s.LaunchLatitude +} + +// GetLaunchLongitude returns the value of LaunchLongitude. +func (s *Parameters) GetLaunchLongitude() OptFloat64 { + return s.LaunchLongitude +} + +// GetLaunchDatetime returns the value of LaunchDatetime. +func (s *Parameters) GetLaunchDatetime() OptDateTime { + return s.LaunchDatetime +} + +// GetLaunchAltitude returns the value of LaunchAltitude. +func (s *Parameters) GetLaunchAltitude() OptFloat64 { + return s.LaunchAltitude +} + +// GetProfile returns the value of Profile. +func (s *Parameters) GetProfile() OptParametersProfile { + return s.Profile +} + +// GetAscentRate returns the value of AscentRate. +func (s *Parameters) GetAscentRate() OptFloat64 { + return s.AscentRate +} + +// GetBurstAltitude returns the value of BurstAltitude. +func (s *Parameters) GetBurstAltitude() OptFloat64 { + return s.BurstAltitude +} + +// GetDescentRate returns the value of DescentRate. +func (s *Parameters) GetDescentRate() OptFloat64 { + return s.DescentRate +} + +// GetFloatAltitude returns the value of FloatAltitude. +func (s *Parameters) GetFloatAltitude() OptFloat64 { + return s.FloatAltitude +} + +// GetStopDatetime returns the value of StopDatetime. +func (s *Parameters) GetStopDatetime() OptDateTime { + return s.StopDatetime +} + +// GetAscentCurve returns the value of AscentCurve. +func (s *Parameters) GetAscentCurve() OptString { + return s.AscentCurve +} + +// GetDescentCurve returns the value of DescentCurve. +func (s *Parameters) GetDescentCurve() OptString { + return s.DescentCurve +} + +// GetInterpolate returns the value of Interpolate. +func (s *Parameters) GetInterpolate() OptBool { + return s.Interpolate +} + +// GetFormat returns the value of Format. +func (s *Parameters) GetFormat() OptParametersFormat { + return s.Format +} + +// GetDataset returns the value of Dataset. +func (s *Parameters) GetDataset() OptDateTime { + return s.Dataset +} + +// SetLaunchLatitude sets the value of LaunchLatitude. +func (s *Parameters) SetLaunchLatitude(val OptFloat64) { + s.LaunchLatitude = val +} + +// SetLaunchLongitude sets the value of LaunchLongitude. +func (s *Parameters) SetLaunchLongitude(val OptFloat64) { + s.LaunchLongitude = val +} + +// SetLaunchDatetime sets the value of LaunchDatetime. +func (s *Parameters) SetLaunchDatetime(val OptDateTime) { + s.LaunchDatetime = val +} + +// SetLaunchAltitude sets the value of LaunchAltitude. +func (s *Parameters) SetLaunchAltitude(val OptFloat64) { + s.LaunchAltitude = val +} + +// SetProfile sets the value of Profile. +func (s *Parameters) SetProfile(val OptParametersProfile) { + s.Profile = val +} + +// SetAscentRate sets the value of AscentRate. +func (s *Parameters) SetAscentRate(val OptFloat64) { + s.AscentRate = val +} + +// SetBurstAltitude sets the value of BurstAltitude. +func (s *Parameters) SetBurstAltitude(val OptFloat64) { + s.BurstAltitude = val +} + +// SetDescentRate sets the value of DescentRate. +func (s *Parameters) SetDescentRate(val OptFloat64) { + s.DescentRate = val +} + +// SetFloatAltitude sets the value of FloatAltitude. +func (s *Parameters) SetFloatAltitude(val OptFloat64) { + s.FloatAltitude = val +} + +// SetStopDatetime sets the value of StopDatetime. +func (s *Parameters) SetStopDatetime(val OptDateTime) { + s.StopDatetime = val +} + +// SetAscentCurve sets the value of AscentCurve. +func (s *Parameters) SetAscentCurve(val OptString) { + s.AscentCurve = val +} + +// SetDescentCurve sets the value of DescentCurve. +func (s *Parameters) SetDescentCurve(val OptString) { + s.DescentCurve = val +} + +// SetInterpolate sets the value of Interpolate. +func (s *Parameters) SetInterpolate(val OptBool) { + s.Interpolate = val +} + +// SetFormat sets the value of Format. +func (s *Parameters) SetFormat(val OptParametersFormat) { + s.Format = val +} + +// SetDataset sets the value of Dataset. +func (s *Parameters) SetDataset(val OptDateTime) { + s.Dataset = val +} + +type ParametersFormat string + +const ( + ParametersFormatJSON ParametersFormat = "json" +) + +// AllValues returns all ParametersFormat values. +func (ParametersFormat) AllValues() []ParametersFormat { + return []ParametersFormat{ + ParametersFormatJSON, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s ParametersFormat) MarshalText() ([]byte, error) { + switch s { + case ParametersFormatJSON: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *ParametersFormat) UnmarshalText(data []byte) error { + switch ParametersFormat(data) { + case ParametersFormatJSON: + *s = ParametersFormatJSON + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +type ParametersProfile string + +const ( + ParametersProfileStandardProfile ParametersProfile = "standard_profile" + ParametersProfileFloatProfile ParametersProfile = "float_profile" + ParametersProfileReverseProfile ParametersProfile = "reverse_profile" + ParametersProfileCustomProfile ParametersProfile = "custom_profile" +) + +// AllValues returns all ParametersProfile values. +func (ParametersProfile) AllValues() []ParametersProfile { + return []ParametersProfile{ + ParametersProfileStandardProfile, + ParametersProfileFloatProfile, + ParametersProfileReverseProfile, + ParametersProfileCustomProfile, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s ParametersProfile) MarshalText() ([]byte, error) { + switch s { + case ParametersProfileStandardProfile: + return []byte(s), nil + case ParametersProfileFloatProfile: + return []byte(s), nil + case ParametersProfileReverseProfile: + return []byte(s), nil + case ParametersProfileCustomProfile: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *ParametersProfile) UnmarshalText(data []byte) error { + switch ParametersProfile(data) { + case ParametersProfileStandardProfile: + *s = ParametersProfileStandardProfile + return nil + case ParametersProfileFloatProfile: + *s = ParametersProfileFloatProfile + return nil + case ParametersProfileReverseProfile: + *s = ParametersProfileReverseProfile + return nil + case ParametersProfileCustomProfile: + *s = ParametersProfileCustomProfile + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +// Ref: #/components/schemas/Prediction/Result +type Result struct { + Metadata ResultMetadata `json:"metadata"` + Prediction []ResultPredictionItem `json:"prediction"` +} + +// GetMetadata returns the value of Metadata. +func (s *Result) GetMetadata() ResultMetadata { + return s.Metadata +} + +// GetPrediction returns the value of Prediction. +func (s *Result) GetPrediction() []ResultPredictionItem { + return s.Prediction +} + +// SetMetadata sets the value of Metadata. +func (s *Result) SetMetadata(val ResultMetadata) { + s.Metadata = val +} + +// SetPrediction sets the value of Prediction. +func (s *Result) SetPrediction(val []ResultPredictionItem) { + s.Prediction = val +} + +type ResultMetadata struct { + CompleteDatetime time.Time `json:"complete_datetime"` + StartDatetime time.Time `json:"start_datetime"` +} + +// GetCompleteDatetime returns the value of CompleteDatetime. +func (s *ResultMetadata) GetCompleteDatetime() time.Time { + return s.CompleteDatetime +} + +// GetStartDatetime returns the value of StartDatetime. +func (s *ResultMetadata) GetStartDatetime() time.Time { + return s.StartDatetime +} + +// SetCompleteDatetime sets the value of CompleteDatetime. +func (s *ResultMetadata) SetCompleteDatetime(val time.Time) { + s.CompleteDatetime = val +} + +// SetStartDatetime sets the value of StartDatetime. +func (s *ResultMetadata) SetStartDatetime(val time.Time) { + s.StartDatetime = val +} + +type ResultPredictionItem struct { + Stage ResultPredictionItemStage `json:"stage"` + Trajectory []ResultPredictionItemTrajectoryItem `json:"trajectory"` +} + +// GetStage returns the value of Stage. +func (s *ResultPredictionItem) GetStage() ResultPredictionItemStage { + return s.Stage +} + +// GetTrajectory returns the value of Trajectory. +func (s *ResultPredictionItem) GetTrajectory() []ResultPredictionItemTrajectoryItem { + return s.Trajectory +} + +// SetStage sets the value of Stage. +func (s *ResultPredictionItem) SetStage(val ResultPredictionItemStage) { + s.Stage = val +} + +// SetTrajectory sets the value of Trajectory. +func (s *ResultPredictionItem) SetTrajectory(val []ResultPredictionItemTrajectoryItem) { + s.Trajectory = val +} + +type ResultPredictionItemStage string + +const ( + ResultPredictionItemStageAscent ResultPredictionItemStage = "ascent" + ResultPredictionItemStageDescent ResultPredictionItemStage = "descent" +) + +// AllValues returns all ResultPredictionItemStage values. +func (ResultPredictionItemStage) AllValues() []ResultPredictionItemStage { + return []ResultPredictionItemStage{ + ResultPredictionItemStageAscent, + ResultPredictionItemStageDescent, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s ResultPredictionItemStage) MarshalText() ([]byte, error) { + switch s { + case ResultPredictionItemStageAscent: + return []byte(s), nil + case ResultPredictionItemStageDescent: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *ResultPredictionItemStage) UnmarshalText(data []byte) error { + switch ResultPredictionItemStage(data) { + case ResultPredictionItemStageAscent: + *s = ResultPredictionItemStageAscent + return nil + case ResultPredictionItemStageDescent: + *s = ResultPredictionItemStageDescent + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +type ResultPredictionItemTrajectoryItem struct{} diff --git a/pkg/rest/oas_server_gen.go b/pkg/rest/oas_server_gen.go new file mode 100644 index 0000000..bb4accc --- /dev/null +++ b/pkg/rest/oas_server_gen.go @@ -0,0 +1,40 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "context" +) + +// Handler handles operations described by OpenAPI v3 specification. +type Handler interface { + // PerformPrediction implements performPrediction operation. + // + // Perform preidction. + // + // POST /api/v1/prediction + PerformPrediction(ctx context.Context, req OptParameters, params PerformPredictionParams) (*Result, error) + // NewError creates *ErrorStatusCode from error returned by handler. + // + // Used for common default response. + NewError(ctx context.Context, err error) *ErrorStatusCode +} + +// Server implements http server based on OpenAPI v3 specification and +// calls Handler to handle requests. +type Server struct { + h Handler + baseServer +} + +// NewServer creates new Server. +func NewServer(h Handler, opts ...ServerOption) (*Server, error) { + s, err := newServerConfig(opts...).baseServer() + if err != nil { + return nil, err + } + return &Server{ + h: h, + baseServer: s, + }, nil +} diff --git a/pkg/rest/oas_unimplemented_gen.go b/pkg/rest/oas_unimplemented_gen.go new file mode 100644 index 0000000..b87adb0 --- /dev/null +++ b/pkg/rest/oas_unimplemented_gen.go @@ -0,0 +1,31 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "context" + + ht "github.com/ogen-go/ogen/http" +) + +// UnimplementedHandler is no-op Handler which returns http.ErrNotImplemented. +type UnimplementedHandler struct{} + +var _ Handler = UnimplementedHandler{} + +// PerformPrediction implements performPrediction operation. +// +// Perform preidction. +// +// POST /api/v1/prediction +func (UnimplementedHandler) PerformPrediction(ctx context.Context, req OptParameters, params PerformPredictionParams) (r *Result, _ error) { + return r, ht.ErrNotImplemented +} + +// NewError creates *ErrorStatusCode from error returned by handler. +// +// Used for common default response. +func (UnimplementedHandler) NewError(ctx context.Context, err error) (r *ErrorStatusCode) { + r = new(ErrorStatusCode) + return r +} diff --git a/pkg/rest/oas_uri_gen.go b/pkg/rest/oas_uri_gen.go new file mode 100644 index 0000000..6c486e7 --- /dev/null +++ b/pkg/rest/oas_uri_gen.go @@ -0,0 +1,535 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "time" + + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/conv" + "github.com/ogen-go/ogen/uri" +) + +// EncodeURI encodes Parameters as URI form. +func (s *Parameters) EncodeURI(e uri.Encoder) error { + if err := e.EncodeField("launch_latitude", func(e uri.Encoder) error { + if val, ok := s.LaunchLatitude.Get(); ok { + return e.EncodeValue(conv.Float64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"launch_latitude\"") + } + if err := e.EncodeField("launch_longitude", func(e uri.Encoder) error { + if val, ok := s.LaunchLongitude.Get(); ok { + return e.EncodeValue(conv.Float64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"launch_longitude\"") + } + if err := e.EncodeField("launch_datetime", func(e uri.Encoder) error { + if val, ok := s.LaunchDatetime.Get(); ok { + return e.EncodeValue(conv.DateTimeToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"launch_datetime\"") + } + if err := e.EncodeField("launch_altitude", func(e uri.Encoder) error { + if val, ok := s.LaunchAltitude.Get(); ok { + return e.EncodeValue(conv.Float64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"launch_altitude\"") + } + if err := e.EncodeField("profile", func(e uri.Encoder) error { + if val, ok := s.Profile.Get(); ok { + return e.EncodeValue(conv.StringToString(string(val))) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"profile\"") + } + if err := e.EncodeField("ascent_rate", func(e uri.Encoder) error { + if val, ok := s.AscentRate.Get(); ok { + return e.EncodeValue(conv.Float64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"ascent_rate\"") + } + if err := e.EncodeField("burst_altitude", func(e uri.Encoder) error { + if val, ok := s.BurstAltitude.Get(); ok { + return e.EncodeValue(conv.Float64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"burst_altitude\"") + } + if err := e.EncodeField("descent_rate", func(e uri.Encoder) error { + if val, ok := s.DescentRate.Get(); ok { + return e.EncodeValue(conv.Float64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"descent_rate\"") + } + if err := e.EncodeField("float_altitude", func(e uri.Encoder) error { + if val, ok := s.FloatAltitude.Get(); ok { + return e.EncodeValue(conv.Float64ToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"float_altitude\"") + } + if err := e.EncodeField("stop_datetime", func(e uri.Encoder) error { + if val, ok := s.StopDatetime.Get(); ok { + return e.EncodeValue(conv.DateTimeToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"stop_datetime\"") + } + if err := e.EncodeField("ascent_curve", func(e uri.Encoder) error { + if val, ok := s.AscentCurve.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"ascent_curve\"") + } + if err := e.EncodeField("descent_curve", func(e uri.Encoder) error { + if val, ok := s.DescentCurve.Get(); ok { + return e.EncodeValue(conv.StringToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"descent_curve\"") + } + if err := e.EncodeField("interpolate", func(e uri.Encoder) error { + if val, ok := s.Interpolate.Get(); ok { + return e.EncodeValue(conv.BoolToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"interpolate\"") + } + if err := e.EncodeField("format", func(e uri.Encoder) error { + if val, ok := s.Format.Get(); ok { + return e.EncodeValue(conv.StringToString(string(val))) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"format\"") + } + if err := e.EncodeField("dataset", func(e uri.Encoder) error { + if val, ok := s.Dataset.Get(); ok { + return e.EncodeValue(conv.DateTimeToString(val)) + } + return nil + }); err != nil { + return errors.Wrap(err, "encode field \"dataset\"") + } + return nil +} + +var uriFieldsNameOfParameters = [15]string{ + 0: "launch_latitude", + 1: "launch_longitude", + 2: "launch_datetime", + 3: "launch_altitude", + 4: "profile", + 5: "ascent_rate", + 6: "burst_altitude", + 7: "descent_rate", + 8: "float_altitude", + 9: "stop_datetime", + 10: "ascent_curve", + 11: "descent_curve", + 12: "interpolate", + 13: "format", + 14: "dataset", +} + +// DecodeURI decodes Parameters from URI form. +func (s *Parameters) DecodeURI(d uri.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode Parameters to nil") + } + s.setDefaults() + + if err := d.DecodeFields(func(k string, d uri.Decoder) error { + switch k { + case "launch_latitude": + if err := func() error { + var sDotLaunchLatitudeVal float64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToFloat64(val) + if err != nil { + return err + } + + sDotLaunchLatitudeVal = c + return nil + }(); err != nil { + return err + } + s.LaunchLatitude.SetTo(sDotLaunchLatitudeVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_latitude\"") + } + case "launch_longitude": + if err := func() error { + var sDotLaunchLongitudeVal float64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToFloat64(val) + if err != nil { + return err + } + + sDotLaunchLongitudeVal = c + return nil + }(); err != nil { + return err + } + s.LaunchLongitude.SetTo(sDotLaunchLongitudeVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_longitude\"") + } + case "launch_datetime": + if err := func() error { + var sDotLaunchDatetimeVal time.Time + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToDateTime(val) + if err != nil { + return err + } + + sDotLaunchDatetimeVal = c + return nil + }(); err != nil { + return err + } + s.LaunchDatetime.SetTo(sDotLaunchDatetimeVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_datetime\"") + } + case "launch_altitude": + if err := func() error { + var sDotLaunchAltitudeVal float64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToFloat64(val) + if err != nil { + return err + } + + sDotLaunchAltitudeVal = c + return nil + }(); err != nil { + return err + } + s.LaunchAltitude.SetTo(sDotLaunchAltitudeVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"launch_altitude\"") + } + case "profile": + if err := func() error { + var sDotProfileVal ParametersProfile + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + sDotProfileVal = ParametersProfile(c) + return nil + }(); err != nil { + return err + } + s.Profile.SetTo(sDotProfileVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"profile\"") + } + case "ascent_rate": + if err := func() error { + var sDotAscentRateVal float64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToFloat64(val) + if err != nil { + return err + } + + sDotAscentRateVal = c + return nil + }(); err != nil { + return err + } + s.AscentRate.SetTo(sDotAscentRateVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ascent_rate\"") + } + case "burst_altitude": + if err := func() error { + var sDotBurstAltitudeVal float64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToFloat64(val) + if err != nil { + return err + } + + sDotBurstAltitudeVal = c + return nil + }(); err != nil { + return err + } + s.BurstAltitude.SetTo(sDotBurstAltitudeVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"burst_altitude\"") + } + case "descent_rate": + if err := func() error { + var sDotDescentRateVal float64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToFloat64(val) + if err != nil { + return err + } + + sDotDescentRateVal = c + return nil + }(); err != nil { + return err + } + s.DescentRate.SetTo(sDotDescentRateVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"descent_rate\"") + } + case "float_altitude": + if err := func() error { + var sDotFloatAltitudeVal float64 + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToFloat64(val) + if err != nil { + return err + } + + sDotFloatAltitudeVal = c + return nil + }(); err != nil { + return err + } + s.FloatAltitude.SetTo(sDotFloatAltitudeVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"float_altitude\"") + } + case "stop_datetime": + if err := func() error { + var sDotStopDatetimeVal time.Time + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToDateTime(val) + if err != nil { + return err + } + + sDotStopDatetimeVal = c + return nil + }(); err != nil { + return err + } + s.StopDatetime.SetTo(sDotStopDatetimeVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"stop_datetime\"") + } + case "ascent_curve": + if err := func() error { + var sDotAscentCurveVal string + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + sDotAscentCurveVal = c + return nil + }(); err != nil { + return err + } + s.AscentCurve.SetTo(sDotAscentCurveVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"ascent_curve\"") + } + case "descent_curve": + if err := func() error { + var sDotDescentCurveVal string + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + sDotDescentCurveVal = c + return nil + }(); err != nil { + return err + } + s.DescentCurve.SetTo(sDotDescentCurveVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"descent_curve\"") + } + case "interpolate": + if err := func() error { + var sDotInterpolateVal bool + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToBool(val) + if err != nil { + return err + } + + sDotInterpolateVal = c + return nil + }(); err != nil { + return err + } + s.Interpolate.SetTo(sDotInterpolateVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"interpolate\"") + } + case "format": + if err := func() error { + var sDotFormatVal ParametersFormat + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + sDotFormatVal = ParametersFormat(c) + return nil + }(); err != nil { + return err + } + s.Format.SetTo(sDotFormatVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"format\"") + } + case "dataset": + if err := func() error { + var sDotDatasetVal time.Time + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToDateTime(val) + if err != nil { + return err + } + + sDotDatasetVal = c + return nil + }(); err != nil { + return err + } + s.Dataset.SetTo(sDotDatasetVal) + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"dataset\"") + } + default: + return nil + } + return nil + }); err != nil { + return errors.Wrap(err, "decode Parameters") + } + + return nil +} diff --git a/pkg/rest/oas_validators_gen.go b/pkg/rest/oas_validators_gen.go new file mode 100644 index 0000000..ee198cc --- /dev/null +++ b/pkg/rest/oas_validators_gen.go @@ -0,0 +1,294 @@ +// Code generated by ogen, DO NOT EDIT. + +package gsn + +import ( + "fmt" + + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/validate" +) + +func (s *Parameters) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if value, ok := s.LaunchLatitude.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "launch_latitude", + Error: err, + }) + } + if err := func() error { + if value, ok := s.LaunchLongitude.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "launch_longitude", + Error: err, + }) + } + if err := func() error { + if value, ok := s.LaunchAltitude.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "launch_altitude", + Error: err, + }) + } + if err := func() error { + if value, ok := s.Profile.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "profile", + Error: err, + }) + } + if err := func() error { + if value, ok := s.AscentRate.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "ascent_rate", + Error: err, + }) + } + if err := func() error { + if value, ok := s.BurstAltitude.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "burst_altitude", + Error: err, + }) + } + if err := func() error { + if value, ok := s.DescentRate.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "descent_rate", + Error: err, + }) + } + if err := func() error { + if value, ok := s.FloatAltitude.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "float_altitude", + Error: err, + }) + } + if err := func() error { + if value, ok := s.Format.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "format", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s ParametersFormat) Validate() error { + switch s { + case "json": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + +func (s ParametersProfile) Validate() error { + switch s { + case "standard_profile": + return nil + case "float_profile": + return nil + case "reverse_profile": + return nil + case "custom_profile": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + +func (s *Result) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if s.Prediction == nil { + return errors.New("nil is invalid value") + } + var failures []validate.FieldError + for i, elem := range s.Prediction { + if err := func() error { + if err := elem.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: fmt.Sprintf("[%d]", i), + Error: err, + }) + } + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "prediction", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s *ResultPredictionItem) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + + var failures []validate.FieldError + if err := func() error { + if err := s.Stage.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "stage", + Error: err, + }) + } + if err := func() error { + if s.Trajectory == nil { + return errors.New("nil is invalid value") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "trajectory", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s ResultPredictionItemStage) Validate() error { + switch s { + case "ascent": + return nil + case "descent": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} From bcb9ace54ce1ac48dd80d3623b93a06825d7a815 Mon Sep 17 00:00:00 2001 From: "a.antonov" Date: Sat, 21 Jun 2025 22:06:32 +0300 Subject: [PATCH 2/4] feat: implemented service/transport/main layers --- api/rest/predictor.swagger.yml | 155 +++++----- cmd/api/main.go | 41 +++ go.mod | 32 ++ go.sum | 77 +++++ internal/pkg/ds/predictor.go | 7 + internal/pkg/errcodes/errcodes.go | 25 ++ internal/pkg/log/log.go | 23 ++ internal/service/deps.go | 16 + internal/service/predictor.go | 13 + internal/service/service.go | 10 + internal/transport/middleware/log.go | 44 +++ internal/transport/rest/config.go | 23 ++ internal/transport/rest/handler/deps.go | 11 + internal/transport/rest/handler/handler.go | 52 ++++ internal/transport/rest/transport.go | 38 +++ pkg/rest/oas_client_gen.go | 6 +- pkg/rest/oas_defaults_gen.go | 4 +- pkg/rest/oas_handlers_gen.go | 6 +- pkg/rest/oas_json_gen.go | 234 +++++++-------- pkg/rest/oas_parameters_gen.go | 6 +- pkg/rest/oas_request_decoders_gen.go | 4 +- pkg/rest/oas_request_encoders_gen.go | 2 +- pkg/rest/oas_response_decoders_gen.go | 4 +- pkg/rest/oas_response_encoders_gen.go | 2 +- pkg/rest/oas_schemas_gen.go | 324 ++++++++++----------- pkg/rest/oas_server_gen.go | 2 +- pkg/rest/oas_unimplemented_gen.go | 2 +- pkg/rest/oas_uri_gen.go | 22 +- pkg/rest/oas_validators_gen.go | 12 +- 29 files changed, 804 insertions(+), 393 deletions(-) create mode 100644 cmd/api/main.go create mode 100644 go.sum create mode 100644 internal/pkg/ds/predictor.go create mode 100644 internal/pkg/errcodes/errcodes.go create mode 100644 internal/pkg/log/log.go create mode 100644 internal/service/deps.go create mode 100644 internal/service/predictor.go create mode 100644 internal/service/service.go create mode 100644 internal/transport/middleware/log.go create mode 100644 internal/transport/rest/config.go create mode 100644 internal/transport/rest/handler/deps.go create mode 100644 internal/transport/rest/handler/handler.go create mode 100644 internal/transport/rest/transport.go diff --git a/api/rest/predictor.swagger.yml b/api/rest/predictor.swagger.yml index d44f7fa..68ef128 100644 --- a/api/rest/predictor.swagger.yml +++ b/api/rest/predictor.swagger.yml @@ -14,7 +14,7 @@ paths: name: parameters required: false schema: - $ref: '#/components/schemas/Prediction/Parameters' + $ref: '#/components/schemas/PredictionParameters' style: form explode: true requestBody: @@ -22,14 +22,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Prediction/Parameters' + $ref: '#/components/schemas/PredictionParameters' responses: "200": description: "Prediction response" content: application/json: schema: - $ref: '#/components/schemas/Prediction/Result' + $ref: '#/components/schemas/PredictionResult' default: description: Error content: @@ -48,82 +48,81 @@ components: type: string details: type: string - Prediction: - Parameters: - type: object - properties: - launch_latitude: # TODO: altitude not required with fallback to https://github.com/priyeshpatel/ruaumoko Go analog - type: number - launch_longitude: - type: number - launch_datetime: - type: string - format: date-time - launch_altitude: - type: number - profile: - type: string - enum: ["standard_profile", "float_profile", "reverse_profile", "custom_profile"] - ascent_rate: - type: number - burst_altitude: - type: number - descent_rate: - type: number - float_altitude: - type: number - stop_datetime: - type: string - format: date-time - ascent_curve: - type: string - description: "Base64 encoded ascent curve" - descent_curve: - type: string - description: "Base64 encoded descent curve" - interpolate: - type: boolean - default: false - format: # TODO: custom output format (csv, kml) with json as default - type: string - enum: ["json"] - default: json - dataset: - type: string - format: date-time - Result: # - type: object - required: - - metadata - - prediction - properties: - metadata: + PredictionParameters: + type: object + properties: + launch_latitude: # TODO: altitude not required with fallback to https://github.com/priyeshpatel/ruaumoko Go analog + type: number + launch_longitude: + type: number + launch_datetime: + type: string + format: date-time + launch_altitude: + type: number + profile: + type: string + enum: ["standard_profile", "float_profile", "reverse_profile", "custom_profile"] + ascent_rate: + type: number + burst_altitude: + type: number + descent_rate: + type: number + float_altitude: + type: number + stop_datetime: + type: string + format: date-time + ascent_curve: + type: string + description: "Base64 encoded ascent curve" + descent_curve: + type: string + description: "Base64 encoded descent curve" + interpolate: + type: boolean + default: false + format: # TODO: custom output format (csv, kml) with json as default + type: string + enum: ["json"] + default: json + dataset: + type: string + format: date-time + PredictionResult: + type: object + required: + - metadata + - prediction + properties: + metadata: + type: object + required: + - complete_datetime + - start_datetime + properties: + complete_datetime: + type: string + format: date-time + start_datetime: + type: string + format: date-time + prediction: + type: array + items: type: object required: - - complete_datetime - - start_datetime + - stage + - trajectory properties: - complete_datetime: + stage: type: string - format: date-time - start_datetime: - type: string - format: date-time - prediction: - type: array - items: - type: object - required: - - stage - - trajectory - properties: - stage: - type: string - enum: ["ascent", "descent"] - trajectory: - type: array - items: - type: object - required: - - datetime - - latitude \ No newline at end of file + enum: ["ascent", "descent"] + trajectory: + type: array + items: + type: object + required: + - datetime + - latitude \ No newline at end of file diff --git a/cmd/api/main.go b/cmd/api/main.go new file mode 100644 index 0000000..a271536 --- /dev/null +++ b/cmd/api/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "git.intra.yksa.space/gsn/predictor/internal/service" + "git.intra.yksa.space/gsn/predictor/internal/transport/rest" + "git.intra.yksa.space/gsn/predictor/internal/transport/rest/handler" + "go.uber.org/zap" +) + +const ( + servicePrefix = "PREDICTOR" +) + +func main() { + lg, err := zap.NewProduction() + if err != nil { + panic(err) + } + + svc := service.New() + + handler := handler.New(svc) + + restConfig, err := rest.NewConfig(servicePrefix) + if err != nil { + lg.Fatal("failed to init transport config", zap.Error(err)) + } + + transport, err := rest.New(lg, handler, restConfig) + if err != nil { + lg.Fatal("failed to init transport", zap.Error(err)) + } + + for { + transport.Run() + + if r := recover(); r != nil { + lg.Error("panic occured", zap.Any("recover", r)) + } + } +} diff --git a/go.mod b/go.mod index af3a3ba..6885f78 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,35 @@ module git.intra.yksa.space/gsn/predictor go 1.24.4 + +require ( + github.com/caarlos0/env/v11 v11.3.1 + github.com/go-faster/errors v0.7.1 + github.com/go-faster/jx v1.1.0 + github.com/ogen-go/ogen v1.14.0 + go.opentelemetry.io/otel v1.36.0 + go.opentelemetry.io/otel/metric v1.36.0 + go.opentelemetry.io/otel/trace v1.36.0 + go.uber.org/zap v1.27.0 +) + +require ( + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-faster/yaml v0.4.6 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/segmentio/asm v1.2.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.25.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e28db0e --- /dev/null +++ b/go.sum @@ -0,0 +1,77 @@ +github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA= +github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= +github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= +github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg= +github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg= +github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= +github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/ogen-go/ogen v1.14.0 h1:TU1Nj4z9UBsAfTkf+IhuNNp7igdFQKqkk9+6/y4XuWg= +github.com/ogen-go/ogen v1.14.0/go.mod h1:Iw1vkqkx6SU7I9th5ceP+fVPJ6Wge4e3kAVzAxJEpPE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= +golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/pkg/ds/predictor.go b/internal/pkg/ds/predictor.go new file mode 100644 index 0000000..3f6b265 --- /dev/null +++ b/internal/pkg/ds/predictor.go @@ -0,0 +1,7 @@ +package ds + +type PredictionParameters struct { +} + +type PredicitonResult struct { +} \ No newline at end of file diff --git a/internal/pkg/errcodes/errcodes.go b/internal/pkg/errcodes/errcodes.go new file mode 100644 index 0000000..245f508 --- /dev/null +++ b/internal/pkg/errcodes/errcodes.go @@ -0,0 +1,25 @@ +package errcodes + +import ( + "strings" +) + +type ErrorCode struct { + StatusCode int + Message string + Details string +} + +var errorCodeCounter int32 + +func New(statusCode int, message string, details ...string) *ErrorCode { + return &ErrorCode{ + StatusCode: statusCode, + Message: message, + Details: strings.Join(details, " "), + } +} + +func (e *ErrorCode) Error() string { + return e.Message +} diff --git a/internal/pkg/log/log.go b/internal/pkg/log/log.go new file mode 100644 index 0000000..58db255 --- /dev/null +++ b/internal/pkg/log/log.go @@ -0,0 +1,23 @@ +package log + +import ( + "context" + + "go.uber.org/zap" +) + +type ctxLogKey struct{} + +func ToCtx(ctx context.Context, lg *zap.Logger) context.Context { + return context.WithValue(ctx, ctxLogKey{}, lg) +} + +func Ctx(ctx context.Context) *zap.Logger { + lg, ok := ctx.Value(ctxLogKey{}).(*zap.Logger) + if !ok || lg == nil { + zap.L().Error("no logger in context, using global") + return zap.L() + } + + return lg +} diff --git a/internal/service/deps.go b/internal/service/deps.go new file mode 100644 index 0000000..0becf3e --- /dev/null +++ b/internal/service/deps.go @@ -0,0 +1,16 @@ +package service + +import ( + "context" + "time" +) + +type Redis interface { + Lock(ctx context.Context, key string, ttl time.Duration) (func(context.Context), error) + Set(key string, value []byte, ttl time.Duration) error + Get(key string) ([]byte, error) +} + +type Downloader interface { + Download(ctx context.Context) +} diff --git a/internal/service/predictor.go b/internal/service/predictor.go new file mode 100644 index 0000000..c78e2b4 --- /dev/null +++ b/internal/service/predictor.go @@ -0,0 +1,13 @@ +package service + +import ( + "context" + "net/http" + + "git.intra.yksa.space/gsn/predictor/internal/pkg/ds" + "git.intra.yksa.space/gsn/predictor/internal/pkg/errcodes" +) + +func (s *Service) PerformPrediction(ctx context.Context, params ds.PredictionParameters) ([]ds.PredicitonResult, error) { + return nil, errcodes.New(http.StatusNotImplemented, "not implemented", "please wait") +} diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 0000000..0ac3f89 --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,10 @@ +package service + +type Service struct { + redis Redis + downloader Downloader +} + +func New() *Service { + return &Service{} +} diff --git a/internal/transport/middleware/log.go b/internal/transport/middleware/log.go new file mode 100644 index 0000000..1ad417c --- /dev/null +++ b/internal/transport/middleware/log.go @@ -0,0 +1,44 @@ +package middleware + +import ( + "time" + + "git.intra.yksa.space/gsn/predictor/internal/pkg/errcodes" + "git.intra.yksa.space/gsn/predictor/internal/pkg/log" + "github.com/ogen-go/ogen/middleware" + "go.uber.org/zap" +) + +func Logging(logger *zap.Logger) middleware.Middleware { + return func(req middleware.Request, next func(req middleware.Request) (middleware.Response, error)) (middleware.Response, error) { + lg := logger.With( + zap.String("operationId", req.OperationID), + ) + + lg.Info("started request") + + req.Context = log.ToCtx(req.Context, lg) + + start := time.Now() + resp, err := next(req) + dur := time.Since(start).Microseconds() + + if err != nil { + if errcode, ok := err.(*errcodes.ErrorCode); ok { + lg.Error("request error", + zap.Int("status_code", errcode.StatusCode), + zap.String("message", errcode.Message), + zap.String("details", errcode.Details), + ) + } else { + lg.Error("request internal error", + zap.Error(err), + ) + } + } + + lg.Info("done request", zap.Float64("duration_ms", float64(dur)/float64(1000))) + + return resp, err + } +} diff --git a/internal/transport/rest/config.go b/internal/transport/rest/config.go new file mode 100644 index 0000000..2cddd06 --- /dev/null +++ b/internal/transport/rest/config.go @@ -0,0 +1,23 @@ +package rest + +import ( + "fmt" + + env "github.com/caarlos0/env/v11" +) + +type Config struct { + Port int `env:"PORT" envDefault:"8080"` +} + +func NewConfig(servicePrefix string) (*Config, error) { + cfg := &Config{} + + if err := env.ParseWithOptions(cfg, env.Options{ + PrefixTagName: fmt.Sprintf("%s_REST_", servicePrefix), + }); err != nil { + return nil, err + } + + return cfg, nil +} diff --git a/internal/transport/rest/handler/deps.go b/internal/transport/rest/handler/deps.go new file mode 100644 index 0000000..e75769c --- /dev/null +++ b/internal/transport/rest/handler/deps.go @@ -0,0 +1,11 @@ +package handler + +import ( + "context" + + "git.intra.yksa.space/gsn/predictor/internal/pkg/ds" +) + +type Service interface { + PerformPrediction(ctx context.Context, params ds.PredictionParameters) ([]ds.PredicitonResult, error) +} diff --git a/internal/transport/rest/handler/handler.go b/internal/transport/rest/handler/handler.go new file mode 100644 index 0000000..49ce1c8 --- /dev/null +++ b/internal/transport/rest/handler/handler.go @@ -0,0 +1,52 @@ +package handler + +import ( + "context" + "net/http" + + "git.intra.yksa.space/gsn/predictor/internal/pkg/errcodes" + api "git.intra.yksa.space/gsn/predictor/pkg/rest" +) + +var ( + _ api.Handler = (*Handler)(nil) +) + +type Handler struct { + svc Service +} + +func New(svc Service) *Handler { + return &Handler{ + svc: svc, + } +} + +func (h *Handler) PerformPrediction(ctx context.Context, req api.OptPredictionParameters, params api.PerformPredictionParams) (*api.PredictionResult, error) { + return nil, errcodes.New(http.StatusNotImplemented, "not implemented", "please wait") +} + +func (h *Handler) NewError(ctx context.Context, err error) *api.ErrorStatusCode { + if errcode, ok := err.(*errcodes.ErrorCode); ok { + resp := api.Error{ + Message: errcode.Message, + } + + if errcode.Details != "" { + resp.Details = api.NewOptString(errcode.Details) + } + + return &api.ErrorStatusCode{ + StatusCode: errcode.StatusCode, + Response: resp, + } + } + + return &api.ErrorStatusCode{ + StatusCode: http.StatusInternalServerError, + Response: api.Error{ + Message: "undefined internal error", + Details: api.NewOptString(err.Error()), + }, + } +} diff --git a/internal/transport/rest/transport.go b/internal/transport/rest/transport.go new file mode 100644 index 0000000..2657272 --- /dev/null +++ b/internal/transport/rest/transport.go @@ -0,0 +1,38 @@ +package rest + +import ( + "fmt" + "net/http" + + "git.intra.yksa.space/gsn/predictor/internal/transport/middleware" + handler "git.intra.yksa.space/gsn/predictor/internal/transport/rest/handler" + api "git.intra.yksa.space/gsn/predictor/pkg/rest" + "go.uber.org/zap" +) + +type Transport struct { + lg *zap.Logger + cfg *Config + srv *api.Server +} + +func New(lg *zap.Logger, handler *handler.Handler, cfg *Config) (*Transport, error) { + srv, err := api.NewServer(handler, api.WithMiddleware(middleware.Logging(lg))) + if err != nil { + return nil, err + } + + return &Transport{ + lg: lg, + srv: srv, + cfg: cfg, + }, nil +} + +func (t *Transport) Run() { + t.lg.Info("started") + + if err := http.ListenAndServe(fmt.Sprintf(":%d", t.cfg.Port), t.srv); err != nil { + panic(err) + } +} diff --git a/pkg/rest/oas_client_gen.go b/pkg/rest/oas_client_gen.go index 8118041..036f7cd 100644 --- a/pkg/rest/oas_client_gen.go +++ b/pkg/rest/oas_client_gen.go @@ -32,7 +32,7 @@ type Invoker interface { // Perform preidction. // // POST /api/v1/prediction - PerformPrediction(ctx context.Context, request OptParameters, params PerformPredictionParams) (*Result, error) + PerformPrediction(ctx context.Context, request OptPredictionParameters, params PerformPredictionParams) (*PredictionResult, error) } // Client implements OAS client. @@ -87,12 +87,12 @@ func (c *Client) requestURL(ctx context.Context) *url.URL { // Perform preidction. // // POST /api/v1/prediction -func (c *Client) PerformPrediction(ctx context.Context, request OptParameters, params PerformPredictionParams) (*Result, error) { +func (c *Client) PerformPrediction(ctx context.Context, request OptPredictionParameters, params PerformPredictionParams) (*PredictionResult, error) { res, err := c.sendPerformPrediction(ctx, request, params) return res, err } -func (c *Client) sendPerformPrediction(ctx context.Context, request OptParameters, params PerformPredictionParams) (res *Result, err error) { +func (c *Client) sendPerformPrediction(ctx context.Context, request OptPredictionParameters, params PerformPredictionParams) (res *PredictionResult, err error) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("performPrediction"), semconv.HTTPRequestMethodKey.String("POST"), diff --git a/pkg/rest/oas_defaults_gen.go b/pkg/rest/oas_defaults_gen.go index 2f09154..4cccade 100644 --- a/pkg/rest/oas_defaults_gen.go +++ b/pkg/rest/oas_defaults_gen.go @@ -3,13 +3,13 @@ package gsn // setDefaults set default value of fields. -func (s *Parameters) setDefaults() { +func (s *PredictionParameters) setDefaults() { { val := bool(false) s.Interpolate.SetTo(val) } { - val := ParametersFormat("json") + val := PredictionParametersFormat("json") s.Format.SetTo(val) } } diff --git a/pkg/rest/oas_handlers_gen.go b/pkg/rest/oas_handlers_gen.go index 638947a..70eabc0 100644 --- a/pkg/rest/oas_handlers_gen.go +++ b/pkg/rest/oas_handlers_gen.go @@ -130,7 +130,7 @@ func (s *Server) handlePerformPredictionRequest(args [0]string, argsEscaped bool } }() - var response *Result + var response *PredictionResult if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, @@ -148,9 +148,9 @@ func (s *Server) handlePerformPredictionRequest(args [0]string, argsEscaped bool } type ( - Request = OptParameters + Request = OptPredictionParameters Params = PerformPredictionParams - Response = *Result + Response = *PredictionResult ) response, err = middleware.HookMiddleware[ Request, diff --git a/pkg/rest/oas_json_gen.go b/pkg/rest/oas_json_gen.go index 9542a4e..3bd1884 100644 --- a/pkg/rest/oas_json_gen.go +++ b/pkg/rest/oas_json_gen.go @@ -232,18 +232,18 @@ func (s *OptFloat64) UnmarshalJSON(data []byte) error { return s.Decode(d) } -// Encode encodes Parameters as json. -func (o OptParameters) Encode(e *jx.Encoder) { +// Encode encodes PredictionParameters as json. +func (o OptPredictionParameters) Encode(e *jx.Encoder) { if !o.Set { return } o.Value.Encode(e) } -// Decode decodes Parameters from json. -func (o *OptParameters) Decode(d *jx.Decoder) error { +// Decode decodes PredictionParameters from json. +func (o *OptPredictionParameters) Decode(d *jx.Decoder) error { if o == nil { - return errors.New("invalid: unable to decode OptParameters to nil") + return errors.New("invalid: unable to decode OptPredictionParameters to nil") } o.Set = true if err := o.Value.Decode(d); err != nil { @@ -253,30 +253,30 @@ func (o *OptParameters) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s OptParameters) MarshalJSON() ([]byte, error) { +func (s OptPredictionParameters) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptParameters) UnmarshalJSON(data []byte) error { +func (s *OptPredictionParameters) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes ParametersFormat as json. -func (o OptParametersFormat) Encode(e *jx.Encoder) { +// Encode encodes PredictionParametersFormat as json. +func (o OptPredictionParametersFormat) Encode(e *jx.Encoder) { if !o.Set { return } e.Str(string(o.Value)) } -// Decode decodes ParametersFormat from json. -func (o *OptParametersFormat) Decode(d *jx.Decoder) error { +// Decode decodes PredictionParametersFormat from json. +func (o *OptPredictionParametersFormat) Decode(d *jx.Decoder) error { if o == nil { - return errors.New("invalid: unable to decode OptParametersFormat to nil") + return errors.New("invalid: unable to decode OptPredictionParametersFormat to nil") } o.Set = true if err := o.Value.Decode(d); err != nil { @@ -286,30 +286,30 @@ func (o *OptParametersFormat) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s OptParametersFormat) MarshalJSON() ([]byte, error) { +func (s OptPredictionParametersFormat) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptParametersFormat) UnmarshalJSON(data []byte) error { +func (s *OptPredictionParametersFormat) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes ParametersProfile as json. -func (o OptParametersProfile) Encode(e *jx.Encoder) { +// Encode encodes PredictionParametersProfile as json. +func (o OptPredictionParametersProfile) Encode(e *jx.Encoder) { if !o.Set { return } e.Str(string(o.Value)) } -// Decode decodes ParametersProfile from json. -func (o *OptParametersProfile) Decode(d *jx.Decoder) error { +// Decode decodes PredictionParametersProfile from json. +func (o *OptPredictionParametersProfile) Decode(d *jx.Decoder) error { if o == nil { - return errors.New("invalid: unable to decode OptParametersProfile to nil") + return errors.New("invalid: unable to decode OptPredictionParametersProfile to nil") } o.Set = true if err := o.Value.Decode(d); err != nil { @@ -319,14 +319,14 @@ func (o *OptParametersProfile) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s OptParametersProfile) MarshalJSON() ([]byte, error) { +func (s OptPredictionParametersProfile) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *OptParametersProfile) UnmarshalJSON(data []byte) error { +func (s *OptPredictionParametersProfile) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } @@ -367,14 +367,14 @@ func (s *OptString) UnmarshalJSON(data []byte) error { } // Encode implements json.Marshaler. -func (s *Parameters) Encode(e *jx.Encoder) { +func (s *PredictionParameters) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *Parameters) encodeFields(e *jx.Encoder) { +func (s *PredictionParameters) encodeFields(e *jx.Encoder) { { if s.LaunchLatitude.Set { e.FieldStart("launch_latitude") @@ -467,7 +467,7 @@ func (s *Parameters) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfParameters = [15]string{ +var jsonFieldsNameOfPredictionParameters = [15]string{ 0: "launch_latitude", 1: "launch_longitude", 2: "launch_datetime", @@ -485,10 +485,10 @@ var jsonFieldsNameOfParameters = [15]string{ 14: "dataset", } -// Decode decodes Parameters from json. -func (s *Parameters) Decode(d *jx.Decoder) error { +// Decode decodes PredictionParameters from json. +func (s *PredictionParameters) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode Parameters to nil") + return errors.New("invalid: unable to decode PredictionParameters to nil") } s.setDefaults() @@ -649,116 +649,116 @@ func (s *Parameters) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode Parameters") + return errors.Wrap(err, "decode PredictionParameters") } return nil } // MarshalJSON implements stdjson.Marshaler. -func (s *Parameters) MarshalJSON() ([]byte, error) { +func (s *PredictionParameters) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *Parameters) UnmarshalJSON(data []byte) error { +func (s *PredictionParameters) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes ParametersFormat as json. -func (s ParametersFormat) Encode(e *jx.Encoder) { +// Encode encodes PredictionParametersFormat as json. +func (s PredictionParametersFormat) Encode(e *jx.Encoder) { e.Str(string(s)) } -// Decode decodes ParametersFormat from json. -func (s *ParametersFormat) Decode(d *jx.Decoder) error { +// Decode decodes PredictionParametersFormat from json. +func (s *PredictionParametersFormat) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode ParametersFormat to nil") + return errors.New("invalid: unable to decode PredictionParametersFormat to nil") } v, err := d.StrBytes() if err != nil { return err } // Try to use constant string. - switch ParametersFormat(v) { - case ParametersFormatJSON: - *s = ParametersFormatJSON + switch PredictionParametersFormat(v) { + case PredictionParametersFormatJSON: + *s = PredictionParametersFormatJSON default: - *s = ParametersFormat(v) + *s = PredictionParametersFormat(v) } return nil } // MarshalJSON implements stdjson.Marshaler. -func (s ParametersFormat) MarshalJSON() ([]byte, error) { +func (s PredictionParametersFormat) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *ParametersFormat) UnmarshalJSON(data []byte) error { +func (s *PredictionParametersFormat) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes ParametersProfile as json. -func (s ParametersProfile) Encode(e *jx.Encoder) { +// Encode encodes PredictionParametersProfile as json. +func (s PredictionParametersProfile) Encode(e *jx.Encoder) { e.Str(string(s)) } -// Decode decodes ParametersProfile from json. -func (s *ParametersProfile) Decode(d *jx.Decoder) error { +// Decode decodes PredictionParametersProfile from json. +func (s *PredictionParametersProfile) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode ParametersProfile to nil") + return errors.New("invalid: unable to decode PredictionParametersProfile to nil") } v, err := d.StrBytes() if err != nil { return err } // Try to use constant string. - switch ParametersProfile(v) { - case ParametersProfileStandardProfile: - *s = ParametersProfileStandardProfile - case ParametersProfileFloatProfile: - *s = ParametersProfileFloatProfile - case ParametersProfileReverseProfile: - *s = ParametersProfileReverseProfile - case ParametersProfileCustomProfile: - *s = ParametersProfileCustomProfile + switch PredictionParametersProfile(v) { + case PredictionParametersProfileStandardProfile: + *s = PredictionParametersProfileStandardProfile + case PredictionParametersProfileFloatProfile: + *s = PredictionParametersProfileFloatProfile + case PredictionParametersProfileReverseProfile: + *s = PredictionParametersProfileReverseProfile + case PredictionParametersProfileCustomProfile: + *s = PredictionParametersProfileCustomProfile default: - *s = ParametersProfile(v) + *s = PredictionParametersProfile(v) } return nil } // MarshalJSON implements stdjson.Marshaler. -func (s ParametersProfile) MarshalJSON() ([]byte, error) { +func (s PredictionParametersProfile) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *ParametersProfile) UnmarshalJSON(data []byte) error { +func (s *PredictionParametersProfile) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *Result) Encode(e *jx.Encoder) { +func (s *PredictionResult) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *Result) encodeFields(e *jx.Encoder) { +func (s *PredictionResult) encodeFields(e *jx.Encoder) { { e.FieldStart("metadata") s.Metadata.Encode(e) @@ -773,15 +773,15 @@ func (s *Result) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfResult = [2]string{ +var jsonFieldsNameOfPredictionResult = [2]string{ 0: "metadata", 1: "prediction", } -// Decode decodes Result from json. -func (s *Result) Decode(d *jx.Decoder) error { +// Decode decodes PredictionResult from json. +func (s *PredictionResult) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode Result to nil") + return errors.New("invalid: unable to decode PredictionResult to nil") } var requiredBitSet [1]uint8 @@ -800,9 +800,9 @@ func (s *Result) Decode(d *jx.Decoder) error { case "prediction": requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Prediction = make([]ResultPredictionItem, 0) + s.Prediction = make([]PredictionResultPredictionItem, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem ResultPredictionItem + var elem PredictionResultPredictionItem if err := elem.Decode(d); err != nil { return err } @@ -820,7 +820,7 @@ func (s *Result) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode Result") + return errors.Wrap(err, "decode PredictionResult") } // Validate required fields. var failures []validate.FieldError @@ -837,8 +837,8 @@ func (s *Result) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfResult) { - name = jsonFieldsNameOfResult[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfPredictionResult) { + name = jsonFieldsNameOfPredictionResult[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -859,27 +859,27 @@ func (s *Result) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *Result) MarshalJSON() ([]byte, error) { +func (s *PredictionResult) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *Result) UnmarshalJSON(data []byte) error { +func (s *PredictionResult) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *ResultMetadata) Encode(e *jx.Encoder) { +func (s *PredictionResultMetadata) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *ResultMetadata) encodeFields(e *jx.Encoder) { +func (s *PredictionResultMetadata) encodeFields(e *jx.Encoder) { { e.FieldStart("complete_datetime") json.EncodeDateTime(e, s.CompleteDatetime) @@ -890,15 +890,15 @@ func (s *ResultMetadata) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfResultMetadata = [2]string{ +var jsonFieldsNameOfPredictionResultMetadata = [2]string{ 0: "complete_datetime", 1: "start_datetime", } -// Decode decodes ResultMetadata from json. -func (s *ResultMetadata) Decode(d *jx.Decoder) error { +// Decode decodes PredictionResultMetadata from json. +func (s *PredictionResultMetadata) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode ResultMetadata to nil") + return errors.New("invalid: unable to decode PredictionResultMetadata to nil") } var requiredBitSet [1]uint8 @@ -933,7 +933,7 @@ func (s *ResultMetadata) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode ResultMetadata") + return errors.Wrap(err, "decode PredictionResultMetadata") } // Validate required fields. var failures []validate.FieldError @@ -950,8 +950,8 @@ func (s *ResultMetadata) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfResultMetadata) { - name = jsonFieldsNameOfResultMetadata[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfPredictionResultMetadata) { + name = jsonFieldsNameOfPredictionResultMetadata[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -972,27 +972,27 @@ func (s *ResultMetadata) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *ResultMetadata) MarshalJSON() ([]byte, error) { +func (s *PredictionResultMetadata) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *ResultMetadata) UnmarshalJSON(data []byte) error { +func (s *PredictionResultMetadata) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *ResultPredictionItem) Encode(e *jx.Encoder) { +func (s *PredictionResultPredictionItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *ResultPredictionItem) encodeFields(e *jx.Encoder) { +func (s *PredictionResultPredictionItem) encodeFields(e *jx.Encoder) { { e.FieldStart("stage") s.Stage.Encode(e) @@ -1007,15 +1007,15 @@ func (s *ResultPredictionItem) encodeFields(e *jx.Encoder) { } } -var jsonFieldsNameOfResultPredictionItem = [2]string{ +var jsonFieldsNameOfPredictionResultPredictionItem = [2]string{ 0: "stage", 1: "trajectory", } -// Decode decodes ResultPredictionItem from json. -func (s *ResultPredictionItem) Decode(d *jx.Decoder) error { +// Decode decodes PredictionResultPredictionItem from json. +func (s *PredictionResultPredictionItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode ResultPredictionItem to nil") + return errors.New("invalid: unable to decode PredictionResultPredictionItem to nil") } var requiredBitSet [1]uint8 @@ -1034,9 +1034,9 @@ func (s *ResultPredictionItem) Decode(d *jx.Decoder) error { case "trajectory": requiredBitSet[0] |= 1 << 1 if err := func() error { - s.Trajectory = make([]ResultPredictionItemTrajectoryItem, 0) + s.Trajectory = make([]PredictionResultPredictionItemTrajectoryItem, 0) if err := d.Arr(func(d *jx.Decoder) error { - var elem ResultPredictionItemTrajectoryItem + var elem PredictionResultPredictionItemTrajectoryItem if err := elem.Decode(d); err != nil { return err } @@ -1054,7 +1054,7 @@ func (s *ResultPredictionItem) Decode(d *jx.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode ResultPredictionItem") + return errors.Wrap(err, "decode PredictionResultPredictionItem") } // Validate required fields. var failures []validate.FieldError @@ -1071,8 +1071,8 @@ func (s *ResultPredictionItem) Decode(d *jx.Decoder) error { bitIdx := bits.TrailingZeros8(result) fieldIdx := i*8 + bitIdx var name string - if fieldIdx < len(jsonFieldsNameOfResultPredictionItem) { - name = jsonFieldsNameOfResultPredictionItem[fieldIdx] + if fieldIdx < len(jsonFieldsNameOfPredictionResultPredictionItem) { + name = jsonFieldsNameOfPredictionResultPredictionItem[fieldIdx] } else { name = strconv.Itoa(fieldIdx) } @@ -1093,75 +1093,75 @@ func (s *ResultPredictionItem) Decode(d *jx.Decoder) error { } // MarshalJSON implements stdjson.Marshaler. -func (s *ResultPredictionItem) MarshalJSON() ([]byte, error) { +func (s *PredictionResultPredictionItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *ResultPredictionItem) UnmarshalJSON(data []byte) error { +func (s *PredictionResultPredictionItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } -// Encode encodes ResultPredictionItemStage as json. -func (s ResultPredictionItemStage) Encode(e *jx.Encoder) { +// Encode encodes PredictionResultPredictionItemStage as json. +func (s PredictionResultPredictionItemStage) Encode(e *jx.Encoder) { e.Str(string(s)) } -// Decode decodes ResultPredictionItemStage from json. -func (s *ResultPredictionItemStage) Decode(d *jx.Decoder) error { +// Decode decodes PredictionResultPredictionItemStage from json. +func (s *PredictionResultPredictionItemStage) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode ResultPredictionItemStage to nil") + return errors.New("invalid: unable to decode PredictionResultPredictionItemStage to nil") } v, err := d.StrBytes() if err != nil { return err } // Try to use constant string. - switch ResultPredictionItemStage(v) { - case ResultPredictionItemStageAscent: - *s = ResultPredictionItemStageAscent - case ResultPredictionItemStageDescent: - *s = ResultPredictionItemStageDescent + switch PredictionResultPredictionItemStage(v) { + case PredictionResultPredictionItemStageAscent: + *s = PredictionResultPredictionItemStageAscent + case PredictionResultPredictionItemStageDescent: + *s = PredictionResultPredictionItemStageDescent default: - *s = ResultPredictionItemStage(v) + *s = PredictionResultPredictionItemStage(v) } return nil } // MarshalJSON implements stdjson.Marshaler. -func (s ResultPredictionItemStage) MarshalJSON() ([]byte, error) { +func (s PredictionResultPredictionItemStage) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *ResultPredictionItemStage) UnmarshalJSON(data []byte) error { +func (s *PredictionResultPredictionItemStage) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } // Encode implements json.Marshaler. -func (s *ResultPredictionItemTrajectoryItem) Encode(e *jx.Encoder) { +func (s *PredictionResultPredictionItemTrajectoryItem) Encode(e *jx.Encoder) { e.ObjStart() s.encodeFields(e) e.ObjEnd() } // encodeFields encodes fields. -func (s *ResultPredictionItemTrajectoryItem) encodeFields(e *jx.Encoder) { +func (s *PredictionResultPredictionItemTrajectoryItem) encodeFields(e *jx.Encoder) { } -var jsonFieldsNameOfResultPredictionItemTrajectoryItem = [0]string{} +var jsonFieldsNameOfPredictionResultPredictionItemTrajectoryItem = [0]string{} -// Decode decodes ResultPredictionItemTrajectoryItem from json. -func (s *ResultPredictionItemTrajectoryItem) Decode(d *jx.Decoder) error { +// Decode decodes PredictionResultPredictionItemTrajectoryItem from json. +func (s *PredictionResultPredictionItemTrajectoryItem) Decode(d *jx.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode ResultPredictionItemTrajectoryItem to nil") + return errors.New("invalid: unable to decode PredictionResultPredictionItemTrajectoryItem to nil") } if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { @@ -1170,21 +1170,21 @@ func (s *ResultPredictionItemTrajectoryItem) Decode(d *jx.Decoder) error { return d.Skip() } }); err != nil { - return errors.Wrap(err, "decode ResultPredictionItemTrajectoryItem") + return errors.Wrap(err, "decode PredictionResultPredictionItemTrajectoryItem") } return nil } // MarshalJSON implements stdjson.Marshaler. -func (s *ResultPredictionItemTrajectoryItem) MarshalJSON() ([]byte, error) { +func (s *PredictionResultPredictionItemTrajectoryItem) MarshalJSON() ([]byte, error) { e := jx.Encoder{} s.Encode(&e) return e.Bytes(), nil } // UnmarshalJSON implements stdjson.Unmarshaler. -func (s *ResultPredictionItemTrajectoryItem) UnmarshalJSON(data []byte) error { +func (s *PredictionResultPredictionItemTrajectoryItem) UnmarshalJSON(data []byte) error { d := jx.DecodeBytes(data) return s.Decode(d) } diff --git a/pkg/rest/oas_parameters_gen.go b/pkg/rest/oas_parameters_gen.go index afefaf8..6c3b0d7 100644 --- a/pkg/rest/oas_parameters_gen.go +++ b/pkg/rest/oas_parameters_gen.go @@ -12,7 +12,7 @@ import ( // PerformPredictionParams is parameters of performPrediction operation. type PerformPredictionParams struct { - Parameters OptParameters + Parameters OptPredictionParameters } func unpackPerformPredictionParams(packed middleware.Parameters) (params PerformPredictionParams) { @@ -22,7 +22,7 @@ func unpackPerformPredictionParams(packed middleware.Parameters) (params Perform In: "query", } if v, ok := packed[key]; ok { - params.Parameters = v.(OptParameters) + params.Parameters = v.(OptPredictionParameters) } } return params @@ -41,7 +41,7 @@ func decodePerformPredictionParams(args [0]string, argsEscaped bool, r *http.Req if err := q.HasParam(cfg); err == nil { if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - var paramsDotParametersVal Parameters + var paramsDotParametersVal PredictionParameters if err := func() error { return paramsDotParametersVal.DecodeURI(d) }(); err != nil { diff --git a/pkg/rest/oas_request_decoders_gen.go b/pkg/rest/oas_request_decoders_gen.go index 0f3e00d..1a68a60 100644 --- a/pkg/rest/oas_request_decoders_gen.go +++ b/pkg/rest/oas_request_decoders_gen.go @@ -15,7 +15,7 @@ import ( ) func (s *Server) decodePerformPredictionRequest(r *http.Request) ( - req OptParameters, + req OptPredictionParameters, close func() error, rerr error, ) { @@ -57,7 +57,7 @@ func (s *Server) decodePerformPredictionRequest(r *http.Request) ( d := jx.DecodeBytes(buf) - var request OptParameters + var request OptPredictionParameters if err := func() error { request.Reset() if err := request.Decode(d); err != nil { diff --git a/pkg/rest/oas_request_encoders_gen.go b/pkg/rest/oas_request_encoders_gen.go index 8b30faa..a387ab8 100644 --- a/pkg/rest/oas_request_encoders_gen.go +++ b/pkg/rest/oas_request_encoders_gen.go @@ -12,7 +12,7 @@ import ( ) func encodePerformPredictionRequest( - req OptParameters, + req OptPredictionParameters, r *http.Request, ) error { const contentType = "application/json" diff --git a/pkg/rest/oas_response_decoders_gen.go b/pkg/rest/oas_response_decoders_gen.go index 22a6d75..ad8cb3c 100644 --- a/pkg/rest/oas_response_decoders_gen.go +++ b/pkg/rest/oas_response_decoders_gen.go @@ -14,7 +14,7 @@ import ( "github.com/ogen-go/ogen/validate" ) -func decodePerformPredictionResponse(resp *http.Response) (res *Result, _ error) { +func decodePerformPredictionResponse(resp *http.Response) (res *PredictionResult, _ error) { switch resp.StatusCode { case 200: // Code 200. @@ -30,7 +30,7 @@ func decodePerformPredictionResponse(resp *http.Response) (res *Result, _ error) } d := jx.DecodeBytes(buf) - var response Result + var response PredictionResult if err := func() error { if err := response.Decode(d); err != nil { return err diff --git a/pkg/rest/oas_response_encoders_gen.go b/pkg/rest/oas_response_encoders_gen.go index 456cb76..d944b45 100644 --- a/pkg/rest/oas_response_encoders_gen.go +++ b/pkg/rest/oas_response_encoders_gen.go @@ -13,7 +13,7 @@ import ( ht "github.com/ogen-go/ogen/http" ) -func encodePerformPredictionResponse(response *Result, w http.ResponseWriter, span trace.Span) error { +func encodePerformPredictionResponse(response *PredictionResult, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) span.SetStatus(codes.Ok, http.StatusText(200)) diff --git a/pkg/rest/oas_schemas_gen.go b/pkg/rest/oas_schemas_gen.go index 5aa7de5..f7fcd59 100644 --- a/pkg/rest/oas_schemas_gen.go +++ b/pkg/rest/oas_schemas_gen.go @@ -203,38 +203,38 @@ func (o OptFloat64) Or(d float64) float64 { return d } -// NewOptParameters returns new OptParameters with value set to v. -func NewOptParameters(v Parameters) OptParameters { - return OptParameters{ +// NewOptPredictionParameters returns new OptPredictionParameters with value set to v. +func NewOptPredictionParameters(v PredictionParameters) OptPredictionParameters { + return OptPredictionParameters{ Value: v, Set: true, } } -// OptParameters is optional Parameters. -type OptParameters struct { - Value Parameters +// OptPredictionParameters is optional PredictionParameters. +type OptPredictionParameters struct { + Value PredictionParameters Set bool } -// IsSet returns true if OptParameters was set. -func (o OptParameters) IsSet() bool { return o.Set } +// IsSet returns true if OptPredictionParameters was set. +func (o OptPredictionParameters) IsSet() bool { return o.Set } // Reset unsets value. -func (o *OptParameters) Reset() { - var v Parameters +func (o *OptPredictionParameters) Reset() { + var v PredictionParameters o.Value = v o.Set = false } // SetTo sets value to v. -func (o *OptParameters) SetTo(v Parameters) { +func (o *OptPredictionParameters) SetTo(v PredictionParameters) { o.Set = true o.Value = v } // Get returns value and boolean that denotes whether value was set. -func (o OptParameters) Get() (v Parameters, ok bool) { +func (o OptPredictionParameters) Get() (v PredictionParameters, ok bool) { if !o.Set { return v, false } @@ -242,45 +242,45 @@ func (o OptParameters) Get() (v Parameters, ok bool) { } // Or returns value if set, or given parameter if does not. -func (o OptParameters) Or(d Parameters) Parameters { +func (o OptPredictionParameters) Or(d PredictionParameters) PredictionParameters { if v, ok := o.Get(); ok { return v } return d } -// NewOptParametersFormat returns new OptParametersFormat with value set to v. -func NewOptParametersFormat(v ParametersFormat) OptParametersFormat { - return OptParametersFormat{ +// NewOptPredictionParametersFormat returns new OptPredictionParametersFormat with value set to v. +func NewOptPredictionParametersFormat(v PredictionParametersFormat) OptPredictionParametersFormat { + return OptPredictionParametersFormat{ Value: v, Set: true, } } -// OptParametersFormat is optional ParametersFormat. -type OptParametersFormat struct { - Value ParametersFormat +// OptPredictionParametersFormat is optional PredictionParametersFormat. +type OptPredictionParametersFormat struct { + Value PredictionParametersFormat Set bool } -// IsSet returns true if OptParametersFormat was set. -func (o OptParametersFormat) IsSet() bool { return o.Set } +// IsSet returns true if OptPredictionParametersFormat was set. +func (o OptPredictionParametersFormat) IsSet() bool { return o.Set } // Reset unsets value. -func (o *OptParametersFormat) Reset() { - var v ParametersFormat +func (o *OptPredictionParametersFormat) Reset() { + var v PredictionParametersFormat o.Value = v o.Set = false } // SetTo sets value to v. -func (o *OptParametersFormat) SetTo(v ParametersFormat) { +func (o *OptPredictionParametersFormat) SetTo(v PredictionParametersFormat) { o.Set = true o.Value = v } // Get returns value and boolean that denotes whether value was set. -func (o OptParametersFormat) Get() (v ParametersFormat, ok bool) { +func (o OptPredictionParametersFormat) Get() (v PredictionParametersFormat, ok bool) { if !o.Set { return v, false } @@ -288,45 +288,45 @@ func (o OptParametersFormat) Get() (v ParametersFormat, ok bool) { } // Or returns value if set, or given parameter if does not. -func (o OptParametersFormat) Or(d ParametersFormat) ParametersFormat { +func (o OptPredictionParametersFormat) Or(d PredictionParametersFormat) PredictionParametersFormat { if v, ok := o.Get(); ok { return v } return d } -// NewOptParametersProfile returns new OptParametersProfile with value set to v. -func NewOptParametersProfile(v ParametersProfile) OptParametersProfile { - return OptParametersProfile{ +// NewOptPredictionParametersProfile returns new OptPredictionParametersProfile with value set to v. +func NewOptPredictionParametersProfile(v PredictionParametersProfile) OptPredictionParametersProfile { + return OptPredictionParametersProfile{ Value: v, Set: true, } } -// OptParametersProfile is optional ParametersProfile. -type OptParametersProfile struct { - Value ParametersProfile +// OptPredictionParametersProfile is optional PredictionParametersProfile. +type OptPredictionParametersProfile struct { + Value PredictionParametersProfile Set bool } -// IsSet returns true if OptParametersProfile was set. -func (o OptParametersProfile) IsSet() bool { return o.Set } +// IsSet returns true if OptPredictionParametersProfile was set. +func (o OptPredictionParametersProfile) IsSet() bool { return o.Set } // Reset unsets value. -func (o *OptParametersProfile) Reset() { - var v ParametersProfile +func (o *OptPredictionParametersProfile) Reset() { + var v PredictionParametersProfile o.Value = v o.Set = false } // SetTo sets value to v. -func (o *OptParametersProfile) SetTo(v ParametersProfile) { +func (o *OptPredictionParametersProfile) SetTo(v PredictionParametersProfile) { o.Set = true o.Value = v } // Get returns value and boolean that denotes whether value was set. -func (o OptParametersProfile) Get() (v ParametersProfile, ok bool) { +func (o OptPredictionParametersProfile) Get() (v PredictionParametersProfile, ok bool) { if !o.Set { return v, false } @@ -334,7 +334,7 @@ func (o OptParametersProfile) Get() (v ParametersProfile, ok bool) { } // Or returns value if set, or given parameter if does not. -func (o OptParametersProfile) Or(d ParametersProfile) ParametersProfile { +func (o OptPredictionParametersProfile) Or(d PredictionParametersProfile) PredictionParametersProfile { if v, ok := o.Get(); ok { return v } @@ -387,194 +387,194 @@ func (o OptString) Or(d string) string { return d } -// Ref: #/components/schemas/Prediction/Parameters -type Parameters struct { - LaunchLatitude OptFloat64 `json:"launch_latitude"` - LaunchLongitude OptFloat64 `json:"launch_longitude"` - LaunchDatetime OptDateTime `json:"launch_datetime"` - LaunchAltitude OptFloat64 `json:"launch_altitude"` - Profile OptParametersProfile `json:"profile"` - AscentRate OptFloat64 `json:"ascent_rate"` - BurstAltitude OptFloat64 `json:"burst_altitude"` - DescentRate OptFloat64 `json:"descent_rate"` - FloatAltitude OptFloat64 `json:"float_altitude"` - StopDatetime OptDateTime `json:"stop_datetime"` +// Ref: #/components/schemas/PredictionParameters +type PredictionParameters struct { + LaunchLatitude OptFloat64 `json:"launch_latitude"` + LaunchLongitude OptFloat64 `json:"launch_longitude"` + LaunchDatetime OptDateTime `json:"launch_datetime"` + LaunchAltitude OptFloat64 `json:"launch_altitude"` + Profile OptPredictionParametersProfile `json:"profile"` + AscentRate OptFloat64 `json:"ascent_rate"` + BurstAltitude OptFloat64 `json:"burst_altitude"` + DescentRate OptFloat64 `json:"descent_rate"` + FloatAltitude OptFloat64 `json:"float_altitude"` + StopDatetime OptDateTime `json:"stop_datetime"` // Base64 encoded ascent curve. AscentCurve OptString `json:"ascent_curve"` // Base64 encoded descent curve. - DescentCurve OptString `json:"descent_curve"` - Interpolate OptBool `json:"interpolate"` - Format OptParametersFormat `json:"format"` - Dataset OptDateTime `json:"dataset"` + DescentCurve OptString `json:"descent_curve"` + Interpolate OptBool `json:"interpolate"` + Format OptPredictionParametersFormat `json:"format"` + Dataset OptDateTime `json:"dataset"` } // GetLaunchLatitude returns the value of LaunchLatitude. -func (s *Parameters) GetLaunchLatitude() OptFloat64 { +func (s *PredictionParameters) GetLaunchLatitude() OptFloat64 { return s.LaunchLatitude } // GetLaunchLongitude returns the value of LaunchLongitude. -func (s *Parameters) GetLaunchLongitude() OptFloat64 { +func (s *PredictionParameters) GetLaunchLongitude() OptFloat64 { return s.LaunchLongitude } // GetLaunchDatetime returns the value of LaunchDatetime. -func (s *Parameters) GetLaunchDatetime() OptDateTime { +func (s *PredictionParameters) GetLaunchDatetime() OptDateTime { return s.LaunchDatetime } // GetLaunchAltitude returns the value of LaunchAltitude. -func (s *Parameters) GetLaunchAltitude() OptFloat64 { +func (s *PredictionParameters) GetLaunchAltitude() OptFloat64 { return s.LaunchAltitude } // GetProfile returns the value of Profile. -func (s *Parameters) GetProfile() OptParametersProfile { +func (s *PredictionParameters) GetProfile() OptPredictionParametersProfile { return s.Profile } // GetAscentRate returns the value of AscentRate. -func (s *Parameters) GetAscentRate() OptFloat64 { +func (s *PredictionParameters) GetAscentRate() OptFloat64 { return s.AscentRate } // GetBurstAltitude returns the value of BurstAltitude. -func (s *Parameters) GetBurstAltitude() OptFloat64 { +func (s *PredictionParameters) GetBurstAltitude() OptFloat64 { return s.BurstAltitude } // GetDescentRate returns the value of DescentRate. -func (s *Parameters) GetDescentRate() OptFloat64 { +func (s *PredictionParameters) GetDescentRate() OptFloat64 { return s.DescentRate } // GetFloatAltitude returns the value of FloatAltitude. -func (s *Parameters) GetFloatAltitude() OptFloat64 { +func (s *PredictionParameters) GetFloatAltitude() OptFloat64 { return s.FloatAltitude } // GetStopDatetime returns the value of StopDatetime. -func (s *Parameters) GetStopDatetime() OptDateTime { +func (s *PredictionParameters) GetStopDatetime() OptDateTime { return s.StopDatetime } // GetAscentCurve returns the value of AscentCurve. -func (s *Parameters) GetAscentCurve() OptString { +func (s *PredictionParameters) GetAscentCurve() OptString { return s.AscentCurve } // GetDescentCurve returns the value of DescentCurve. -func (s *Parameters) GetDescentCurve() OptString { +func (s *PredictionParameters) GetDescentCurve() OptString { return s.DescentCurve } // GetInterpolate returns the value of Interpolate. -func (s *Parameters) GetInterpolate() OptBool { +func (s *PredictionParameters) GetInterpolate() OptBool { return s.Interpolate } // GetFormat returns the value of Format. -func (s *Parameters) GetFormat() OptParametersFormat { +func (s *PredictionParameters) GetFormat() OptPredictionParametersFormat { return s.Format } // GetDataset returns the value of Dataset. -func (s *Parameters) GetDataset() OptDateTime { +func (s *PredictionParameters) GetDataset() OptDateTime { return s.Dataset } // SetLaunchLatitude sets the value of LaunchLatitude. -func (s *Parameters) SetLaunchLatitude(val OptFloat64) { +func (s *PredictionParameters) SetLaunchLatitude(val OptFloat64) { s.LaunchLatitude = val } // SetLaunchLongitude sets the value of LaunchLongitude. -func (s *Parameters) SetLaunchLongitude(val OptFloat64) { +func (s *PredictionParameters) SetLaunchLongitude(val OptFloat64) { s.LaunchLongitude = val } // SetLaunchDatetime sets the value of LaunchDatetime. -func (s *Parameters) SetLaunchDatetime(val OptDateTime) { +func (s *PredictionParameters) SetLaunchDatetime(val OptDateTime) { s.LaunchDatetime = val } // SetLaunchAltitude sets the value of LaunchAltitude. -func (s *Parameters) SetLaunchAltitude(val OptFloat64) { +func (s *PredictionParameters) SetLaunchAltitude(val OptFloat64) { s.LaunchAltitude = val } // SetProfile sets the value of Profile. -func (s *Parameters) SetProfile(val OptParametersProfile) { +func (s *PredictionParameters) SetProfile(val OptPredictionParametersProfile) { s.Profile = val } // SetAscentRate sets the value of AscentRate. -func (s *Parameters) SetAscentRate(val OptFloat64) { +func (s *PredictionParameters) SetAscentRate(val OptFloat64) { s.AscentRate = val } // SetBurstAltitude sets the value of BurstAltitude. -func (s *Parameters) SetBurstAltitude(val OptFloat64) { +func (s *PredictionParameters) SetBurstAltitude(val OptFloat64) { s.BurstAltitude = val } // SetDescentRate sets the value of DescentRate. -func (s *Parameters) SetDescentRate(val OptFloat64) { +func (s *PredictionParameters) SetDescentRate(val OptFloat64) { s.DescentRate = val } // SetFloatAltitude sets the value of FloatAltitude. -func (s *Parameters) SetFloatAltitude(val OptFloat64) { +func (s *PredictionParameters) SetFloatAltitude(val OptFloat64) { s.FloatAltitude = val } // SetStopDatetime sets the value of StopDatetime. -func (s *Parameters) SetStopDatetime(val OptDateTime) { +func (s *PredictionParameters) SetStopDatetime(val OptDateTime) { s.StopDatetime = val } // SetAscentCurve sets the value of AscentCurve. -func (s *Parameters) SetAscentCurve(val OptString) { +func (s *PredictionParameters) SetAscentCurve(val OptString) { s.AscentCurve = val } // SetDescentCurve sets the value of DescentCurve. -func (s *Parameters) SetDescentCurve(val OptString) { +func (s *PredictionParameters) SetDescentCurve(val OptString) { s.DescentCurve = val } // SetInterpolate sets the value of Interpolate. -func (s *Parameters) SetInterpolate(val OptBool) { +func (s *PredictionParameters) SetInterpolate(val OptBool) { s.Interpolate = val } // SetFormat sets the value of Format. -func (s *Parameters) SetFormat(val OptParametersFormat) { +func (s *PredictionParameters) SetFormat(val OptPredictionParametersFormat) { s.Format = val } // SetDataset sets the value of Dataset. -func (s *Parameters) SetDataset(val OptDateTime) { +func (s *PredictionParameters) SetDataset(val OptDateTime) { s.Dataset = val } -type ParametersFormat string +type PredictionParametersFormat string const ( - ParametersFormatJSON ParametersFormat = "json" + PredictionParametersFormatJSON PredictionParametersFormat = "json" ) -// AllValues returns all ParametersFormat values. -func (ParametersFormat) AllValues() []ParametersFormat { - return []ParametersFormat{ - ParametersFormatJSON, +// AllValues returns all PredictionParametersFormat values. +func (PredictionParametersFormat) AllValues() []PredictionParametersFormat { + return []PredictionParametersFormat{ + PredictionParametersFormatJSON, } } // MarshalText implements encoding.TextMarshaler. -func (s ParametersFormat) MarshalText() ([]byte, error) { +func (s PredictionParametersFormat) MarshalText() ([]byte, error) { switch s { - case ParametersFormatJSON: + case PredictionParametersFormatJSON: return []byte(s), nil default: return nil, errors.Errorf("invalid value: %q", s) @@ -582,45 +582,45 @@ func (s ParametersFormat) MarshalText() ([]byte, error) { } // UnmarshalText implements encoding.TextUnmarshaler. -func (s *ParametersFormat) UnmarshalText(data []byte) error { - switch ParametersFormat(data) { - case ParametersFormatJSON: - *s = ParametersFormatJSON +func (s *PredictionParametersFormat) UnmarshalText(data []byte) error { + switch PredictionParametersFormat(data) { + case PredictionParametersFormatJSON: + *s = PredictionParametersFormatJSON return nil default: return errors.Errorf("invalid value: %q", data) } } -type ParametersProfile string +type PredictionParametersProfile string const ( - ParametersProfileStandardProfile ParametersProfile = "standard_profile" - ParametersProfileFloatProfile ParametersProfile = "float_profile" - ParametersProfileReverseProfile ParametersProfile = "reverse_profile" - ParametersProfileCustomProfile ParametersProfile = "custom_profile" + PredictionParametersProfileStandardProfile PredictionParametersProfile = "standard_profile" + PredictionParametersProfileFloatProfile PredictionParametersProfile = "float_profile" + PredictionParametersProfileReverseProfile PredictionParametersProfile = "reverse_profile" + PredictionParametersProfileCustomProfile PredictionParametersProfile = "custom_profile" ) -// AllValues returns all ParametersProfile values. -func (ParametersProfile) AllValues() []ParametersProfile { - return []ParametersProfile{ - ParametersProfileStandardProfile, - ParametersProfileFloatProfile, - ParametersProfileReverseProfile, - ParametersProfileCustomProfile, +// AllValues returns all PredictionParametersProfile values. +func (PredictionParametersProfile) AllValues() []PredictionParametersProfile { + return []PredictionParametersProfile{ + PredictionParametersProfileStandardProfile, + PredictionParametersProfileFloatProfile, + PredictionParametersProfileReverseProfile, + PredictionParametersProfileCustomProfile, } } // MarshalText implements encoding.TextMarshaler. -func (s ParametersProfile) MarshalText() ([]byte, error) { +func (s PredictionParametersProfile) MarshalText() ([]byte, error) { switch s { - case ParametersProfileStandardProfile: + case PredictionParametersProfileStandardProfile: return []byte(s), nil - case ParametersProfileFloatProfile: + case PredictionParametersProfileFloatProfile: return []byte(s), nil - case ParametersProfileReverseProfile: + case PredictionParametersProfileReverseProfile: return []byte(s), nil - case ParametersProfileCustomProfile: + case PredictionParametersProfileCustomProfile: return []byte(s), nil default: return nil, errors.Errorf("invalid value: %q", s) @@ -628,122 +628,122 @@ func (s ParametersProfile) MarshalText() ([]byte, error) { } // UnmarshalText implements encoding.TextUnmarshaler. -func (s *ParametersProfile) UnmarshalText(data []byte) error { - switch ParametersProfile(data) { - case ParametersProfileStandardProfile: - *s = ParametersProfileStandardProfile +func (s *PredictionParametersProfile) UnmarshalText(data []byte) error { + switch PredictionParametersProfile(data) { + case PredictionParametersProfileStandardProfile: + *s = PredictionParametersProfileStandardProfile return nil - case ParametersProfileFloatProfile: - *s = ParametersProfileFloatProfile + case PredictionParametersProfileFloatProfile: + *s = PredictionParametersProfileFloatProfile return nil - case ParametersProfileReverseProfile: - *s = ParametersProfileReverseProfile + case PredictionParametersProfileReverseProfile: + *s = PredictionParametersProfileReverseProfile return nil - case ParametersProfileCustomProfile: - *s = ParametersProfileCustomProfile + case PredictionParametersProfileCustomProfile: + *s = PredictionParametersProfileCustomProfile return nil default: return errors.Errorf("invalid value: %q", data) } } -// Ref: #/components/schemas/Prediction/Result -type Result struct { - Metadata ResultMetadata `json:"metadata"` - Prediction []ResultPredictionItem `json:"prediction"` +// Ref: #/components/schemas/PredictionResult +type PredictionResult struct { + Metadata PredictionResultMetadata `json:"metadata"` + Prediction []PredictionResultPredictionItem `json:"prediction"` } // GetMetadata returns the value of Metadata. -func (s *Result) GetMetadata() ResultMetadata { +func (s *PredictionResult) GetMetadata() PredictionResultMetadata { return s.Metadata } // GetPrediction returns the value of Prediction. -func (s *Result) GetPrediction() []ResultPredictionItem { +func (s *PredictionResult) GetPrediction() []PredictionResultPredictionItem { return s.Prediction } // SetMetadata sets the value of Metadata. -func (s *Result) SetMetadata(val ResultMetadata) { +func (s *PredictionResult) SetMetadata(val PredictionResultMetadata) { s.Metadata = val } // SetPrediction sets the value of Prediction. -func (s *Result) SetPrediction(val []ResultPredictionItem) { +func (s *PredictionResult) SetPrediction(val []PredictionResultPredictionItem) { s.Prediction = val } -type ResultMetadata struct { +type PredictionResultMetadata struct { CompleteDatetime time.Time `json:"complete_datetime"` StartDatetime time.Time `json:"start_datetime"` } // GetCompleteDatetime returns the value of CompleteDatetime. -func (s *ResultMetadata) GetCompleteDatetime() time.Time { +func (s *PredictionResultMetadata) GetCompleteDatetime() time.Time { return s.CompleteDatetime } // GetStartDatetime returns the value of StartDatetime. -func (s *ResultMetadata) GetStartDatetime() time.Time { +func (s *PredictionResultMetadata) GetStartDatetime() time.Time { return s.StartDatetime } // SetCompleteDatetime sets the value of CompleteDatetime. -func (s *ResultMetadata) SetCompleteDatetime(val time.Time) { +func (s *PredictionResultMetadata) SetCompleteDatetime(val time.Time) { s.CompleteDatetime = val } // SetStartDatetime sets the value of StartDatetime. -func (s *ResultMetadata) SetStartDatetime(val time.Time) { +func (s *PredictionResultMetadata) SetStartDatetime(val time.Time) { s.StartDatetime = val } -type ResultPredictionItem struct { - Stage ResultPredictionItemStage `json:"stage"` - Trajectory []ResultPredictionItemTrajectoryItem `json:"trajectory"` +type PredictionResultPredictionItem struct { + Stage PredictionResultPredictionItemStage `json:"stage"` + Trajectory []PredictionResultPredictionItemTrajectoryItem `json:"trajectory"` } // GetStage returns the value of Stage. -func (s *ResultPredictionItem) GetStage() ResultPredictionItemStage { +func (s *PredictionResultPredictionItem) GetStage() PredictionResultPredictionItemStage { return s.Stage } // GetTrajectory returns the value of Trajectory. -func (s *ResultPredictionItem) GetTrajectory() []ResultPredictionItemTrajectoryItem { +func (s *PredictionResultPredictionItem) GetTrajectory() []PredictionResultPredictionItemTrajectoryItem { return s.Trajectory } // SetStage sets the value of Stage. -func (s *ResultPredictionItem) SetStage(val ResultPredictionItemStage) { +func (s *PredictionResultPredictionItem) SetStage(val PredictionResultPredictionItemStage) { s.Stage = val } // SetTrajectory sets the value of Trajectory. -func (s *ResultPredictionItem) SetTrajectory(val []ResultPredictionItemTrajectoryItem) { +func (s *PredictionResultPredictionItem) SetTrajectory(val []PredictionResultPredictionItemTrajectoryItem) { s.Trajectory = val } -type ResultPredictionItemStage string +type PredictionResultPredictionItemStage string const ( - ResultPredictionItemStageAscent ResultPredictionItemStage = "ascent" - ResultPredictionItemStageDescent ResultPredictionItemStage = "descent" + PredictionResultPredictionItemStageAscent PredictionResultPredictionItemStage = "ascent" + PredictionResultPredictionItemStageDescent PredictionResultPredictionItemStage = "descent" ) -// AllValues returns all ResultPredictionItemStage values. -func (ResultPredictionItemStage) AllValues() []ResultPredictionItemStage { - return []ResultPredictionItemStage{ - ResultPredictionItemStageAscent, - ResultPredictionItemStageDescent, +// AllValues returns all PredictionResultPredictionItemStage values. +func (PredictionResultPredictionItemStage) AllValues() []PredictionResultPredictionItemStage { + return []PredictionResultPredictionItemStage{ + PredictionResultPredictionItemStageAscent, + PredictionResultPredictionItemStageDescent, } } // MarshalText implements encoding.TextMarshaler. -func (s ResultPredictionItemStage) MarshalText() ([]byte, error) { +func (s PredictionResultPredictionItemStage) MarshalText() ([]byte, error) { switch s { - case ResultPredictionItemStageAscent: + case PredictionResultPredictionItemStageAscent: return []byte(s), nil - case ResultPredictionItemStageDescent: + case PredictionResultPredictionItemStageDescent: return []byte(s), nil default: return nil, errors.Errorf("invalid value: %q", s) @@ -751,17 +751,17 @@ func (s ResultPredictionItemStage) MarshalText() ([]byte, error) { } // UnmarshalText implements encoding.TextUnmarshaler. -func (s *ResultPredictionItemStage) UnmarshalText(data []byte) error { - switch ResultPredictionItemStage(data) { - case ResultPredictionItemStageAscent: - *s = ResultPredictionItemStageAscent +func (s *PredictionResultPredictionItemStage) UnmarshalText(data []byte) error { + switch PredictionResultPredictionItemStage(data) { + case PredictionResultPredictionItemStageAscent: + *s = PredictionResultPredictionItemStageAscent return nil - case ResultPredictionItemStageDescent: - *s = ResultPredictionItemStageDescent + case PredictionResultPredictionItemStageDescent: + *s = PredictionResultPredictionItemStageDescent return nil default: return errors.Errorf("invalid value: %q", data) } } -type ResultPredictionItemTrajectoryItem struct{} +type PredictionResultPredictionItemTrajectoryItem struct{} diff --git a/pkg/rest/oas_server_gen.go b/pkg/rest/oas_server_gen.go index bb4accc..50835d7 100644 --- a/pkg/rest/oas_server_gen.go +++ b/pkg/rest/oas_server_gen.go @@ -13,7 +13,7 @@ type Handler interface { // Perform preidction. // // POST /api/v1/prediction - PerformPrediction(ctx context.Context, req OptParameters, params PerformPredictionParams) (*Result, error) + PerformPrediction(ctx context.Context, req OptPredictionParameters, params PerformPredictionParams) (*PredictionResult, error) // NewError creates *ErrorStatusCode from error returned by handler. // // Used for common default response. diff --git a/pkg/rest/oas_unimplemented_gen.go b/pkg/rest/oas_unimplemented_gen.go index b87adb0..afc4fdd 100644 --- a/pkg/rest/oas_unimplemented_gen.go +++ b/pkg/rest/oas_unimplemented_gen.go @@ -18,7 +18,7 @@ var _ Handler = UnimplementedHandler{} // Perform preidction. // // POST /api/v1/prediction -func (UnimplementedHandler) PerformPrediction(ctx context.Context, req OptParameters, params PerformPredictionParams) (r *Result, _ error) { +func (UnimplementedHandler) PerformPrediction(ctx context.Context, req OptPredictionParameters, params PerformPredictionParams) (r *PredictionResult, _ error) { return r, ht.ErrNotImplemented } diff --git a/pkg/rest/oas_uri_gen.go b/pkg/rest/oas_uri_gen.go index 6c486e7..7990aa4 100644 --- a/pkg/rest/oas_uri_gen.go +++ b/pkg/rest/oas_uri_gen.go @@ -11,8 +11,8 @@ import ( "github.com/ogen-go/ogen/uri" ) -// EncodeURI encodes Parameters as URI form. -func (s *Parameters) EncodeURI(e uri.Encoder) error { +// EncodeURI encodes PredictionParameters as URI form. +func (s *PredictionParameters) EncodeURI(e uri.Encoder) error { if err := e.EncodeField("launch_latitude", func(e uri.Encoder) error { if val, ok := s.LaunchLatitude.Get(); ok { return e.EncodeValue(conv.Float64ToString(val)) @@ -136,7 +136,7 @@ func (s *Parameters) EncodeURI(e uri.Encoder) error { return nil } -var uriFieldsNameOfParameters = [15]string{ +var uriFieldsNameOfPredictionParameters = [15]string{ 0: "launch_latitude", 1: "launch_longitude", 2: "launch_datetime", @@ -154,10 +154,10 @@ var uriFieldsNameOfParameters = [15]string{ 14: "dataset", } -// DecodeURI decodes Parameters from URI form. -func (s *Parameters) DecodeURI(d uri.Decoder) error { +// DecodeURI decodes PredictionParameters from URI form. +func (s *PredictionParameters) DecodeURI(d uri.Decoder) error { if s == nil { - return errors.New("invalid: unable to decode Parameters to nil") + return errors.New("invalid: unable to decode PredictionParameters to nil") } s.setDefaults() @@ -261,7 +261,7 @@ func (s *Parameters) DecodeURI(d uri.Decoder) error { } case "profile": if err := func() error { - var sDotProfileVal ParametersProfile + var sDotProfileVal PredictionParametersProfile if err := func() error { val, err := d.DecodeValue() if err != nil { @@ -273,7 +273,7 @@ func (s *Parameters) DecodeURI(d uri.Decoder) error { return err } - sDotProfileVal = ParametersProfile(c) + sDotProfileVal = PredictionParametersProfile(c) return nil }(); err != nil { return err @@ -477,7 +477,7 @@ func (s *Parameters) DecodeURI(d uri.Decoder) error { } case "format": if err := func() error { - var sDotFormatVal ParametersFormat + var sDotFormatVal PredictionParametersFormat if err := func() error { val, err := d.DecodeValue() if err != nil { @@ -489,7 +489,7 @@ func (s *Parameters) DecodeURI(d uri.Decoder) error { return err } - sDotFormatVal = ParametersFormat(c) + sDotFormatVal = PredictionParametersFormat(c) return nil }(); err != nil { return err @@ -528,7 +528,7 @@ func (s *Parameters) DecodeURI(d uri.Decoder) error { } return nil }); err != nil { - return errors.Wrap(err, "decode Parameters") + return errors.Wrap(err, "decode PredictionParameters") } return nil diff --git a/pkg/rest/oas_validators_gen.go b/pkg/rest/oas_validators_gen.go index ee198cc..9933ab9 100644 --- a/pkg/rest/oas_validators_gen.go +++ b/pkg/rest/oas_validators_gen.go @@ -10,7 +10,7 @@ import ( "github.com/ogen-go/ogen/validate" ) -func (s *Parameters) Validate() error { +func (s *PredictionParameters) Validate() error { if s == nil { return validate.ErrNilPointer } @@ -184,7 +184,7 @@ func (s *Parameters) Validate() error { return nil } -func (s ParametersFormat) Validate() error { +func (s PredictionParametersFormat) Validate() error { switch s { case "json": return nil @@ -193,7 +193,7 @@ func (s ParametersFormat) Validate() error { } } -func (s ParametersProfile) Validate() error { +func (s PredictionParametersProfile) Validate() error { switch s { case "standard_profile": return nil @@ -208,7 +208,7 @@ func (s ParametersProfile) Validate() error { } } -func (s *Result) Validate() error { +func (s *PredictionResult) Validate() error { if s == nil { return validate.ErrNilPointer } @@ -248,7 +248,7 @@ func (s *Result) Validate() error { return nil } -func (s *ResultPredictionItem) Validate() error { +func (s *PredictionResultPredictionItem) Validate() error { if s == nil { return validate.ErrNilPointer } @@ -282,7 +282,7 @@ func (s *ResultPredictionItem) Validate() error { return nil } -func (s ResultPredictionItemStage) Validate() error { +func (s PredictionResultPredictionItemStage) Validate() error { switch s { case "ascent": return nil From 5240968c33fc342fbf9bebd0a87b4cf53d6456d0 Mon Sep 17 00:00:00 2001 From: "a.antonov" Date: Sat, 21 Jun 2025 23:11:38 +0300 Subject: [PATCH 3/4] feat: planned structure --- internal/pkg/grib/config.go | 22 ++++++++++++++++++++++ internal/pkg/grib/grib.go | 3 +++ internal/service/deps.go | 4 ++-- internal/service/service.go | 16 ++++++++++++++-- 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 internal/pkg/grib/config.go create mode 100644 internal/pkg/grib/grib.go diff --git a/internal/pkg/grib/config.go b/internal/pkg/grib/config.go new file mode 100644 index 0000000..c0804bf --- /dev/null +++ b/internal/pkg/grib/config.go @@ -0,0 +1,22 @@ +package downloader + +import ( + "fmt" + + env "github.com/caarlos0/env/v11" +) + +type Config struct { +} + +func NewConfig(servicePrefix string) (*Config, error) { + cfg := &Config{} + + if err := env.ParseWithOptions(cfg, env.Options{ + PrefixTagName: fmt.Sprintf("%s_GRIB_", servicePrefix), + }); err != nil { + return nil, err + } + + return cfg, nil +} diff --git a/internal/pkg/grib/grib.go b/internal/pkg/grib/grib.go new file mode 100644 index 0000000..320ac2a --- /dev/null +++ b/internal/pkg/grib/grib.go @@ -0,0 +1,3 @@ +package downloader + +// diff --git a/internal/service/deps.go b/internal/service/deps.go index 0becf3e..15f3945 100644 --- a/internal/service/deps.go +++ b/internal/service/deps.go @@ -11,6 +11,6 @@ type Redis interface { Get(key string) ([]byte, error) } -type Downloader interface { - Download(ctx context.Context) +type Grib interface { + Update(ctx context.Context) error } diff --git a/internal/service/service.go b/internal/service/service.go index 0ac3f89..4119bb5 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -1,10 +1,22 @@ package service +import ( + "context" +) + type Service struct { redis Redis downloader Downloader } -func New() *Service { - return &Service{} +func New(redis Redis, downloader Downloader) *Service { + return &Service{ + redis: redis, + downloader: downloader, + } +} + +// DownloadWeatherData downloads weather forecast data using the configured downloader +func (s *Service) DownloadWeatherData(ctx context.Context) error { + return s.downloader.Download(ctx) } From b9c1a98895fc119142f9a5ddcf255668fadb4ccf Mon Sep 17 00:00:00 2001 From: "a.antonov" Date: Sun, 22 Jun 2025 22:36:10 +0300 Subject: [PATCH 4/4] wip: grib --- go.mod | 2 + go.sum | 4 + internal/pkg/errcodes/errcodes.go | 8 +- internal/pkg/grib/cache.go | 40 ++++++++ internal/pkg/grib/config.go | 4 +- internal/pkg/grib/cube.go | 43 +++++++++ internal/pkg/grib/dataset.go | 6 ++ internal/pkg/grib/downloader.go | 69 +++++++++++++ internal/pkg/grib/extractor.go | 53 ++++++++++ internal/pkg/grib/grib.go | 155 +++++++++++++++++++++++++++++- internal/pkg/grib/pressure.go | 9 ++ internal/pkg/grib/util.go | 26 +++++ 12 files changed, 414 insertions(+), 5 deletions(-) create mode 100644 internal/pkg/grib/cache.go create mode 100644 internal/pkg/grib/cube.go create mode 100644 internal/pkg/grib/dataset.go create mode 100644 internal/pkg/grib/downloader.go create mode 100644 internal/pkg/grib/extractor.go create mode 100644 internal/pkg/grib/pressure.go create mode 100644 internal/pkg/grib/util.go diff --git a/go.mod b/go.mod index 6885f78..6d9ab2c 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( require ( github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/edsrzf/mmap-go v1.2.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-faster/yaml v0.4.6 // indirect @@ -23,6 +24,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/nilsmagnus/grib v1.2.8 // indirect github.com/segmentio/asm v1.2.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.uber.org/multierr v1.11.0 // indirect diff --git a/go.sum b/go.sum index e28db0e..64d966f 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/edsrzf/mmap-go v1.2.0 h1:hXLYlkbaPzt1SaQk+anYwKSRNhufIDCchSPkUD6dD84= +github.com/edsrzf/mmap-go v1.2.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -32,6 +34,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/nilsmagnus/grib v1.2.8 h1:H7ch/1/agaCqM3MC8hW1Ft+EJ+q2XB757uml/IfPvp4= +github.com/nilsmagnus/grib v1.2.8/go.mod h1:XHm+5zuoOk0NSIWaGmA3JaAxI4i50YvD1L1vz+aqPOQ= github.com/ogen-go/ogen v1.14.0 h1:TU1Nj4z9UBsAfTkf+IhuNNp7igdFQKqkk9+6/y4XuWg= github.com/ogen-go/ogen v1.14.0/go.mod h1:Iw1vkqkx6SU7I9th5ceP+fVPJ6Wge4e3kAVzAxJEpPE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/internal/pkg/errcodes/errcodes.go b/internal/pkg/errcodes/errcodes.go index 245f508..32420c3 100644 --- a/internal/pkg/errcodes/errcodes.go +++ b/internal/pkg/errcodes/errcodes.go @@ -1,6 +1,7 @@ package errcodes import ( + "net/http" "strings" ) @@ -10,8 +11,6 @@ type ErrorCode struct { Details string } -var errorCodeCounter int32 - func New(statusCode int, message string, details ...string) *ErrorCode { return &ErrorCode{ StatusCode: statusCode, @@ -23,3 +22,8 @@ func New(statusCode int, message string, details ...string) *ErrorCode { func (e *ErrorCode) Error() string { return e.Message } + +var ( + ErrNoDataset = New(http.StatusNotFound, "no grib dataset found") + ErrOutOfBounds = New(http.StatusBadRequest, "requested time is out of bounds") +) diff --git a/internal/pkg/grib/cache.go b/internal/pkg/grib/cache.go new file mode 100644 index 0000000..9df0ff2 --- /dev/null +++ b/internal/pkg/grib/cache.go @@ -0,0 +1,40 @@ +package grib + +import ( + "encoding/binary" + "math" + "sync" + "time" +) + +type vec [2]float64 + +type item struct { + v vec + exp time.Time +} + +type memCache struct { + ttl time.Duration + m sync.Map +} + +func (c *memCache) get(k uint64) (vec, bool) { + if v, ok := c.m.Load(k); ok { + it := v.(item) + if time.Now().Before(it.exp) { + return it.v, true + } + c.m.Delete(k) + } + return vec{}, false +} + +func (c *memCache) set(k uint64, v vec) { c.m.Store(k, item{v, time.Now().Add(c.ttl)}) } + +func encodeVec(v vec) []byte { + var b [16]byte + binary.LittleEndian.PutUint64(b[:8], math.Float64bits(v[0])) + binary.LittleEndian.PutUint64(b[8:], math.Float64bits(v[1])) + return b[:] +} diff --git a/internal/pkg/grib/config.go b/internal/pkg/grib/config.go index c0804bf..065c688 100644 --- a/internal/pkg/grib/config.go +++ b/internal/pkg/grib/config.go @@ -1,12 +1,14 @@ -package downloader +package grib import ( "fmt" + "net/url" env "github.com/caarlos0/env/v11" ) type Config struct { + DatasetURL url.URL `env:"DATASET_URL"` } func NewConfig(servicePrefix string) (*Config, error) { diff --git a/internal/pkg/grib/cube.go b/internal/pkg/grib/cube.go new file mode 100644 index 0000000..6e8498f --- /dev/null +++ b/internal/pkg/grib/cube.go @@ -0,0 +1,43 @@ +package grib + +import ( + "encoding/binary" + "math" + "os" + + mmap "github.com/edsrzf/mmap-go" +) + +type cube struct { + mm mmap.MMap // read‑only, U followed by V (float32 LE) + t, p, lat, lon int + bytesPerVar int64 +} + +func openCube(path string) (*cube, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + + mm, err := mmap.Map(f, mmap.RDONLY, 0) + if err != nil { + return nil, err + } + + const ( + nT = 17 + nP = 34 + nLat = 361 + nLon = 720 + ) + + return &cube{mm: mm, t: nT, p: nP, lat: nLat, lon: nLon, bytesPerVar: int64(nT * nP * nLat * nLon * 4)}, nil +} + +func (c *cube) val(varIdx, ti, pi, y, x int) float32 { + idx := (((ti*c.p+pi)*c.lat + y) * c.lon) + x + off := int64(varIdx)*c.bytesPerVar + int64(idx)*4 + bits := binary.LittleEndian.Uint32(c.mm[off : off+4]) + return math.Float32frombits(bits) +} diff --git a/internal/pkg/grib/dataset.go b/internal/pkg/grib/dataset.go new file mode 100644 index 0000000..987da59 --- /dev/null +++ b/internal/pkg/grib/dataset.go @@ -0,0 +1,6 @@ +package grib + +type dataset struct { + cube *cube + runUTC int64 // unix seconds +} diff --git a/internal/pkg/grib/downloader.go b/internal/pkg/grib/downloader.go new file mode 100644 index 0000000..892d84b --- /dev/null +++ b/internal/pkg/grib/downloader.go @@ -0,0 +1,69 @@ +package grib + +import ( + "context" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "time" + + "golang.org/x/sync/errgroup" +) + +// NOMADS only. +const nomadsRoot = "https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod" + +type Downloader struct { + Dir string + Parallel int + Client *http.Client +} + +func (d *Downloader) fileURL(run string, hour int, step int) string { + return fmt.Sprintf("%s/gfs.%s/%02d/atmos/gfs.t%02dz.pgrb2.0p50.f%03d", nomadsRoot, run, hour, hour, step) +} + +func (d *Downloader) fetch(ctx context.Context, url, dst string) error { + if _, err := os.Stat(dst); err == nil { + return nil + } + tmp := dst + ".part" + f, err := os.Create(tmp) + if err != nil { + return err + } + defer f.Close() + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + resp, err := d.Client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("bad status %s", resp.Status) + } + if _, err := io.Copy(f, resp.Body); err != nil { + return err + } + return os.Rename(tmp, dst) +} + +func (d *Downloader) Run(ctx context.Context, run time.Time) error { + runStr := run.Format("20060102") + hour := run.Hour() + g, ctx := errgroup.WithContext(ctx) + sem := make(chan struct{}, d.Parallel) + for _, step := range steps { + step := step + sem <- struct{}{} + g.Go(func() error { + defer func() { <-sem }() + url := d.fileURL(runStr, hour, step) + dst := filepath.Join(d.Dir, fileName(run, step)) + return d.fetch(ctx, url, dst) + }) + } + return g.Wait() +} diff --git a/internal/pkg/grib/extractor.go b/internal/pkg/grib/extractor.go new file mode 100644 index 0000000..e56a52d --- /dev/null +++ b/internal/pkg/grib/extractor.go @@ -0,0 +1,53 @@ +package grib + +import "math" + +func lerp(a, b, t float64) float64 { return a + t*(b-a) } + +// Interpolate 16‑point (time, p, lat, lon) +func (d *dataset) uv(lat, lon, alt float64, tHours float64) (float64, float64) { + if lon < 0 { + lon += 360 + } + iy := (lat + 90) * 2 + y0 := int(math.Floor(iy)) + y1 := y0 + 1 + wy := iy - float64(y0) + ix := lon * 2 + x0 := int(math.Floor(ix)) % d.cube.lon + x1 := (x0 + 1) % d.cube.lon + wx := ix - float64(x0) + it0 := int(math.Floor(tHours / 3.0)) + wt := (tHours - float64(it0*3)) / 3.0 + p := pressureFromAlt(alt) + ip0 := 0 + for ip0+1 < len(pressureLevels) && pressureLevels[ip0+1] > p { + ip0++ + } + ip1 := ip0 + 1 + wp := (pressureLevels[ip0] - p) / (pressureLevels[ip0] - pressureLevels[ip1]) + fetch := func(ti, pi int) (float64, float64) { + u00 := d.cube.val(0, ti, pi, y0, x0) + u10 := d.cube.val(0, ti, pi, y0, x1) + u01 := d.cube.val(0, ti, pi, y1, x0) + u11 := d.cube.val(0, ti, pi, y1, x1) + v00 := d.cube.val(1, ti, pi, y0, x0) + v10 := d.cube.val(1, ti, pi, y0, x1) + v01 := d.cube.val(1, ti, pi, y1, x0) + v11 := d.cube.val(1, ti, pi, y1, x1) + uxy := (1-wy)*((1-wx)*float64(u00)+wx*float64(u10)) + wy*((1-wx)*float64(u01)+wx*float64(u11)) + vxy := (1-wy)*((1-wx)*float64(v00)+wx*float64(v10)) + wy*((1-wx)*float64(v01)+wx*float64(v11)) + return uxy, vxy + } + u0p0, v0p0 := fetch(it0, ip0) + u0p1, v0p1 := fetch(it0, ip1) + u1p0, v1p0 := fetch(it0+1, ip0) + u1p1, v1p1 := fetch(it0+1, ip1) + uLow := lerp(u0p0, u0p1, wp) + vLow := lerp(v0p0, v0p1, wp) + uHig := lerp(u1p0, u1p1, wp) + vHig := lerp(v1p0, v1p1, wp) + u := lerp(uLow, uHig, wt) + v := lerp(vLow, vHig, wt) + return u, v +} diff --git a/internal/pkg/grib/grib.go b/internal/pkg/grib/grib.go index 320ac2a..ff95e90 100644 --- a/internal/pkg/grib/grib.go +++ b/internal/pkg/grib/grib.go @@ -1,3 +1,154 @@ -package downloader +package grib -// +import ( + "context" + "encoding/binary" + "math" + "net/http" + "os" + "path/filepath" + "sync/atomic" + "time" + + "git.intra.yksa.space/gsn/predictor/internal/pkg/errcodes" + "github.com/edsrzf/mmap-go" + "github.com/nilsmagnus/grib/griblib" +) + +type RedisIface interface { + Lock(ctx context.Context, key string, ttl time.Duration) (func(context.Context), error) + Set(key string, value []byte, ttl time.Duration) error + Get(key string) ([]byte, error) +} + +type ServiceConfig struct { + Dir string + TTL time.Duration + CacheTTL time.Duration + Redis RedisIface + Parallel int + Client *http.Client +} + +type service struct { + cfg ServiceConfig + cache memCache + data atomic.Pointer[dataset] +} + +func New(cfg ServiceConfig) (*service, error) { + if cfg.TTL == 0 { + cfg.TTL = 24 * time.Hour + } + if err := os.MkdirAll(cfg.Dir, 0o755); err != nil { + return nil, err + } + s := &service{cfg: cfg, cache: memCache{ttl: cfg.CacheTTL}} + return s, nil +} + +// Update() downloads missing GRIBs, assembles cube into a single mmap‑file. +func (s *service) Update(ctx context.Context) error { + unlock, err := s.cfg.Redis.Lock(ctx, "grib-dl", 45*time.Minute) + if err != nil { + return err + } + defer unlock(ctx) + + dl := downloader.Downloader{Dir: s.cfg.Dir, Parallel: s.cfg.Parallel, Client: s.cfg.Client} + run := nearestRun(time.Now().UTC().Add(-4 * time.Hour)) + if err := dl.Run(ctx, run); err != nil { + return err + } + + cubePath := filepath.Join(s.cfg.Dir, run.Format("20060102_15")) + ".cube" + if _, err := os.Stat(cubePath); err != nil { + if err := assembleCube(s.cfg.Dir, run, cubePath); err != nil { + return err + } + } + c, err := openCube(cubePath) + if err != nil { + return err + } + ds := &dataset{cube: c, runUTC: run.Unix()} + s.data.Store(ds) + s.cache = memCache{ttl: s.cfg.CacheTTL} + return nil +} + +func assembleCube(dir string, run time.Time, cubePath string) error { + const sizePerVar = 17 * 34 * 361 * 720 * 4 + total := int64(sizePerVar * 2) + f, err := os.Create(cubePath) + if err != nil { + return err + } + if err := f.Truncate(total); err != nil { + return err + } + mm, err := mmap.MapRegion(f, int(total), mmap.RDWR, 0, 0) + if err != nil { + return err + } + defer mm.Unmap() + defer f.Close() + + pIndex := make(map[int]int) + for i, p := range pressureLevels { + pIndex[int(math.Round(p))] = i + } + + for ti, step := range steps { + fn := filepath.Join(dir, fileName(run, step)) + gf, err := griblib.Read(fn) + if err != nil { + return err + } + for _, m := range gf.Messages { + if m.ParameterShortName != "u" && m.ParameterShortName != "v" { + continue + } + if m.TypeOfFirstFixedSurface != 100 { + continue + } + pIdx, ok := pIndex[int(m.PressureLevel)] + if !ok { + continue + } + varIdx := 0 + if m.ParameterShortName == "v" { + varIdx = 1 + } + vals := m.Values + // GRIB library returns scan north->south, west->east already in row-major order + raw := make([]byte, len(vals)*4) + for i, v := range vals { + binary.LittleEndian.PutUint32(raw[i*4:], math.Float32bits(float32(v))) + } + base := int64(varIdx*sizePerVar + (ti*34+pIdx)*361*720*4) + copy(mm[base:base+int64(len(raw))], raw) + } + } + return mm.Flush() +} + +func (s *service) Extract(ctx context.Context, lat, lon, alt float64, ts time.Time) ([2]float64, error) { + var zero [2]float64 + d := s.data.Load() + if d == nil { + return zero, errcodes.ErrNoDataset + } + if ts.Before(time.Unix(d.runUTC, 0)) || ts.After(time.Unix(d.runUTC, 0).Add(48*time.Hour)) { + return zero, errcodes.ErrOutOfBounds + } + key := encodeKey(lat, lon, alt, ts) + if v, ok := s.cache.get(key); ok { + return [2]float64(v), nil + } + td := ts.Sub(time.Unix(d.runUTC, 0)).Hours() + u, v := d.uv(lat, lon, alt, td) + out := [2]float64{u, v} + s.cache.set(key, vec(out)) + return out, nil +} diff --git a/internal/pkg/grib/pressure.go b/internal/pkg/grib/pressure.go new file mode 100644 index 0000000..f0eff6d --- /dev/null +++ b/internal/pkg/grib/pressure.go @@ -0,0 +1,9 @@ +package grib + +import "math" + +var pressureLevels = []float64{1000, 975, 950, 925, 900, 875, 850, 825, 800, 775, 750, 725, 700, 650, 600, 550, 500, 450, 400, 350, 300, 250, 200, 150, 100, 70, 50, 30, 20, 10, 7, 5, 3, 2} + +func pressureFromAlt(alt float64) float64 { // ICAO ISA + return 1013.25 * math.Pow(1-alt/44307.69396, 5.255877) +} diff --git a/internal/pkg/grib/util.go b/internal/pkg/grib/util.go new file mode 100644 index 0000000..291c85e --- /dev/null +++ b/internal/pkg/grib/util.go @@ -0,0 +1,26 @@ +package grib + +import ( + "fmt" + "hash/fnv" + "time" +) + +var steps = []int{0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48} + +func nearestRun(t time.Time) time.Time { + h := t.UTC().Hour() - t.UTC().Hour()%6 + return time.Date(t.Year(), t.Month(), t.Day(), h, 0, 0, 0, time.UTC) +} + +func fileName(run time.Time, step int) string { + return fmt.Sprintf("gfs.t%02dz.pgrb2.0p50.f%03d", run.Hour(), step) +} + +func encodeKey(a ...any) uint64 { + h := fnv.New64a() + for _, v := range a { + fmt.Fprint(h, v) + } + return h.Sum64() +}