// This is the approximate behavior of AWS SQS API. It seems a little weird in many cases, however, it works. func ParseCreateQueueAttributes(sqsQuery *urlutils.SQSQuery) (*QueueAttributes, *sqserr.SQSError) { var err *sqserr.SQSError out := NewQueueAttributes() attrs, err := urlutils.ParseNNotationAttr("Attribute.", sqsQuery.ParamsList, nil, NewReqQueueAttr) if err != nil { return nil, err } attrsSize := len(attrs) for i := 1; i <= attrsSize; i++ { v, ok := attrs[i] if !ok { return nil, sqserr.MalformedInputError("End of list found where not expected") } reqAttr, _ := v.(*ReqQueueAttr) if reqAttr.Name == "" { return nil, sqserr.MalformedInputError("End of list found where not expected") } if reqAttr.Value == "" { return nil, sqserr.EmptyValueError("No Value Found for " + reqAttr.Name) } err = out.HandleAttribute(reqAttr.Name, reqAttr.Value) if err != nil { return nil, err } } return out, nil }
func SendMessageBatch(pq *pqueue.PQueue, sqsQuery *urlutils.SQSQuery) sqs_response.SQSResponse { attrs, _ := urlutils.ParseNNotationAttr( "SendMessageBatchRequestEntry.", sqsQuery.ParamsList, nil, NewReqQueueAttr) attrsLen := len(attrs) checker, err := validation.NewBatchIdValidation(attrsLen) if err != nil { return err } // map used to detect duplicated ids. attrList := make([]*MessageBatchParams, 0, attrsLen) for i := 1; i <= attrsLen; i++ { a, ok := attrs[i] if !ok { return sqserr.MissingParameterError("The request is missing sequence %d", i) } p, _ := a.(*MessageBatchParams) if err = checker.Validate(p.Id); err != nil { return err } if err := validation.ValidateBatchRequestId(p.Id); err != nil { return err } attrList = append(attrList, p) } batchResponse := &SendMessageBatchResponse{ RequestId: "rreer", } for _, a := range attrList { resp := send_message.PushAMessage(pq, sqsQuery.SenderId, a.ParamsList) if resp.HttpCode() == 200 { batchResponse.ResultEntry = append(batchResponse.ResultEntry, resp.BatchResult(a.Id)) } else { batchResponse.ErrorEntry = append(batchResponse.ErrorEntry, resp.BatchResult(a.Id)) } } return batchResponse }
func ChangeMessageVisibilityBatch(pq *pqueue.PQueue, sqsQuery *urlutils.SQSQuery) sqs_response.SQSResponse { attrs, _ := urlutils.ParseNNotationAttr( "ChangeMessageVisibilityBatchRequestEntry.", sqsQuery.ParamsList, nil, NewVisibilityBatchParams) attrsLen := len(attrs) checker, err := validation.NewBatchIdValidation(attrsLen) if err != nil { return err } attrList := make([]*VisibilityBatchParams, 0, attrsLen) for i := 1; i <= attrsLen; i++ { a, ok := attrs[i] if !ok { return sqserr.MissingParameterError("The request is missing sequence %d", i) } p, _ := a.(*VisibilityBatchParams) if err = checker.Validate(p.Id); err != nil { return err } attrList = append(attrList, p) } output := &ChangeMessageVisibilityBatchResponse{ RequestId: "visibilitybatch", } for _, batchItem := range attrList { resp := pq.UpdateLockByRcpt(batchItem.ReceiptHandle, batchItem.VisibilityTimeout) if resp == mpqerr.ERR_INVALID_RECEIPT { e := sqserr.InvalidReceiptHandleError("The input receipt handle is not a valid receipt handle.") output.ErrorEntry = append(output.ErrorEntry, e.BatchResult(batchItem.Id)) } else { output.ResultEntry = append(output.ResultEntry, &OkChange{Id: batchItem.Id}) } } return output }
func SetQueueAttributes(pq *pqueue.PQueue, sqsQuery *urlutils.SQSQuery) sqs_response.SQSResponse { attrs, err := urlutils.ParseNNotationAttr("MessageAttribute.", sqsQuery.ParamsList, nil, NewAttribute) if err != nil { return err } attrsLen := len(attrs) params := &pqueue.PQueueParams{} for i := 1; i < attrsLen; i++ { a, ok := attrs[i] if !ok { return sqserr.InvalidParameterValueError("The request must contain non-empty message attribute name.") } attr, _ := a.(*Attribute) err = nil switch attr.Name { case "DelaySeconds": if v, e := strconv.ParseInt(attr.Value, 10, 0); e == nil { v := v * 1000 if v >= 0 && v <= conf.CFG_PQ.MaxDeliveryDelay { params.DeliveryDelay = &v continue } } return sqserr.InvalidAttributeValueError(AttrErrText, attr.Name) case "MaximumMessageSize": if v, e := strconv.ParseInt(attr.Value, 10, 0); e == nil { if v >= 1024 && v <= conf.CFG_PQ.MaxMessageSize { params.MaxMsgSize = &v continue } } return sqserr.InvalidAttributeValueError(AttrErrText, attr.Name) case "MessageRetentionPeriod": if v, e := strconv.ParseInt(attr.Value, 10, 0); e == nil { if v >= 60 && v <= 1209600 { v := v * 1000 params.MsgTTL = &v continue } } return sqserr.InvalidAttributeValueError(AttrErrText, attr.Name) case "ReceiveMessageWaitTimeSeconds": if v, e := strconv.ParseInt(attr.Value, 10, 0); e == nil { v := v * 1000 if v >= 60000 && v <= conf.CFG_PQ.MaxPopWaitTimeout { params.PopWaitTimeout = &v continue } } return sqserr.InvalidAttributeValueError(AttrErrText, attr.Name) case "VisibilityTimeout": if v, e := strconv.ParseInt(attr.Value, 10, 0); e == nil { v := v * 1000 if v > 0 && v <= conf.CFG_PQ.MaxLockTimeout { params.PopLockTimeout = &v continue } } return sqserr.InvalidAttributeValueError(AttrErrText, attr.Name) // These parameters are just ignored. case "Policy": case "ApproximateNumberOfMessages": case "ApproximateNumberOfMessagesDelayed": case "ApproximateNumberOfMessagesNotVisible": case "CreatedTimestamp": case "LastModifiedTimestamp": case "QueueArn": // Any unexpected attribute will produce unexpected attribute error. default: return sqserr.InvalidAttributeNameError("Unknown Attribute: %s", attr.Name) } } pq.SetParams(params) return &SetQueueAttributesResponse{ RequestId: "req", } }
func PushAMessage(pq *pqueue.PQueue, senderId string, paramList []string) sqs_response.SQSResponse { out := &MessageParams{ DelaySeconds: -1, MessageBody: "", } attrs, err := urlutils.ParseNNotationAttr("MessageAttribute.", paramList, out.Parse, NewReqQueueAttr) if err != nil { return err } attrsLen := len(attrs) outAttrs := make(map[string]*sqsmsg.UserAttribute) for i := 1; i <= attrsLen; i++ { a, ok := attrs[i] if !ok { return sqserr.InvalidParameterValueError("The request must contain non-empty message attribute name.") } reqMsgAttr, _ := a.(*ReqMsgAttr) sqs_err := validation.ValidateMessageAttrName(reqMsgAttr.Name) if sqs_err != nil { return sqs_err } sqs_err = validation.ValidateMessageAttrName(reqMsgAttr.DataType) if sqs_err != nil { return sqs_err } if reqMsgAttr.BinaryValue != "" && reqMsgAttr.StringValue != "" { return sqserr.InvalidParameterValueError( "Message attribute name '%s' has multiple values.", reqMsgAttr.Name) } if _, ok := outAttrs[reqMsgAttr.Name]; ok { return sqserr.InvalidParameterValueError( "Message attribute name '%s' already exists.", reqMsgAttr.Name) } if strings.HasPrefix(reqMsgAttr.DataType, "Number") { if _, err := strconv.Atoi(reqMsgAttr.StringValue); err != nil { return sqserr.InvalidParameterValueError( "Could not cast message attribute '%s' value to number.", reqMsgAttr.Name) } } if reqMsgAttr.BinaryValue != "" { if reqMsgAttr.DataType != "Binary" { return sqserr.InvalidParameterValueError( "The message attribute '%s' with type 'Binary' must use field 'Binary'", reqMsgAttr.Name) } outAttrs[reqMsgAttr.Name] = &sqsmsg.UserAttribute{ Type: reqMsgAttr.DataType, Value: reqMsgAttr.BinaryValue, } continue } if reqMsgAttr.StringValue != "" { if reqMsgAttr.DataType != "String" && reqMsgAttr.DataType != "Number" { return sqserr.InvalidParameterValueError( "The message attribute '%s' with type 'String' must use field 'String'", reqMsgAttr.Name) } outAttrs[reqMsgAttr.Name] = &sqsmsg.UserAttribute{ Type: reqMsgAttr.DataType, Value: reqMsgAttr.StringValue, } } } msgId := IdGen.RandId() if out.DelaySeconds < 0 { out.DelaySeconds = pq.Config().DeliveryDelay } else if out.DelaySeconds > conf.CFG_PQ.MaxDeliveryDelay { return sqserr.InvalidParameterValueError( "Delay secods must be between 0 and %d", conf.CFG_PQ.MaxDeliveryDelay/1000) } bodyMd5str := fmt.Sprintf("%x", md5.Sum(enc.UnsafeStringToBytes(out.MessageBody))) attrMd5 := CalcAttrMd5(outAttrs) msgPayload := sqsmsg.SQSMessagePayload{ UserAttributes: outAttrs, MD5OfMessageBody: bodyMd5str, MD5OfMessageAttributes: attrMd5, SenderId: senderId, SentTimestamp: strconv.FormatInt(utils.Uts(), 10), Payload: out.MessageBody, } d, marshalErr := msgPayload.Marshal() if marshalErr != nil { log.Error("Failed to serialize message payload: %v", err) } payload := enc.UnsafeBytesToString(d) resp := pq.Push(msgId, payload, pq.Config().MsgTtl, out.DelaySeconds, 1) if resp.IsError() { e, _ := resp.(error) return sqserr.InvalidParameterValueError(e.Error()) } return &SendMessageResponse{ MessageId: msgId, MD5OfMessageBody: bodyMd5str, MD5OfMessageAttributes: attrMd5, RequestId: "req", } }