diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index 7c34512..5dfd115 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -24,12 +24,6 @@ import ( // Invoker invokes operations described by OpenAPI v3 specification. type Invoker interface { - // ActionSubmissionPublish invokes actionSubmissionPublish operation. - // - // (Internal endpoint) Role Validator changes status from Publishing -> Published. - // - // POST /submissions/{SubmissionID}/status/validator-published - ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error // ActionSubmissionReject invokes actionSubmissionReject operation. // // Role Reviewer changes status from Submitted -> Rejected. @@ -54,24 +48,18 @@ type Invoker interface { // // POST /submissions/{SubmissionID}/status/submit ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error - // ActionSubmissionTriggerPublish invokes actionSubmissionTriggerPublish operation. + // ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation. // - // Role Admin changes status from Validated -> Publishing. + // Role Admin changes status from Validated -> Uploading. // - // POST /submissions/{SubmissionID}/status/trigger-publish - ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error + // POST /submissions/{SubmissionID}/status/trigger-upload + ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error // ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation. // // Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating. // // POST /submissions/{SubmissionID}/status/trigger-validate ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error - // ActionSubmissionValidate invokes actionSubmissionValidate operation. - // - // (Internal endpoint) Role Validator changes status from Validating -> Validated. - // - // POST /submissions/{SubmissionID}/status/validator-validated - ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error // CreateScript invokes createScript operation. // // Create a new script. @@ -218,97 +206,6 @@ func (c *Client) requestURL(ctx context.Context) *url.URL { return u } -// ActionSubmissionPublish invokes actionSubmissionPublish operation. -// -// (Internal endpoint) Role Validator changes status from Publishing -> Published. -// -// POST /submissions/{SubmissionID}/status/validator-published -func (c *Client) ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error { - _, err := c.sendActionSubmissionPublish(ctx, params) - return err -} - -func (c *Client) sendActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) (res *ActionSubmissionPublishNoContent, err error) { - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("actionSubmissionPublish"), - semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-published"), - } - - // 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, ActionSubmissionPublishOperation, - 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 [3]string - pathParts[0] = "/submissions/" - { - // Encode "SubmissionID" parameter. - e := uri.NewPathEncoder(uri.PathEncoderConfig{ - Param: "SubmissionID", - Style: uri.PathStyleSimple, - Explode: false, - }) - if err := func() error { - return e.EncodeValue(conv.Int64ToString(params.SubmissionID)) - }(); err != nil { - return res, errors.Wrap(err, "encode path") - } - encoded, err := e.Result() - if err != nil { - return res, errors.Wrap(err, "encode path") - } - pathParts[1] = encoded - } - pathParts[2] = "/status/validator-published" - uri.AddPathParts(u, pathParts[:]...) - - stage = "EncodeRequest" - r, err := ht.NewRequest(ctx, "POST", u) - if err != nil { - return res, errors.Wrap(err, "create 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 := decodeActionSubmissionPublishResponse(resp) - if err != nil { - return res, errors.Wrap(err, "decode response") - } - - return result, nil -} - // ActionSubmissionReject invokes actionSubmissionReject operation. // // Role Reviewer changes status from Submitted -> Rejected. @@ -805,21 +702,21 @@ func (c *Client) sendActionSubmissionSubmit(ctx context.Context, params ActionSu return result, nil } -// ActionSubmissionTriggerPublish invokes actionSubmissionTriggerPublish operation. +// ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation. // -// Role Admin changes status from Validated -> Publishing. +// Role Admin changes status from Validated -> Uploading. // -// POST /submissions/{SubmissionID}/status/trigger-publish -func (c *Client) ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error { - _, err := c.sendActionSubmissionTriggerPublish(ctx, params) +// POST /submissions/{SubmissionID}/status/trigger-upload +func (c *Client) ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error { + _, err := c.sendActionSubmissionTriggerUpload(ctx, params) return err } -func (c *Client) sendActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) (res *ActionSubmissionTriggerPublishNoContent, err error) { +func (c *Client) sendActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) (res *ActionSubmissionTriggerUploadNoContent, err error) { otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("actionSubmissionTriggerPublish"), + otelogen.OperationID("actionSubmissionTriggerUpload"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-publish"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-upload"), } // Run stopwatch. @@ -834,7 +731,7 @@ func (c *Client) sendActionSubmissionTriggerPublish(ctx context.Context, params c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) // Start a span for this request. - ctx, span := c.cfg.Tracer.Start(ctx, ActionSubmissionTriggerPublishOperation, + ctx, span := c.cfg.Tracer.Start(ctx, ActionSubmissionTriggerUploadOperation, trace.WithAttributes(otelAttrs...), clientSpanKind, ) @@ -871,7 +768,7 @@ func (c *Client) sendActionSubmissionTriggerPublish(ctx context.Context, params } pathParts[1] = encoded } - pathParts[2] = "/status/trigger-publish" + pathParts[2] = "/status/trigger-upload" uri.AddPathParts(u, pathParts[:]...) stage = "EncodeRequest" @@ -885,7 +782,7 @@ func (c *Client) sendActionSubmissionTriggerPublish(ctx context.Context, params var satisfied bitset { stage = "Security:CookieAuth" - switch err := c.securityCookieAuth(ctx, ActionSubmissionTriggerPublishOperation, r); { + switch err := c.securityCookieAuth(ctx, ActionSubmissionTriggerUploadOperation, r); { case err == nil: // if NO error satisfied[0] |= 1 << 0 case errors.Is(err, ogenerrors.ErrSkipClientSecurity): @@ -921,7 +818,7 @@ func (c *Client) sendActionSubmissionTriggerPublish(ctx context.Context, params defer resp.Body.Close() stage = "DecodeResponse" - result, err := decodeActionSubmissionTriggerPublishResponse(resp) + result, err := decodeActionSubmissionTriggerUploadResponse(resp) if err != nil { return res, errors.Wrap(err, "decode response") } @@ -1053,97 +950,6 @@ func (c *Client) sendActionSubmissionTriggerValidate(ctx context.Context, params return result, nil } -// ActionSubmissionValidate invokes actionSubmissionValidate operation. -// -// (Internal endpoint) Role Validator changes status from Validating -> Validated. -// -// POST /submissions/{SubmissionID}/status/validator-validated -func (c *Client) ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error { - _, err := c.sendActionSubmissionValidate(ctx, params) - return err -} - -func (c *Client) sendActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) (res *ActionSubmissionValidateNoContent, err error) { - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("actionSubmissionValidate"), - semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-validated"), - } - - // 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, ActionSubmissionValidateOperation, - 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 [3]string - pathParts[0] = "/submissions/" - { - // Encode "SubmissionID" parameter. - e := uri.NewPathEncoder(uri.PathEncoderConfig{ - Param: "SubmissionID", - Style: uri.PathStyleSimple, - Explode: false, - }) - if err := func() error { - return e.EncodeValue(conv.Int64ToString(params.SubmissionID)) - }(); err != nil { - return res, errors.Wrap(err, "encode path") - } - encoded, err := e.Result() - if err != nil { - return res, errors.Wrap(err, "encode path") - } - pathParts[1] = encoded - } - pathParts[2] = "/status/validator-validated" - uri.AddPathParts(u, pathParts[:]...) - - stage = "EncodeRequest" - r, err := ht.NewRequest(ctx, "POST", u) - if err != nil { - return res, errors.Wrap(err, "create 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 := decodeActionSubmissionValidateResponse(resp) - if err != nil { - return res, errors.Wrap(err, "decode response") - } - - return result, nil -} - // CreateScript invokes createScript operation. // // Create a new script. diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index f1e1ece..70afd7a 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -30,155 +30,6 @@ func (c *codeRecorder) WriteHeader(status int) { c.ResponseWriter.WriteHeader(status) } -// handleActionSubmissionPublishRequest handles actionSubmissionPublish operation. -// -// (Internal endpoint) Role Validator changes status from Publishing -> Published. -// -// POST /submissions/{SubmissionID}/status/validator-published -func (s *Server) handleActionSubmissionPublishRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { - statusWriter := &codeRecorder{ResponseWriter: w} - w = statusWriter - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("actionSubmissionPublish"), - semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-published"), - } - - // Start a span for this request. - ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionPublishOperation, - 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: ActionSubmissionPublishOperation, - ID: "actionSubmissionPublish", - } - ) - params, err := decodeActionSubmissionPublishParams(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 - } - - var response *ActionSubmissionPublishNoContent - if m := s.cfg.Middleware; m != nil { - mreq := middleware.Request{ - Context: ctx, - OperationName: ActionSubmissionPublishOperation, - OperationSummary: "(Internal endpoint) Role Validator changes status from Publishing -> Published", - OperationID: "actionSubmissionPublish", - Body: nil, - Params: middleware.Parameters{ - { - Name: "SubmissionID", - In: "path", - }: params.SubmissionID, - }, - Raw: r, - } - - type ( - Request = struct{} - Params = ActionSubmissionPublishParams - Response = *ActionSubmissionPublishNoContent - ) - response, err = middleware.HookMiddleware[ - Request, - Params, - Response, - ]( - m, - mreq, - unpackActionSubmissionPublishParams, - func(ctx context.Context, request Request, params Params) (response Response, err error) { - err = s.h.ActionSubmissionPublish(ctx, params) - return response, err - }, - ) - } else { - err = s.h.ActionSubmissionPublish(ctx, 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 := encodeActionSubmissionPublishResponse(response, w, span); err != nil { - defer recordError("EncodeResponse", err) - if !errors.Is(err, ht.ErrInternalServerErrorResponse) { - s.cfg.ErrorHandler(ctx, w, r, err) - } - return - } -} - // handleActionSubmissionRejectRequest handles actionSubmissionReject operation. // // Role Reviewer changes status from Submitted -> Rejected. @@ -959,22 +810,22 @@ func (s *Server) handleActionSubmissionSubmitRequest(args [1]string, argsEscaped } } -// handleActionSubmissionTriggerPublishRequest handles actionSubmissionTriggerPublish operation. +// handleActionSubmissionTriggerUploadRequest handles actionSubmissionTriggerUpload operation. // -// Role Admin changes status from Validated -> Publishing. +// Role Admin changes status from Validated -> Uploading. // -// POST /submissions/{SubmissionID}/status/trigger-publish -func (s *Server) handleActionSubmissionTriggerPublishRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { +// POST /submissions/{SubmissionID}/status/trigger-upload +func (s *Server) handleActionSubmissionTriggerUploadRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("actionSubmissionTriggerPublish"), + otelogen.OperationID("actionSubmissionTriggerUpload"), semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-publish"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-upload"), } // Start a span for this request. - ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionTriggerPublishOperation, + ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionTriggerUploadOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) @@ -1029,15 +880,15 @@ func (s *Server) handleActionSubmissionTriggerPublishRequest(args [1]string, arg } err error opErrContext = ogenerrors.OperationContext{ - Name: ActionSubmissionTriggerPublishOperation, - ID: "actionSubmissionTriggerPublish", + Name: ActionSubmissionTriggerUploadOperation, + ID: "actionSubmissionTriggerUpload", } ) { type bitset = [1]uint8 var satisfied bitset { - sctx, ok, err := s.securityCookieAuth(ctx, ActionSubmissionTriggerPublishOperation, r) + sctx, ok, err := s.securityCookieAuth(ctx, ActionSubmissionTriggerUploadOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, @@ -1079,7 +930,7 @@ func (s *Server) handleActionSubmissionTriggerPublishRequest(args [1]string, arg return } } - params, err := decodeActionSubmissionTriggerPublishParams(args, argsEscaped, r) + params, err := decodeActionSubmissionTriggerUploadParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, @@ -1090,13 +941,13 @@ func (s *Server) handleActionSubmissionTriggerPublishRequest(args [1]string, arg return } - var response *ActionSubmissionTriggerPublishNoContent + var response *ActionSubmissionTriggerUploadNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, - OperationName: ActionSubmissionTriggerPublishOperation, - OperationSummary: "Role Admin changes status from Validated -> Publishing", - OperationID: "actionSubmissionTriggerPublish", + OperationName: ActionSubmissionTriggerUploadOperation, + OperationSummary: "Role Admin changes status from Validated -> Uploading", + OperationID: "actionSubmissionTriggerUpload", Body: nil, Params: middleware.Parameters{ { @@ -1109,8 +960,8 @@ func (s *Server) handleActionSubmissionTriggerPublishRequest(args [1]string, arg type ( Request = struct{} - Params = ActionSubmissionTriggerPublishParams - Response = *ActionSubmissionTriggerPublishNoContent + Params = ActionSubmissionTriggerUploadParams + Response = *ActionSubmissionTriggerUploadNoContent ) response, err = middleware.HookMiddleware[ Request, @@ -1119,14 +970,14 @@ func (s *Server) handleActionSubmissionTriggerPublishRequest(args [1]string, arg ]( m, mreq, - unpackActionSubmissionTriggerPublishParams, + unpackActionSubmissionTriggerUploadParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { - err = s.h.ActionSubmissionTriggerPublish(ctx, params) + err = s.h.ActionSubmissionTriggerUpload(ctx, params) return response, err }, ) } else { - err = s.h.ActionSubmissionTriggerPublish(ctx, params) + err = s.h.ActionSubmissionTriggerUpload(ctx, params) } if err != nil { if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { @@ -1145,7 +996,7 @@ func (s *Server) handleActionSubmissionTriggerPublishRequest(args [1]string, arg return } - if err := encodeActionSubmissionTriggerPublishResponse(response, w, span); err != nil { + if err := encodeActionSubmissionTriggerUploadResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) @@ -1349,155 +1200,6 @@ func (s *Server) handleActionSubmissionTriggerValidateRequest(args [1]string, ar } } -// handleActionSubmissionValidateRequest handles actionSubmissionValidate operation. -// -// (Internal endpoint) Role Validator changes status from Validating -> Validated. -// -// POST /submissions/{SubmissionID}/status/validator-validated -func (s *Server) handleActionSubmissionValidateRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { - statusWriter := &codeRecorder{ResponseWriter: w} - w = statusWriter - otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("actionSubmissionValidate"), - semconv.HTTPRequestMethodKey.String("POST"), - semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-validated"), - } - - // Start a span for this request. - ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionValidateOperation, - 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: ActionSubmissionValidateOperation, - ID: "actionSubmissionValidate", - } - ) - params, err := decodeActionSubmissionValidateParams(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 - } - - var response *ActionSubmissionValidateNoContent - if m := s.cfg.Middleware; m != nil { - mreq := middleware.Request{ - Context: ctx, - OperationName: ActionSubmissionValidateOperation, - OperationSummary: "(Internal endpoint) Role Validator changes status from Validating -> Validated", - OperationID: "actionSubmissionValidate", - Body: nil, - Params: middleware.Parameters{ - { - Name: "SubmissionID", - In: "path", - }: params.SubmissionID, - }, - Raw: r, - } - - type ( - Request = struct{} - Params = ActionSubmissionValidateParams - Response = *ActionSubmissionValidateNoContent - ) - response, err = middleware.HookMiddleware[ - Request, - Params, - Response, - ]( - m, - mreq, - unpackActionSubmissionValidateParams, - func(ctx context.Context, request Request, params Params) (response Response, err error) { - err = s.h.ActionSubmissionValidate(ctx, params) - return response, err - }, - ) - } else { - err = s.h.ActionSubmissionValidate(ctx, 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 := encodeActionSubmissionValidateResponse(response, w, span); err != nil { - defer recordError("EncodeResponse", err) - if !errors.Is(err, ht.ErrInternalServerErrorResponse) { - s.cfg.ErrorHandler(ctx, w, r, err) - } - return - } -} - // handleCreateScriptRequest handles createScript operation. // // Create a new script. diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index 6288ee8..89bf5d3 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -6,14 +6,12 @@ package api type OperationName = string const ( - ActionSubmissionPublishOperation OperationName = "ActionSubmissionPublish" ActionSubmissionRejectOperation OperationName = "ActionSubmissionReject" ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges" ActionSubmissionRevokeOperation OperationName = "ActionSubmissionRevoke" ActionSubmissionSubmitOperation OperationName = "ActionSubmissionSubmit" - ActionSubmissionTriggerPublishOperation OperationName = "ActionSubmissionTriggerPublish" + ActionSubmissionTriggerUploadOperation OperationName = "ActionSubmissionTriggerUpload" ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate" - ActionSubmissionValidateOperation OperationName = "ActionSubmissionValidate" CreateScriptOperation OperationName = "CreateScript" CreateScriptPolicyOperation OperationName = "CreateScriptPolicy" CreateSubmissionOperation OperationName = "CreateSubmission" diff --git a/pkg/api/oas_parameters_gen.go b/pkg/api/oas_parameters_gen.go index a250aaa..7d01805 100644 --- a/pkg/api/oas_parameters_gen.go +++ b/pkg/api/oas_parameters_gen.go @@ -15,72 +15,6 @@ import ( "github.com/ogen-go/ogen/validate" ) -// ActionSubmissionPublishParams is parameters of actionSubmissionPublish operation. -type ActionSubmissionPublishParams struct { - // The unique identifier for a submission. - SubmissionID int64 -} - -func unpackActionSubmissionPublishParams(packed middleware.Parameters) (params ActionSubmissionPublishParams) { - { - key := middleware.ParameterKey{ - Name: "SubmissionID", - In: "path", - } - params.SubmissionID = packed[key].(int64) - } - return params -} - -func decodeActionSubmissionPublishParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionPublishParams, _ error) { - // Decode path: SubmissionID. - if err := func() error { - param := args[0] - if argsEscaped { - unescaped, err := url.PathUnescape(args[0]) - if err != nil { - return errors.Wrap(err, "unescape path") - } - param = unescaped - } - if len(param) > 0 { - d := uri.NewPathDecoder(uri.PathDecoderConfig{ - Param: "SubmissionID", - Value: param, - Style: uri.PathStyleSimple, - Explode: false, - }) - - if err := func() error { - val, err := d.DecodeValue() - if err != nil { - return err - } - - c, err := conv.ToInt64(val) - if err != nil { - return err - } - - params.SubmissionID = c - return nil - }(); err != nil { - return err - } - } else { - return validate.ErrFieldRequired - } - return nil - }(); err != nil { - return params, &ogenerrors.DecodeParamError{ - Name: "SubmissionID", - In: "path", - Err: err, - } - } - return params, nil -} - // ActionSubmissionRejectParams is parameters of actionSubmissionReject operation. type ActionSubmissionRejectParams struct { // The unique identifier for a submission. @@ -345,13 +279,13 @@ func decodeActionSubmissionSubmitParams(args [1]string, argsEscaped bool, r *htt return params, nil } -// ActionSubmissionTriggerPublishParams is parameters of actionSubmissionTriggerPublish operation. -type ActionSubmissionTriggerPublishParams struct { +// ActionSubmissionTriggerUploadParams is parameters of actionSubmissionTriggerUpload operation. +type ActionSubmissionTriggerUploadParams struct { // The unique identifier for a submission. SubmissionID int64 } -func unpackActionSubmissionTriggerPublishParams(packed middleware.Parameters) (params ActionSubmissionTriggerPublishParams) { +func unpackActionSubmissionTriggerUploadParams(packed middleware.Parameters) (params ActionSubmissionTriggerUploadParams) { { key := middleware.ParameterKey{ Name: "SubmissionID", @@ -362,7 +296,7 @@ func unpackActionSubmissionTriggerPublishParams(packed middleware.Parameters) (p return params } -func decodeActionSubmissionTriggerPublishParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionTriggerPublishParams, _ error) { +func decodeActionSubmissionTriggerUploadParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionTriggerUploadParams, _ error) { // Decode path: SubmissionID. if err := func() error { param := args[0] @@ -477,72 +411,6 @@ func decodeActionSubmissionTriggerValidateParams(args [1]string, argsEscaped boo return params, nil } -// ActionSubmissionValidateParams is parameters of actionSubmissionValidate operation. -type ActionSubmissionValidateParams struct { - // The unique identifier for a submission. - SubmissionID int64 -} - -func unpackActionSubmissionValidateParams(packed middleware.Parameters) (params ActionSubmissionValidateParams) { - { - key := middleware.ParameterKey{ - Name: "SubmissionID", - In: "path", - } - params.SubmissionID = packed[key].(int64) - } - return params -} - -func decodeActionSubmissionValidateParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionValidateParams, _ error) { - // Decode path: SubmissionID. - if err := func() error { - param := args[0] - if argsEscaped { - unescaped, err := url.PathUnescape(args[0]) - if err != nil { - return errors.Wrap(err, "unescape path") - } - param = unescaped - } - if len(param) > 0 { - d := uri.NewPathDecoder(uri.PathDecoderConfig{ - Param: "SubmissionID", - Value: param, - Style: uri.PathStyleSimple, - Explode: false, - }) - - if err := func() error { - val, err := d.DecodeValue() - if err != nil { - return err - } - - c, err := conv.ToInt64(val) - if err != nil { - return err - } - - params.SubmissionID = c - return nil - }(); err != nil { - return err - } - } else { - return validate.ErrFieldRequired - } - return nil - }(); err != nil { - return params, &ogenerrors.DecodeParamError{ - Name: "SubmissionID", - In: "path", - Err: err, - } - } - return params, nil -} - // DeleteScriptParams is parameters of deleteScript operation. type DeleteScriptParams struct { // The unique identifier for a script. diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index e58bd6d..4743df9 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -15,57 +15,6 @@ import ( "github.com/ogen-go/ogen/validate" ) -func decodeActionSubmissionPublishResponse(resp *http.Response) (res *ActionSubmissionPublishNoContent, _ error) { - switch resp.StatusCode { - case 204: - // Code 204. - return &ActionSubmissionPublishNoContent{}, nil - } - // 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") -} - func decodeActionSubmissionRejectResponse(resp *http.Response) (res *ActionSubmissionRejectNoContent, _ error) { switch resp.StatusCode { case 204: @@ -270,11 +219,11 @@ func decodeActionSubmissionSubmitResponse(resp *http.Response) (res *ActionSubmi return res, errors.Wrap(defRes, "error") } -func decodeActionSubmissionTriggerPublishResponse(resp *http.Response) (res *ActionSubmissionTriggerPublishNoContent, _ error) { +func decodeActionSubmissionTriggerUploadResponse(resp *http.Response) (res *ActionSubmissionTriggerUploadNoContent, _ error) { switch resp.StatusCode { case 204: // Code 204. - return &ActionSubmissionTriggerPublishNoContent{}, nil + return &ActionSubmissionTriggerUploadNoContent{}, nil } // Convenient error response. defRes, err := func() (res *ErrorStatusCode, err error) { @@ -372,57 +321,6 @@ func decodeActionSubmissionTriggerValidateResponse(resp *http.Response) (res *Ac return res, errors.Wrap(defRes, "error") } -func decodeActionSubmissionValidateResponse(resp *http.Response) (res *ActionSubmissionValidateNoContent, _ error) { - switch resp.StatusCode { - case 204: - // Code 204. - return &ActionSubmissionValidateNoContent{}, nil - } - // 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") -} - func decodeCreateScriptResponse(resp *http.Response) (res *ID, _ error) { switch resp.StatusCode { case 201: diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index cfd12f2..f27d572 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -13,13 +13,6 @@ import ( ht "github.com/ogen-go/ogen/http" ) -func encodeActionSubmissionPublishResponse(response *ActionSubmissionPublishNoContent, w http.ResponseWriter, span trace.Span) error { - w.WriteHeader(204) - span.SetStatus(codes.Ok, http.StatusText(204)) - - return nil -} - func encodeActionSubmissionRejectResponse(response *ActionSubmissionRejectNoContent, w http.ResponseWriter, span trace.Span) error { w.WriteHeader(204) span.SetStatus(codes.Ok, http.StatusText(204)) @@ -48,7 +41,7 @@ func encodeActionSubmissionSubmitResponse(response *ActionSubmissionSubmitNoCont return nil } -func encodeActionSubmissionTriggerPublishResponse(response *ActionSubmissionTriggerPublishNoContent, w http.ResponseWriter, span trace.Span) error { +func encodeActionSubmissionTriggerUploadResponse(response *ActionSubmissionTriggerUploadNoContent, w http.ResponseWriter, span trace.Span) error { w.WriteHeader(204) span.SetStatus(codes.Ok, http.StatusText(204)) @@ -62,13 +55,6 @@ func encodeActionSubmissionTriggerValidateResponse(response *ActionSubmissionTri return nil } -func encodeActionSubmissionValidateResponse(response *ActionSubmissionValidateNoContent, w http.ResponseWriter, span trace.Span) error { - w.WriteHeader(204) - span.SetStatus(codes.Ok, http.StatusText(204)) - - return nil -} - func encodeCreateScriptResponse(response *ID, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(201) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index e9a4b0c..b8fdfb2 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -477,9 +477,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } switch elem[0] { - case 'p': // Prefix: "publish" + case 'u': // Prefix: "upload" origElem := elem - if l := len("publish"); len(elem) >= l && elem[0:l] == "publish" { + if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" { elem = elem[l:] } else { break @@ -489,7 +489,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Leaf node. switch r.Method { case "POST": - s.handleActionSubmissionTriggerPublishRequest([1]string{ + s.handleActionSubmissionTriggerUploadRequest([1]string{ args[0], }, elemIsEscaped, w, r) default: @@ -525,67 +525,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { elem = origElem } - elem = origElem - case 'v': // Prefix: "validator-" - origElem := elem - if l := len("validator-"); len(elem) >= l && elem[0:l] == "validator-" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'p': // Prefix: "published" - origElem := elem - if l := len("published"); len(elem) >= l && elem[0:l] == "published" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionSubmissionPublishRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - elem = origElem - case 'v': // Prefix: "validated" - origElem := elem - if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "POST": - s.handleActionSubmissionValidateRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, "POST") - } - - return - } - - elem = origElem - } - elem = origElem } @@ -1170,9 +1109,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { break } switch elem[0] { - case 'p': // Prefix: "publish" + case 'u': // Prefix: "upload" origElem := elem - if l := len("publish"); len(elem) >= l && elem[0:l] == "publish" { + if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" { elem = elem[l:] } else { break @@ -1182,10 +1121,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { // Leaf node. switch method { case "POST": - r.name = ActionSubmissionTriggerPublishOperation - r.summary = "Role Admin changes status from Validated -> Publishing" - r.operationID = "actionSubmissionTriggerPublish" - r.pathPattern = "/submissions/{SubmissionID}/status/trigger-publish" + r.name = ActionSubmissionTriggerUploadOperation + r.summary = "Role Admin changes status from Validated -> Uploading" + r.operationID = "actionSubmissionTriggerUpload" + r.pathPattern = "/submissions/{SubmissionID}/status/trigger-upload" r.args = args r.count = 1 return r, true @@ -1222,71 +1161,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { elem = origElem } - elem = origElem - case 'v': // Prefix: "validator-" - origElem := elem - if l := len("validator-"); len(elem) >= l && elem[0:l] == "validator-" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - break - } - switch elem[0] { - case 'p': // Prefix: "published" - origElem := elem - if l := len("published"); len(elem) >= l && elem[0:l] == "published" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionSubmissionPublishOperation - r.summary = "(Internal endpoint) Role Validator changes status from Publishing -> Published" - r.operationID = "actionSubmissionPublish" - r.pathPattern = "/submissions/{SubmissionID}/status/validator-published" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - elem = origElem - case 'v': // Prefix: "validated" - origElem := elem - if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" { - elem = elem[l:] - } else { - break - } - - if len(elem) == 0 { - // Leaf node. - switch method { - case "POST": - r.name = ActionSubmissionValidateOperation - r.summary = "(Internal endpoint) Role Validator changes status from Validating -> Validated" - r.operationID = "actionSubmissionValidate" - r.pathPattern = "/submissions/{SubmissionID}/status/validator-validated" - r.args = args - r.count = 1 - return r, true - default: - return - } - } - - elem = origElem - } - elem = origElem } diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index 19f088c..b793b9d 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -10,9 +10,6 @@ func (s *ErrorStatusCode) Error() string { return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) } -// ActionSubmissionPublishNoContent is response for ActionSubmissionPublish operation. -type ActionSubmissionPublishNoContent struct{} - // ActionSubmissionRejectNoContent is response for ActionSubmissionReject operation. type ActionSubmissionRejectNoContent struct{} @@ -25,15 +22,12 @@ type ActionSubmissionRevokeNoContent struct{} // ActionSubmissionSubmitNoContent is response for ActionSubmissionSubmit operation. type ActionSubmissionSubmitNoContent struct{} -// ActionSubmissionTriggerPublishNoContent is response for ActionSubmissionTriggerPublish operation. -type ActionSubmissionTriggerPublishNoContent struct{} +// ActionSubmissionTriggerUploadNoContent is response for ActionSubmissionTriggerUpload operation. +type ActionSubmissionTriggerUploadNoContent struct{} // ActionSubmissionTriggerValidateNoContent is response for ActionSubmissionTriggerValidate operation. type ActionSubmissionTriggerValidateNoContent struct{} -// ActionSubmissionValidateNoContent is response for ActionSubmissionValidate operation. -type ActionSubmissionValidateNoContent struct{} - type CookieAuth struct { APIKey string } diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index e5dc939..44c02ea 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -8,12 +8,6 @@ import ( // Handler handles operations described by OpenAPI v3 specification. type Handler interface { - // ActionSubmissionPublish implements actionSubmissionPublish operation. - // - // (Internal endpoint) Role Validator changes status from Publishing -> Published. - // - // POST /submissions/{SubmissionID}/status/validator-published - ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error // ActionSubmissionReject implements actionSubmissionReject operation. // // Role Reviewer changes status from Submitted -> Rejected. @@ -38,24 +32,18 @@ type Handler interface { // // POST /submissions/{SubmissionID}/status/submit ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error - // ActionSubmissionTriggerPublish implements actionSubmissionTriggerPublish operation. + // ActionSubmissionTriggerUpload implements actionSubmissionTriggerUpload operation. // - // Role Admin changes status from Validated -> Publishing. + // Role Admin changes status from Validated -> Uploading. // - // POST /submissions/{SubmissionID}/status/trigger-publish - ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error + // POST /submissions/{SubmissionID}/status/trigger-upload + ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error // ActionSubmissionTriggerValidate implements actionSubmissionTriggerValidate operation. // // Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating. // // POST /submissions/{SubmissionID}/status/trigger-validate ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error - // ActionSubmissionValidate implements actionSubmissionValidate operation. - // - // (Internal endpoint) Role Validator changes status from Validating -> Validated. - // - // POST /submissions/{SubmissionID}/status/validator-validated - ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error // CreateScript implements createScript operation. // // Create a new script. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index 80bfc46..0cf3dac 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -13,15 +13,6 @@ type UnimplementedHandler struct{} var _ Handler = UnimplementedHandler{} -// ActionSubmissionPublish implements actionSubmissionPublish operation. -// -// (Internal endpoint) Role Validator changes status from Publishing -> Published. -// -// POST /submissions/{SubmissionID}/status/validator-published -func (UnimplementedHandler) ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error { - return ht.ErrNotImplemented -} - // ActionSubmissionReject implements actionSubmissionReject operation. // // Role Reviewer changes status from Submitted -> Rejected. @@ -58,12 +49,12 @@ func (UnimplementedHandler) ActionSubmissionSubmit(ctx context.Context, params A return ht.ErrNotImplemented } -// ActionSubmissionTriggerPublish implements actionSubmissionTriggerPublish operation. +// ActionSubmissionTriggerUpload implements actionSubmissionTriggerUpload operation. // -// Role Admin changes status from Validated -> Publishing. +// Role Admin changes status from Validated -> Uploading. // -// POST /submissions/{SubmissionID}/status/trigger-publish -func (UnimplementedHandler) ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error { +// POST /submissions/{SubmissionID}/status/trigger-upload +func (UnimplementedHandler) ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error { return ht.ErrNotImplemented } @@ -76,15 +67,6 @@ func (UnimplementedHandler) ActionSubmissionTriggerValidate(ctx context.Context, return ht.ErrNotImplemented } -// ActionSubmissionValidate implements actionSubmissionValidate operation. -// -// (Internal endpoint) Role Validator changes status from Validating -> Validated. -// -// POST /submissions/{SubmissionID}/status/validator-validated -func (UnimplementedHandler) ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error { - return ht.ErrNotImplemented -} - // CreateScript implements createScript operation. // // Create a new script. diff --git a/pkg/internal/oas_cfg_gen.go b/pkg/internal/oas_cfg_gen.go new file mode 100644 index 0000000..fc3ff34 --- /dev/null +++ b/pkg/internal/oas_cfg_gen.go @@ -0,0 +1,283 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +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/internal/oas_client_gen.go b/pkg/internal/oas_client_gen.go new file mode 100644 index 0000000..ee2c470 --- /dev/null +++ b/pkg/internal/oas_client_gen.go @@ -0,0 +1,369 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +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" + + "github.com/ogen-go/ogen/conv" + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/otelogen" + "github.com/ogen-go/ogen/uri" +) + +// Invoker invokes operations described by OpenAPI v3 specification. +type Invoker interface { + // ActionSubmissionReleased invokes actionSubmissionReleased operation. + // + // (Internal endpoint) Role Releaser changes status from releasing -> released. + // + // POST /submissions/{SubmissionID}/status/releaser-released + ActionSubmissionReleased(ctx context.Context, params ActionSubmissionReleasedParams) error + // ActionSubmissionUploaded invokes actionSubmissionUploaded operation. + // + // (Internal endpoint) Role Validator changes status from Uploading -> Uploaded. + // + // POST /submissions/{SubmissionID}/status/validator-uploaded + ActionSubmissionUploaded(ctx context.Context, params ActionSubmissionUploadedParams) error + // ActionSubmissionValidated invokes actionSubmissionValidated operation. + // + // (Internal endpoint) Role Validator changes status from Validating -> Validated. + // + // POST /submissions/{SubmissionID}/status/validator-validated + ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) 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 +}{} + +func trimTrailingSlashes(u *url.URL) { + u.Path = strings.TrimRight(u.Path, "/") + u.RawPath = strings.TrimRight(u.RawPath, "/") +} + +// 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 +} + +// ActionSubmissionReleased invokes actionSubmissionReleased operation. +// +// (Internal endpoint) Role Releaser changes status from releasing -> released. +// +// POST /submissions/{SubmissionID}/status/releaser-released +func (c *Client) ActionSubmissionReleased(ctx context.Context, params ActionSubmissionReleasedParams) error { + _, err := c.sendActionSubmissionReleased(ctx, params) + return err +} + +func (c *Client) sendActionSubmissionReleased(ctx context.Context, params ActionSubmissionReleasedParams) (res *ActionSubmissionReleasedNoContent, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("actionSubmissionReleased"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/releaser-released"), + } + + // 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, ActionSubmissionReleasedOperation, + 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 [3]string + pathParts[0] = "/submissions/" + { + // Encode "SubmissionID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "SubmissionID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Int64ToString(params.SubmissionID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + pathParts[2] = "/status/releaser-released" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create 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 := decodeActionSubmissionReleasedResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// ActionSubmissionUploaded invokes actionSubmissionUploaded operation. +// +// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded. +// +// POST /submissions/{SubmissionID}/status/validator-uploaded +func (c *Client) ActionSubmissionUploaded(ctx context.Context, params ActionSubmissionUploadedParams) error { + _, err := c.sendActionSubmissionUploaded(ctx, params) + return err +} + +func (c *Client) sendActionSubmissionUploaded(ctx context.Context, params ActionSubmissionUploadedParams) (res *ActionSubmissionUploadedNoContent, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("actionSubmissionUploaded"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-uploaded"), + } + + // 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, ActionSubmissionUploadedOperation, + 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 [3]string + pathParts[0] = "/submissions/" + { + // Encode "SubmissionID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "SubmissionID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Int64ToString(params.SubmissionID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + pathParts[2] = "/status/validator-uploaded" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create 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 := decodeActionSubmissionUploadedResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// ActionSubmissionValidated invokes actionSubmissionValidated operation. +// +// (Internal endpoint) Role Validator changes status from Validating -> Validated. +// +// POST /submissions/{SubmissionID}/status/validator-validated +func (c *Client) ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error { + _, err := c.sendActionSubmissionValidated(ctx, params) + return err +} + +func (c *Client) sendActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) (res *ActionSubmissionValidatedNoContent, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("actionSubmissionValidated"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-validated"), + } + + // 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, ActionSubmissionValidatedOperation, + 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 [3]string + pathParts[0] = "/submissions/" + { + // Encode "SubmissionID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "SubmissionID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Int64ToString(params.SubmissionID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + pathParts[2] = "/status/validator-validated" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create 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 := decodeActionSubmissionValidatedResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} diff --git a/pkg/internal/oas_handlers_gen.go b/pkg/internal/oas_handlers_gen.go new file mode 100644 index 0000000..514fb6c --- /dev/null +++ b/pkg/internal/oas_handlers_gen.go @@ -0,0 +1,478 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +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) +} + +// handleActionSubmissionReleasedRequest handles actionSubmissionReleased operation. +// +// (Internal endpoint) Role Releaser changes status from releasing -> released. +// +// POST /submissions/{SubmissionID}/status/releaser-released +func (s *Server) handleActionSubmissionReleasedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("actionSubmissionReleased"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/releaser-released"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionReleasedOperation, + 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: ActionSubmissionReleasedOperation, + ID: "actionSubmissionReleased", + } + ) + params, err := decodeActionSubmissionReleasedParams(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 + } + + var response *ActionSubmissionReleasedNoContent + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: ActionSubmissionReleasedOperation, + OperationSummary: "(Internal endpoint) Role Releaser changes status from releasing -> released", + OperationID: "actionSubmissionReleased", + Body: nil, + Params: middleware.Parameters{ + { + Name: "SubmissionID", + In: "path", + }: params.SubmissionID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = ActionSubmissionReleasedParams + Response = *ActionSubmissionReleasedNoContent + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackActionSubmissionReleasedParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.ActionSubmissionReleased(ctx, params) + return response, err + }, + ) + } else { + err = s.h.ActionSubmissionReleased(ctx, 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 := encodeActionSubmissionReleasedResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleActionSubmissionUploadedRequest handles actionSubmissionUploaded operation. +// +// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded. +// +// POST /submissions/{SubmissionID}/status/validator-uploaded +func (s *Server) handleActionSubmissionUploadedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("actionSubmissionUploaded"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-uploaded"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionUploadedOperation, + 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: ActionSubmissionUploadedOperation, + ID: "actionSubmissionUploaded", + } + ) + params, err := decodeActionSubmissionUploadedParams(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 + } + + var response *ActionSubmissionUploadedNoContent + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: ActionSubmissionUploadedOperation, + OperationSummary: "(Internal endpoint) Role Validator changes status from Uploading -> Uploaded", + OperationID: "actionSubmissionUploaded", + Body: nil, + Params: middleware.Parameters{ + { + Name: "SubmissionID", + In: "path", + }: params.SubmissionID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = ActionSubmissionUploadedParams + Response = *ActionSubmissionUploadedNoContent + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackActionSubmissionUploadedParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.ActionSubmissionUploaded(ctx, params) + return response, err + }, + ) + } else { + err = s.h.ActionSubmissionUploaded(ctx, 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 := encodeActionSubmissionUploadedResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleActionSubmissionValidatedRequest handles actionSubmissionValidated operation. +// +// (Internal endpoint) Role Validator changes status from Validating -> Validated. +// +// POST /submissions/{SubmissionID}/status/validator-validated +func (s *Server) handleActionSubmissionValidatedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("actionSubmissionValidated"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-validated"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionValidatedOperation, + 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: ActionSubmissionValidatedOperation, + ID: "actionSubmissionValidated", + } + ) + params, err := decodeActionSubmissionValidatedParams(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 + } + + var response *ActionSubmissionValidatedNoContent + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: ActionSubmissionValidatedOperation, + OperationSummary: "(Internal endpoint) Role Validator changes status from Validating -> Validated", + OperationID: "actionSubmissionValidated", + Body: nil, + Params: middleware.Parameters{ + { + Name: "SubmissionID", + In: "path", + }: params.SubmissionID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = ActionSubmissionValidatedParams + Response = *ActionSubmissionValidatedNoContent + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackActionSubmissionValidatedParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.ActionSubmissionValidated(ctx, params) + return response, err + }, + ) + } else { + err = s.h.ActionSubmissionValidated(ctx, 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 := encodeActionSubmissionValidatedResponse(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/internal/oas_json_gen.go b/pkg/internal/oas_json_gen.go new file mode 100644 index 0000000..71b3067 --- /dev/null +++ b/pkg/internal/oas_json_gen.go @@ -0,0 +1,126 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "math/bits" + "strconv" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "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("code") + e.Int64(s.Code) + } + { + e.FieldStart("message") + e.Str(s.Message) + } +} + +var jsonFieldsNameOfError = [2]string{ + 0: "code", + 1: "message", +} + +// 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 "code": + requiredBitSet[0] |= 1 << 0 + if err := func() error { + v, err := d.Int64() + s.Code = int64(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"code\"") + } + case "message": + requiredBitSet[0] |= 1 << 1 + 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\"") + } + 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{ + 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(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) +} diff --git a/pkg/internal/oas_labeler_gen.go b/pkg/internal/oas_labeler_gen.go new file mode 100644 index 0000000..7e519e8 --- /dev/null +++ b/pkg/internal/oas_labeler_gen.go @@ -0,0 +1,42 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +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/internal/oas_middleware_gen.go b/pkg/internal/oas_middleware_gen.go new file mode 100644 index 0000000..6f58a1a --- /dev/null +++ b/pkg/internal/oas_middleware_gen.go @@ -0,0 +1,10 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "github.com/ogen-go/ogen/middleware" +) + +// Middleware is middleware type. +type Middleware = middleware.Middleware diff --git a/pkg/internal/oas_operations_gen.go b/pkg/internal/oas_operations_gen.go new file mode 100644 index 0000000..fc1b72a --- /dev/null +++ b/pkg/internal/oas_operations_gen.go @@ -0,0 +1,12 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +// OperationName is the ogen operation name +type OperationName = string + +const ( + ActionSubmissionReleasedOperation OperationName = "ActionSubmissionReleased" + ActionSubmissionUploadedOperation OperationName = "ActionSubmissionUploaded" + ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated" +) diff --git a/pkg/internal/oas_parameters_gen.go b/pkg/internal/oas_parameters_gen.go new file mode 100644 index 0000000..52a65ca --- /dev/null +++ b/pkg/internal/oas_parameters_gen.go @@ -0,0 +1,214 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "net/http" + "net/url" + + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/conv" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/uri" + "github.com/ogen-go/ogen/validate" +) + +// ActionSubmissionReleasedParams is parameters of actionSubmissionReleased operation. +type ActionSubmissionReleasedParams struct { + // The unique identifier for a submission. + SubmissionID int64 +} + +func unpackActionSubmissionReleasedParams(packed middleware.Parameters) (params ActionSubmissionReleasedParams) { + { + key := middleware.ParameterKey{ + Name: "SubmissionID", + In: "path", + } + params.SubmissionID = packed[key].(int64) + } + return params +} + +func decodeActionSubmissionReleasedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionReleasedParams, _ error) { + // Decode path: SubmissionID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "SubmissionID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + params.SubmissionID = c + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "SubmissionID", + In: "path", + Err: err, + } + } + return params, nil +} + +// ActionSubmissionUploadedParams is parameters of actionSubmissionUploaded operation. +type ActionSubmissionUploadedParams struct { + // The unique identifier for a submission. + SubmissionID int64 +} + +func unpackActionSubmissionUploadedParams(packed middleware.Parameters) (params ActionSubmissionUploadedParams) { + { + key := middleware.ParameterKey{ + Name: "SubmissionID", + In: "path", + } + params.SubmissionID = packed[key].(int64) + } + return params +} + +func decodeActionSubmissionUploadedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionUploadedParams, _ error) { + // Decode path: SubmissionID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "SubmissionID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + params.SubmissionID = c + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "SubmissionID", + In: "path", + Err: err, + } + } + return params, nil +} + +// ActionSubmissionValidatedParams is parameters of actionSubmissionValidated operation. +type ActionSubmissionValidatedParams struct { + // The unique identifier for a submission. + SubmissionID int64 +} + +func unpackActionSubmissionValidatedParams(packed middleware.Parameters) (params ActionSubmissionValidatedParams) { + { + key := middleware.ParameterKey{ + Name: "SubmissionID", + In: "path", + } + params.SubmissionID = packed[key].(int64) + } + return params +} + +func decodeActionSubmissionValidatedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionValidatedParams, _ error) { + // Decode path: SubmissionID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "SubmissionID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + params.SubmissionID = c + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "SubmissionID", + In: "path", + Err: err, + } + } + return params, nil +} diff --git a/pkg/internal/oas_request_decoders_gen.go b/pkg/internal/oas_request_decoders_gen.go new file mode 100644 index 0000000..ae379a2 --- /dev/null +++ b/pkg/internal/oas_request_decoders_gen.go @@ -0,0 +1,3 @@ +// Code generated by ogen, DO NOT EDIT. + +package api diff --git a/pkg/internal/oas_request_encoders_gen.go b/pkg/internal/oas_request_encoders_gen.go new file mode 100644 index 0000000..ae379a2 --- /dev/null +++ b/pkg/internal/oas_request_encoders_gen.go @@ -0,0 +1,3 @@ +// Code generated by ogen, DO NOT EDIT. + +package api diff --git a/pkg/internal/oas_response_decoders_gen.go b/pkg/internal/oas_response_decoders_gen.go new file mode 100644 index 0000000..1feec44 --- /dev/null +++ b/pkg/internal/oas_response_decoders_gen.go @@ -0,0 +1,168 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +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 decodeActionSubmissionReleasedResponse(resp *http.Response) (res *ActionSubmissionReleasedNoContent, _ error) { + switch resp.StatusCode { + case 204: + // Code 204. + return &ActionSubmissionReleasedNoContent{}, nil + } + // 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") +} + +func decodeActionSubmissionUploadedResponse(resp *http.Response) (res *ActionSubmissionUploadedNoContent, _ error) { + switch resp.StatusCode { + case 204: + // Code 204. + return &ActionSubmissionUploadedNoContent{}, nil + } + // 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") +} + +func decodeActionSubmissionValidatedResponse(resp *http.Response) (res *ActionSubmissionValidatedNoContent, _ error) { + switch resp.StatusCode { + case 204: + // Code 204. + return &ActionSubmissionValidatedNoContent{}, nil + } + // 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/internal/oas_response_encoders_gen.go b/pkg/internal/oas_response_encoders_gen.go new file mode 100644 index 0000000..182bdf1 --- /dev/null +++ b/pkg/internal/oas_response_encoders_gen.go @@ -0,0 +1,62 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +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 encodeActionSubmissionReleasedResponse(response *ActionSubmissionReleasedNoContent, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(204) + span.SetStatus(codes.Ok, http.StatusText(204)) + + return nil +} + +func encodeActionSubmissionUploadedResponse(response *ActionSubmissionUploadedNoContent, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(204) + span.SetStatus(codes.Ok, http.StatusText(204)) + + return nil +} + +func encodeActionSubmissionValidatedResponse(response *ActionSubmissionValidatedNoContent, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(204) + span.SetStatus(codes.Ok, http.StatusText(204)) + + 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/internal/oas_router_gen.go b/pkg/internal/oas_router_gen.go new file mode 100644 index 0000000..829caf0 --- /dev/null +++ b/pkg/internal/oas_router_gen.go @@ -0,0 +1,387 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +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 + } + args := [1]string{} + + // Static code generated router with unwrapped path search. + switch { + default: + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/submissions/" + origElem := elem + if l := len("/submissions/"); len(elem) >= l && elem[0:l] == "/submissions/" { + elem = elem[l:] + } else { + break + } + + // Param: "SubmissionID" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/status/" + origElem := elem + if l := len("/status/"); len(elem) >= l && elem[0:l] == "/status/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'r': // Prefix: "releaser-released" + origElem := elem + if l := len("releaser-released"); len(elem) >= l && elem[0:l] == "releaser-released" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionSubmissionReleasedRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + elem = origElem + case 'v': // Prefix: "validator-" + origElem := elem + if l := len("validator-"); len(elem) >= l && elem[0:l] == "validator-" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'u': // Prefix: "uploaded" + origElem := elem + if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionSubmissionUploadedRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + elem = origElem + case 'v': // Prefix: "validated" + origElem := elem + if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleActionSubmissionValidatedRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + } + s.notFound(w, r) +} + +// Route is route object. +type Route struct { + name string + summary string + operationID string + pathPattern string + count int + args [1]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: "/submissions/" + origElem := elem + if l := len("/submissions/"); len(elem) >= l && elem[0:l] == "/submissions/" { + elem = elem[l:] + } else { + break + } + + // Param: "SubmissionID" + // Match until "/" + idx := strings.IndexByte(elem, '/') + if idx < 0 { + idx = len(elem) + } + args[0] = elem[:idx] + elem = elem[idx:] + + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/status/" + origElem := elem + if l := len("/status/"); len(elem) >= l && elem[0:l] == "/status/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'r': // Prefix: "releaser-released" + origElem := elem + if l := len("releaser-released"); len(elem) >= l && elem[0:l] == "releaser-released" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionSubmissionReleasedOperation + r.summary = "(Internal endpoint) Role Releaser changes status from releasing -> released" + r.operationID = "actionSubmissionReleased" + r.pathPattern = "/submissions/{SubmissionID}/status/releaser-released" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + elem = origElem + case 'v': // Prefix: "validator-" + origElem := elem + if l := len("validator-"); len(elem) >= l && elem[0:l] == "validator-" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'u': // Prefix: "uploaded" + origElem := elem + if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionSubmissionUploadedOperation + r.summary = "(Internal endpoint) Role Validator changes status from Uploading -> Uploaded" + r.operationID = "actionSubmissionUploaded" + r.pathPattern = "/submissions/{SubmissionID}/status/validator-uploaded" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + elem = origElem + case 'v': // Prefix: "validated" + origElem := elem + if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = ActionSubmissionValidatedOperation + r.summary = "(Internal endpoint) Role Validator changes status from Validating -> Validated" + r.operationID = "actionSubmissionValidated" + r.pathPattern = "/submissions/{SubmissionID}/status/validator-validated" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + + elem = origElem + } + } + return r, false +} diff --git a/pkg/internal/oas_schemas_gen.go b/pkg/internal/oas_schemas_gen.go new file mode 100644 index 0000000..e17044b --- /dev/null +++ b/pkg/internal/oas_schemas_gen.go @@ -0,0 +1,73 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "fmt" +) + +func (s *ErrorStatusCode) Error() string { + return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) +} + +// ActionSubmissionReleasedNoContent is response for ActionSubmissionReleased operation. +type ActionSubmissionReleasedNoContent struct{} + +// ActionSubmissionUploadedNoContent is response for ActionSubmissionUploaded operation. +type ActionSubmissionUploadedNoContent struct{} + +// ActionSubmissionValidatedNoContent is response for ActionSubmissionValidated operation. +type ActionSubmissionValidatedNoContent struct{} + +// Represents error object. +// Ref: #/components/schemas/Error +type Error struct { + Code int64 `json:"code"` + Message string `json:"message"` +} + +// GetCode returns the value of Code. +func (s *Error) GetCode() int64 { + return s.Code +} + +// GetMessage returns the value of Message. +func (s *Error) GetMessage() string { + return s.Message +} + +// SetCode sets the value of Code. +func (s *Error) SetCode(val int64) { + s.Code = val +} + +// SetMessage sets the value of Message. +func (s *Error) SetMessage(val string) { + s.Message = 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 +} diff --git a/pkg/internal/oas_server_gen.go b/pkg/internal/oas_server_gen.go new file mode 100644 index 0000000..7333971 --- /dev/null +++ b/pkg/internal/oas_server_gen.go @@ -0,0 +1,52 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "context" +) + +// Handler handles operations described by OpenAPI v3 specification. +type Handler interface { + // ActionSubmissionReleased implements actionSubmissionReleased operation. + // + // (Internal endpoint) Role Releaser changes status from releasing -> released. + // + // POST /submissions/{SubmissionID}/status/releaser-released + ActionSubmissionReleased(ctx context.Context, params ActionSubmissionReleasedParams) error + // ActionSubmissionUploaded implements actionSubmissionUploaded operation. + // + // (Internal endpoint) Role Validator changes status from Uploading -> Uploaded. + // + // POST /submissions/{SubmissionID}/status/validator-uploaded + ActionSubmissionUploaded(ctx context.Context, params ActionSubmissionUploadedParams) error + // ActionSubmissionValidated implements actionSubmissionValidated operation. + // + // (Internal endpoint) Role Validator changes status from Validating -> Validated. + // + // POST /submissions/{SubmissionID}/status/validator-validated + ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) 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/internal/oas_unimplemented_gen.go b/pkg/internal/oas_unimplemented_gen.go new file mode 100644 index 0000000..7430929 --- /dev/null +++ b/pkg/internal/oas_unimplemented_gen.go @@ -0,0 +1,49 @@ +// Code generated by ogen, DO NOT EDIT. + +package api + +import ( + "context" + + ht "github.com/ogen-go/ogen/http" +) + +// UnimplementedHandler is no-op Handler which returns http.ErrNotImplemented. +type UnimplementedHandler struct{} + +var _ Handler = UnimplementedHandler{} + +// ActionSubmissionReleased implements actionSubmissionReleased operation. +// +// (Internal endpoint) Role Releaser changes status from releasing -> released. +// +// POST /submissions/{SubmissionID}/status/releaser-released +func (UnimplementedHandler) ActionSubmissionReleased(ctx context.Context, params ActionSubmissionReleasedParams) error { + return ht.ErrNotImplemented +} + +// ActionSubmissionUploaded implements actionSubmissionUploaded operation. +// +// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded. +// +// POST /submissions/{SubmissionID}/status/validator-uploaded +func (UnimplementedHandler) ActionSubmissionUploaded(ctx context.Context, params ActionSubmissionUploadedParams) error { + return ht.ErrNotImplemented +} + +// ActionSubmissionValidated implements actionSubmissionValidated operation. +// +// (Internal endpoint) Role Validator changes status from Validating -> Validated. +// +// POST /submissions/{SubmissionID}/status/validator-validated +func (UnimplementedHandler) ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error { + return 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 +}