diff --git a/api/_build/openapi.yaml b/api/_build/openapi.yaml index 2ee6cdc..f875ba2 100644 --- a/api/_build/openapi.yaml +++ b/api/_build/openapi.yaml @@ -16,6 +16,11 @@ paths: schema: type: boolean default: true + - name: ext_search + in: query + schema: + type: boolean + default: false - name: word in: query schema: diff --git a/api/api.gen.go b/api/api.gen.go index 6208050..2294d74 100644 --- a/api/api.gen.go +++ b/api/api.gen.go @@ -178,6 +178,7 @@ type GetTitlesParams struct { Cursor *Cursor `form:"cursor,omitempty" json:"cursor,omitempty"` Sort *TitleSort `form:"sort,omitempty" json:"sort,omitempty"` SortForward *bool `form:"sort_forward,omitempty" json:"sort_forward,omitempty"` + ExtSearch *bool `form:"ext_search,omitempty" json:"ext_search,omitempty"` Word *string `form:"word,omitempty" json:"word,omitempty"` // Status List of title statuses to filter @@ -337,6 +338,14 @@ func (siw *ServerInterfaceWrapper) GetTitles(c *gin.Context) { return } + // ------------- Optional query parameter "ext_search" ------------- + + err = runtime.BindQueryParameter("form", true, false, "ext_search", c.Request.URL.Query(), ¶ms.ExtSearch) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter ext_search: %w", err), http.StatusBadRequest) + return + } + // ------------- Optional query parameter "word" ------------- err = runtime.BindQueryParameter("form", true, false, "word", c.Request.URL.Query(), ¶ms.Word) diff --git a/api/paths/titles.yaml b/api/paths/titles.yaml index af2d17b..4288417 100644 --- a/api/paths/titles.yaml +++ b/api/paths/titles.yaml @@ -8,6 +8,11 @@ get: schema: type: boolean default: true + - in: query + name: ext_search + schema: + type: boolean + default: false - in: query name: word schema: @@ -21,7 +26,6 @@ get: description: List of title statuses to filter style: form explode: false - - in: query name: rating schema: diff --git a/go.mod b/go.mod index bf73121..7fc0e5f 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.54.0 // indirect + github.com/streadway/amqp v1.1.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.0 // indirect go.uber.org/mock v0.5.0 // indirect diff --git a/go.sum b/go.sum index 8f46514..e52e5c9 100644 --- a/go.sum +++ b/go.sum @@ -73,6 +73,8 @@ github.com/quic-go/quic-go v0.54.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= +github.com/streadway/amqp v1.1.0 h1:py12iX8XSyI7aN/3dUT8DFIDJazNJsVJdxNVEpnQTZM= +github.com/streadway/amqp v1.1.0/go.mod h1:WYSrTEYHOXHd0nwFeUXAe2G2hRnQT+deZJJf88uS9Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/modules/backend/rabbit.go b/modules/backend/rabbit.go new file mode 100644 index 0000000..f08bf39 --- /dev/null +++ b/modules/backend/rabbit.go @@ -0,0 +1,103 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + oapi "nyanimedb/api" + "time" + + "github.com/google/uuid" + "github.com/sirupsen/logrus" + "github.com/streadway/amqp" +) + +type RabbitRequest struct { + Name string `json:"name"` + Status oapi.TitleStatus `json:"titlestatus,omitempty"` + Rating float64 `json:"titleraring,omitempty"` + Year int32 `json:"year,omitempty"` + Season oapi.ReleaseSeason `json:"season,omitempty"` + Timestamp time.Time `json:"timestamp"` +} + +// PublishAndAwaitReply отправляет запрос и ждёт ответа от worker’а. +// Возвращает раскодированный ответ или ошибку. +func PublishAndAwaitReply( + ctx context.Context, + ch *amqp.Channel, + requestQueue string, // например: "svc.media.process.requests" + request RabbitRequest, // ваша структура запроса + replyCh chan<- any, // куда положить ответ (вы читаете извне) +) error { + // 1. Создаём временную очередь для ответов + replyQueue, err := ch.QueueDeclare( + "", // auto-generated name + false, // not durable + true, // exclusive + true, // auto-delete + false, // no-wait + nil, + ) + if err != nil { + return fmt.Errorf("failed to declare reply queue: %w", err) + } + + // 2. Готовим корреляционный ID + corrID := uuid.New().String() // ← используйте github.com/google/uuid + logrus.Infof("New CorrID: %s", corrID) + + // 3. Сериализуем запрос + body, err := json.Marshal(request) + if err != nil { + return fmt.Errorf("failed to marshal request: %w", err) + } + + // 4. Публикуем запрос + err = ch.Publish( + "", // default exchange (или свой, если используете) + requestQueue, + false, + false, + amqp.Publishing{ + ContentType: "application/json", + CorrelationId: corrID, + ReplyTo: replyQueue.Name, + DeliveryMode: amqp.Persistent, + Timestamp: time.Now(), + Body: body, + }, + ) + if err != nil { + return fmt.Errorf("failed to publish request, corrID: %s : %w", corrID, err) + } + + // 5. Подписываемся на ответы + msgs, err := ch.Consume( + replyQueue.Name, + "", // consumer tag + true, // auto-ack + true, // exclusive + false, // no-local + false, // no-wait + nil, // args + ) + if err != nil { + return fmt.Errorf("failed to consume from reply queue: %w", err) + } + + // 6. Ожидаем ответ с таймаутом + select { + case msg := <-msgs: + if msg.CorrelationId != corrID { + return fmt.Errorf("correlation ID mismatch: got %s, expected %s", msg.CorrelationId, corrID) + } + // Десериализуем — тут можно передать target-структуру или использовать interface{} + // В данном случае просто возвращаем байты или пусть вызывающая сторона парсит + replyCh <- msg.Body // или json.Unmarshal → и отправить структуру в канал + return nil + + case <-ctx.Done(): + return ctx.Err() + } +}