Files
pipu-music/services/api/internal/api/gen/api.gen.go
T
mrleo1nidandClaude Opus 5.5 4fa1add80d
ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 48s
ci / api (push) Successful in 51s
ci / recommender (push) Canceled after 2s
ci / ts (packages + web) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (apps/web/Dockerfile, web, ) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, api, api) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, storage-agent, storage-agent) (push) Canceled after 0s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/recommender/Dockerfile, recommender, ) (push) Canceled after 0s
ci / mobile (Metro-бандл Android) (push) Canceled after 0s
fix: address project review findings
Security and robustness:
- storage-agent rejects an empty INTERNAL_TOKEN (config notEmpty + middleware)
- api takes the client IP only from X-Real-IP (chi RealIP trusted True-Client-IP)
- /readyz reports ok/fail and logs the cause; checks run in parallel with a timeout
- storage-agent shuts down gracefully; shared httpx.NewServer/Serve with IdleTimeout
- goose migrations take a Postgres advisory lock
- recommender readyz: per-check timeout, redis socket timeouts

Clients:
- Android release allows cleartext HTTP for LAN servers (expo-build-properties)
- checkServer times out after 10s; connect button is disabled while checking

Deploy and CI:
- install.sh hands cache/uploads/updates/models to the non-root service users
- update.sh refuses downgrades unless PIPU_ALLOW_DOWNGRADE=1
- recommender/analyzer get only the env they need; required secrets fail fast
- nginx security headers and CSP; strip True-Client-IP
- dev compose binds ports to 127.0.0.1; postgres/redis images pinned
- version.mjs fails on a malformed explicit tag instead of releasing 0.0.0-dev
- contract check catches untracked generated files
- final releases fail without a release keystore; changelog skips rc tags

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 00:46:46 +03:00

572 lines
18 KiB
Go

