// Изменено: 2026-04-11 — убрана зависимость от copystructure (лишняя аллокация) // GetQueueAttributesV1 — возвращает атрибуты очереди тенанта. package gosqs import ( "fmt" "net/http" "strconv" "strings" "shared-sqs/app/interfaces" "shared-sqs/app/models" "shared-sqs/app/utils" log "github.com/sirupsen/logrus" ) func GetQueueAttributesV1(req *http.Request) (int, interfaces.AbstractResponseBody) { requestBody := models.NewGetQueueAttributesRequest() ok := utils.REQUEST_TRANSFORMER(requestBody, req, false) if !ok { log.Error("Invalid Request - GetQueueAttributesV1") return utils.CreateErrorResponseV1("InvalidParameterValue", true) } if requestBody.QueueUrl == "" { log.Error("Missing QueueUrl - GetQueueAttributesV1") return utils.CreateErrorResponseV1("InvalidParameterValue", true) } t := getTenantFromContext(req) if t == nil { return utils.CreateErrorResponseV1("InvalidClientTokenId", true) } // Определяем набор запрошенных атрибутов (или All) requestedAttributes := func() map[string]bool { attrs := map[string]bool{} if len(requestBody.AttributeNames) == 0 { return map[string]bool{"All": true} } for _, attr := range requestBody.AttributeNames { if "All" == attr { return map[string]bool{"All": true} } attrs[attr] = true } return attrs }() // Фильтруем атрибуты без deep copy — простая проверка через map lookup _, wantAll := requestedAttributes["All"] shouldInclude := func(attr string) bool { if wantAll { return true } _, ok := requestedAttributes[attr] return ok } uriSegments := strings.Split(requestBody.QueueUrl, "/") queueName := uriSegments[len(uriSegments)-1] key := tenantQueueKey(t.AccessKey, queueName) log.Infof("Get Queue Attributes: %s (tenant: %s)", queueName, t.ID) queueAttributes := make([]models.Attribute, 0) models.SyncQueues.RLock() defer models.SyncQueues.RUnlock() queue, ok := models.SyncQueues.Queues[key] if !ok { log.Errorf("Get Queue Attributes: %s queue does not exist for tenant %s", queueName, t.ID) return utils.CreateErrorResponseV1("QueueNotFound", true) } if shouldInclude("DelaySeconds") { queueAttributes = append(queueAttributes, models.Attribute{Name: "DelaySeconds", Value: strconv.Itoa(queue.DelaySeconds)}) } if shouldInclude("MaximumMessageSize") { queueAttributes = append(queueAttributes, models.Attribute{Name: "MaximumMessageSize", Value: strconv.Itoa(queue.MaximumMessageSize)}) } if shouldInclude("MessageRetentionPeriod") { queueAttributes = append(queueAttributes, models.Attribute{Name: "MessageRetentionPeriod", Value: strconv.Itoa(queue.MessageRetentionPeriod)}) } if shouldInclude("ReceiveMessageWaitTimeSeconds") { queueAttributes = append(queueAttributes, models.Attribute{Name: "ReceiveMessageWaitTimeSeconds", Value: strconv.Itoa(queue.ReceiveMessageWaitTimeSeconds)}) } if shouldInclude("VisibilityTimeout") { queueAttributes = append(queueAttributes, models.Attribute{Name: "VisibilityTimeout", Value: strconv.Itoa(queue.VisibilityTimeout)}) } if shouldInclude("ApproximateNumberOfMessages") { queueAttributes = append(queueAttributes, models.Attribute{Name: "ApproximateNumberOfMessages", Value: strconv.Itoa(len(queue.Messages))}) } if shouldInclude("ApproximateNumberOfMessagesNotVisible") { queueAttributes = append(queueAttributes, models.Attribute{Name: "ApproximateNumberOfMessagesNotVisible", Value: strconv.Itoa(numberOfHiddenMessagesInQueue(*queue))}) } if shouldInclude("CreatedTimestamp") { queueAttributes = append(queueAttributes, models.Attribute{Name: "CreatedTimestamp", Value: "0000000000"}) } if shouldInclude("LastModifiedTimestamp") { queueAttributes = append(queueAttributes, models.Attribute{Name: "LastModifiedTimestamp", Value: "0000000000"}) } if shouldInclude("QueueArn") { queueAttributes = append(queueAttributes, models.Attribute{Name: "QueueArn", Value: queue.Arn}) } if shouldInclude("RedrivePolicy") && queue.DeadLetterQueue != nil { queueAttributes = append(queueAttributes, models.Attribute{ Name: "RedrivePolicy", Value: fmt.Sprintf(`{"maxReceiveCount":"%d", "deadLetterTargetArn":"%s"}`, queue.MaxReceiveCount, queue.DeadLetterQueue.Arn), }) } respStruct := models.GetQueueAttributesResponse{ Xmlns: models.BaseXmlns, Result: models.GetQueueAttributesResult{Attrs: queueAttributes}, Metadata: models.BaseResponseMetadata, } return http.StatusOK, respStruct }