// Package gen provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT.
package gen
import (
"bytes"
"compress/gzip"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"net/url"
"path"
"strings"
"github.com/getkin/kin-openapi/openapi3"
"github.com/go-chi/chi/v5"
strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// Defines values for HealthStatusStatus.
const (
HealthStatusStatusOk HealthStatusStatus = "ok"
)
// Defines values for ReadyStatusStatus.
const (
ReadyStatusStatusDegraded ReadyStatusStatus = "degraded"
ReadyStatusStatusOk ReadyStatusStatus = "ok"
)
// HealthStatus defines model for HealthStatus.
type HealthStatus struct {
Status HealthStatusStatus `json:"status"`
}
// HealthStatusStatus defines model for HealthStatus.Status.
type HealthStatusStatus string
// Problem defines model for Problem.
type Problem struct {
// Code Машинный код ошибки для i18n, например `auth.invalid_credentials`
Code string `json:"code"`
// Detail Пояснение для логов (не для показа пользователю)
Detail *string `json:"detail,omitempty"`
Params *map[string]interface{} `json:"params,omitempty"`
Status int `json:"status"`
Type *string `json:"type,omitempty"`
}
// ReadyStatus defines model for ReadyStatus.
type ReadyStatus struct {
// Checks Результат проверки каждой зависимости
Checks map[string]string `json:"checks"`
Status ReadyStatusStatus `json:"status"`
}
// ReadyStatusStatus defines model for ReadyStatus.Status.
type ReadyStatusStatus string
// ServerInfo defines model for ServerInfo.
type ServerInfo struct {
ApiVersion string `json:"api_version"`
// MinAndroidVersionCode Минимальный versionCode Android-приложения, которое поддерживает сервер
MinAndroidVersionCode int `json:"min_android_version_code"`
Name string `json:"name"`
SupportedLocales []string `json:"supported_locales"`
// Version Версия сервера (SemVer)
Version string `json:"version"`
}
// ServerInterface represents all server handlers.
type ServerInterface interface {
// Сведения о сервере для клиентов
// (GET /api/v1/server-info)
GetServerInfo(w http.ResponseWriter, r *http.Request)
// Живость процесса
// (GET /healthz)
GetHealthz(w http.ResponseWriter, r *http.Request)
// Готовность обслуживать запросы (зависимости доступны)
// (GET /readyz)
GetReadyz(w http.ResponseWriter, r *http.Request)
}
// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
type Unimplemented struct{}
// Сведения о сервере для клиентов
// (GET /api/v1/server-info)
func (_ Unimplemented) GetServerInfo(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}
// Живость процесса
// (GET /healthz)
func (_ Unimplemented) GetHealthz(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}
// Готовность обслуживать запросы (зависимости доступны)
// (GET /readyz)
func (_ Unimplemented) GetReadyz(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}
// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
Handler ServerInterface
HandlerMiddlewares []MiddlewareFunc
ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
}
type MiddlewareFunc func(http.Handler) http.Handler
// GetServerInfo operation middleware
func (siw *ServerInterfaceWrapper) GetServerInfo(w http.ResponseWriter, r *http.Request) {
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetServerInfo(w, r)
}))
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler.ServeHTTP(w, r)
}
// GetHealthz operation middleware
func (siw *ServerInterfaceWrapper) GetHealthz(w http.ResponseWriter, r *http.Request) {
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetHealthz(w, r)
}))
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler.ServeHTTP(w, r)
}
// GetReadyz operation middleware
func (siw *ServerInterfaceWrapper) GetReadyz(w http.ResponseWriter, r *http.Request) {
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetReadyz(w, r)
}))
for _, middleware := range siw.HandlerMiddlewares {
handler = middleware(handler)
}
handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
ParamName string
Err error
}
func (e *UnescapedCookieParamError) Error() string {
return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
}
func (e *UnescapedCookieParamError) Unwrap() error {
return e.Err
}
type UnmarshalingParamError struct {
ParamName string
Err error
}
func (e *UnmarshalingParamError) Error() string {
return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
}
func (e *UnmarshalingParamError) Unwrap() error {
return e.Err
}
type RequiredParamError struct {
ParamName string
}
func (e *RequiredParamError) Error() string {
return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
}
type RequiredHeaderError struct {
ParamName string
Err error
}
func (e *RequiredHeaderError) Error() string {
return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
}
func (e *RequiredHeaderError) Unwrap() error {
return e.Err
}
type InvalidParamFormatError struct {
ParamName string
Err error
}
func (e *InvalidParamFormatError) Error() string {
return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
}
func (e *InvalidParamFormatError) Unwrap() error {
return e.Err
}
type TooManyValuesForParamError struct {
ParamName string
Count int
}
func (e *TooManyValuesForParamError) Error() string {
return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
}
// Handler creates http.Handler with routing matching OpenAPI spec.
func Handler(si ServerInterface) http.Handler {
return HandlerWithOptions(si, ChiServerOptions{})
}
type ChiServerOptions struct {
BaseURL string
BaseRouter chi.Router
Middlewares []MiddlewareFunc
ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
}
// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
return HandlerWithOptions(si, ChiServerOptions{
BaseRouter: r,
})
}
func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
return HandlerWithOptions(si, ChiServerOptions{
BaseURL: baseURL,
BaseRouter: r,
})
}
// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
r := options.BaseRouter
if r == nil {
r = chi.NewRouter()
}
if options.ErrorHandlerFunc == nil {
options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, err.Error(), http.StatusBadRequest)
}
}
wrapper := ServerInterfaceWrapper{
Handler: si,
HandlerMiddlewares: options.Middlewares,
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
r.Group(func(r chi.Router) {
r.Get(options.BaseURL+"/api/v1/server-info", wrapper.GetServerInfo)
})
r.Group(func(r chi.Router) {
r.Get(options.BaseURL+"/healthz", wrapper.GetHealthz)
})
r.Group(func(r chi.Router) {
r.Get(options.BaseURL+"/readyz", wrapper.GetReadyz)
})
return r
}
type ProblemApplicationProblemPlusJSONResponse Problem
type GetServerInfoRequestObject struct {
}
type GetServerInfoResponseObject interface {
VisitGetServerInfoResponse(w http.ResponseWriter) error
}
type GetServerInfo200JSONResponse ServerInfo
func (response GetServerInfo200JSONResponse) VisitGetServerInfoResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
return json.NewEncoder(w).Encode(response)
}
type GetServerInfodefaultApplicationProblemPlusJSONResponse struct {
Body Problem
StatusCode int
}
func (response GetServerInfodefaultApplicationProblemPlusJSONResponse) VisitGetServerInfoResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/problem+json")
w.WriteHeader(response.StatusCode)
return json.NewEncoder(w).Encode(response.Body)
}
type GetHealthzRequestObject struct {
}
type GetHealthzResponseObject interface {
VisitGetHealthzResponse(w http.ResponseWriter) error
}
type GetHealthz200JSONResponse HealthStatus
func (response GetHealthz200JSONResponse) VisitGetHealthzResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
return json.NewEncoder(w).Encode(response)
}
type GetReadyzRequestObject struct {
}
type GetReadyzResponseObject interface {
VisitGetReadyzResponse(w http.ResponseWriter) error
}
type GetReadyz200JSONResponse ReadyStatus
func (response GetReadyz200JSONResponse) VisitGetReadyzResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
return json.NewEncoder(w).Encode(response)
}
type GetReadyz503JSONResponse ReadyStatus
func (response GetReadyz503JSONResponse) VisitGetReadyzResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(503)
return json.NewEncoder(w).Encode(response)
}
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
// Сведения о сервере для клиентов
// (GET /api/v1/server-info)
GetServerInfo(ctx context.Context, request GetServerInfoRequestObject) (GetServerInfoResponseObject, error)
// Живость процесса
// (GET /healthz)
GetHealthz(ctx context.Context, request GetHealthzRequestObject) (GetHealthzResponseObject, error)
// Готовность обслуживать запросы (зависимости доступны)
// (GET /readyz)
GetReadyz(ctx context.Context, request GetReadyzRequestObject) (GetReadyzResponseObject, error)
}
type StrictHandlerFunc = strictnethttp.StrictHTTPHandlerFunc
type StrictMiddlewareFunc = strictnethttp.StrictHTTPMiddlewareFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, err.Error(), http.StatusBadRequest)
},
ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, err.Error(), http.StatusInternalServerError)
},
}}
}
func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
options StrictHTTPServerOptions
}
// GetServerInfo operation middleware
func (sh *strictHandler) GetServerInfo(w http.ResponseWriter, r *http.Request) {
var request GetServerInfoRequestObject
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.GetServerInfo(ctx, request.(GetServerInfoRequestObject))
}
for _, middleware := range sh.middlewares {
handler = middleware(handler, "GetServerInfo")
}
response, err := handler(r.Context(), w, r, request)
if err != nil {
sh.options.ResponseErrorHandlerFunc(w, r, err)
} else if validResponse, ok := response.(GetServerInfoResponseObject); ok {
if err := validResponse.VisitGetServerInfoResponse(w); err != nil {
sh.options.ResponseErrorHandlerFunc(w, r, err)
}
} else if response != nil {
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
}
}
// GetHealthz operation middleware
func (sh *strictHandler) GetHealthz(w http.ResponseWriter, r *http.Request) {
var request GetHealthzRequestObject
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.GetHealthz(ctx, request.(GetHealthzRequestObject))
}
for _, middleware := range sh.middlewares {
handler = middleware(handler, "GetHealthz")
}
response, err := handler(r.Context(), w, r, request)
if err != nil {
sh.options.ResponseErrorHandlerFunc(w, r, err)
} else if validResponse, ok := response.(GetHealthzResponseObject); ok {
if err := validResponse.VisitGetHealthzResponse(w); err != nil {
sh.options.ResponseErrorHandlerFunc(w, r, err)
}
} else if response != nil {
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
}
}
// GetReadyz operation middleware
func (sh *strictHandler) GetReadyz(w http.ResponseWriter, r *http.Request) {
var request GetReadyzRequestObject
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.GetReadyz(ctx, request.(GetReadyzRequestObject))
}
for _, middleware := range sh.middlewares {
handler = middleware(handler, "GetReadyz")
}
response, err := handler(r.Context(), w, r, request)
if err != nil {
sh.options.ResponseErrorHandlerFunc(w, r, err)
} else if validResponse, ok := response.(GetReadyzResponseObject); ok {
if err := validResponse.VisitGetReadyzResponse(w); err != nil {
sh.options.ResponseErrorHandlerFunc(w, r, err)
}
} else if response != nil {
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
}
}
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"H4sIAAAAAAAC/7xW3W4bRRR+ldHARSw2tkOpoL6rKqC9QIoSxE0bJZPdSTLN/jE7GxEiS3GCWqSURioI",
"cYFa+gabYDdLHG9e4cwr8CTozO7aa2cTwkW5snf3zPn5vu+cOXvUDrww8LmvItrZo5JHYeBH3DwsymDd",
"5R7+tQNfcV/hXxaGrrCZEoHfCnOLj55GgY/fInuLewz/fSj5Bu3QD1oT/638a9Qq/Xa7XYs6PLKlCNEd",
"7VB4rX+EFE7gHBIyt/TFA3Lvk7ufNihaFsfR+0POXLW1rJiKzXMog5BLJfK8o/F77sce7TymwTZdsaja",
"DTnt0EhJ4W8al5J/GwvJHbQpTk3sgvWn3Fa0a1WBmI5kBw7H35kifofElDGCkT6CvwicQwZ9Atm4uJRA",
"H4b6mIiFz3yLwAgSuNT7kMIFDPQ+WWOx2moKf4e5wlm1JXe4rwRzozV6pQ7EUDHh1iTyBjJ9rHswggGM",
"IIVBGRaGkMGfkMEpmcOv4/eXkCH2cAZJ/jDUL+AMDSHRBzCAoX7ZqMshZJJ5BhTmOAITYO5iBSwlY14D",
"7YSr4pPwFd/kEr/lb7CoDRa7inYoWw9i1Vl3mb9Nb8mnlZNUR+sSZ87udSKyt7i9fUM9s1ivBdtrBFIY",
"QkrWNphw18hcTql+bqSQkL/3fyH6oMD0HDICpyURA6J7SDycQqp7kDTqaZ4i9w8YwJk+RG/6ANkhJh5S",
"hZ6MyJDKd9CHDFV4BknhH2WW6Z4+gJTeSEqlgTD+pmQOd27dS1aJYh36y1zucPnI3wiugs9CsbrDZSTy",
"scK/Y17o4vGdhTpgPOGvMt+RgXDKY6vXtmZqOuECEkND3qDFoQeBw8n93NF80Y/Iz7u8ffSxZVoZOTRA",
"D/IW6UPfIP4OUmwTGOiDCZ0DvU+tSQUL7fa9e1aN2H3m8elaQxHG814cCbuu5igOw0Aq7qy6gc3cHLfx",
"4cdUxhjWR+iF4l61xSZOihdMSraLzxXMZ3B7hYWgcvTxVG04ppe59w2XjWqZtN1caLb/tUdN0ZOw1hTx",
"dTXewPVVjWE0UehrdjDqQzjBXtXPCwksfb78Nbm/+IgsijAmXyHsTQK/mSbJ0ApSOCfYPdg1eKicmbNw",
"BCwU85jSJvcbT/y8DYc4fWFk2v+UzAUh99EMM84TazQJvDWzYGhuj0JxZmg4gR21WCiantN8gsAooQzK",
"k1wx9QqSJQFdixahaIfeababdyiOarVl9IA+WzsLrci04nyJ1SZXdQrQR3Cmj0qF6x5eFyc4gwgk+tBc",
"Dlhfqn9AqCDRzyCFtEMQGTghkJatNTWn9LF+iaPrdCywlzOIWk983TPmeDfm8BfjS7+YxjbBKPU9CRf6",
"CMfssSkCh+Oc/gnOMQCMyjPneL3p5yX4jRxtnExm33nk0A79kqvK6LKmV6aP2+0b1qX/tiZVotRtSm8N",
"rv2xUCCbxm2QXxnF1Vkfapx7ZSfDtvM8JndvFWS8OMxIHEXKNiNzGexGint0BV23tszm9n1FZlfQfViY",
"vEdop/bHOnDfoED1M6O3HslVNIvNr0ZaYx1eVo9Ach0AEpeOG+tfyi3eY/nVxaeu+lfI8TX7AhKe13wI",
"lzgGUWZ323f+t+ReQ99sU8Wuhdur7pkNe7xW1SU+wA1oZMQ8k/40qz/n9zucwmjCbQYnugdDfVjOk/z1",
"WbG1o90RmbslYI1aaWAWpuHx/R6NpUs7tEW7K2PjvWJHKA91V7r/BAAA//8arOezvw0AAA==",
}
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
zr, err := gzip.NewReader(bytes.NewReader(zipped))
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %w", err)
}
var buf bytes.Buffer
_, err = buf.ReadFrom(zr)
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %w", err)
}
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
res := make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
pathToFile := url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}