github.com/aldelo/common@v1.5.1/wrapper/sqs/sqs.go (about)

     1  package sqs
     2  
     3  /*
     4   * Copyright 2020-2023 Aldelo, LP
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  // =================================================================================================================
    20  // AWS CREDENTIAL:
    21  //		use $> aws configure (to set aws access key and secret to target machine)
    22  //		Store AWS Access ID and Secret Key into Default Profile Using '$ aws configure' cli
    23  //
    24  // To Install & Setup AWS CLI on Host:
    25  //		1) https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html
    26  //				On Ubuntu, if host does not have zip and unzip:
    27  //					$> sudo apt install zip
    28  //					$> sudo apt install unzip
    29  //				On Ubuntu, to install AWS CLI v2:
    30  //					$> curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
    31  //					$> unzip awscliv2.zip
    32  //					$> sudo ./aws/install
    33  //		2) $> aws configure set region awsRegionName --profile default
    34  // 		3) $> aws configure
    35  //				follow prompts to enter Access ID and Secret Key
    36  //
    37  // AWS Region Name Reference:
    38  //		us-west-2, us-east-1, ap-northeast-1, etc
    39  //		See: https://docs.aws.amazon.com/general/latest/gr/rande.html
    40  // =================================================================================================================
    41  
    42  import (
    43  	"context"
    44  	"errors"
    45  	util "github.com/aldelo/common"
    46  	awshttp2 "github.com/aldelo/common/wrapper/aws"
    47  	"github.com/aldelo/common/wrapper/aws/awsregion"
    48  	"github.com/aldelo/common/wrapper/sqs/sqscreatequeueattribute"
    49  	"github.com/aldelo/common/wrapper/sqs/sqsgetqueueattribute"
    50  	"github.com/aldelo/common/wrapper/sqs/sqssetqueueattribute"
    51  	"github.com/aldelo/common/wrapper/sqs/sqssystemattribute"
    52  	"github.com/aldelo/common/wrapper/xray"
    53  	"github.com/aws/aws-sdk-go/aws"
    54  	"github.com/aws/aws-sdk-go/aws/session"
    55  	awssqs "github.com/aws/aws-sdk-go/service/sqs"
    56  	awsxray "github.com/aws/aws-xray-sdk-go/xray"
    57  	"net/http"
    58  	"strings"
    59  	"time"
    60  )
    61  
    62  // ================================================================================================================
    63  // STRUCTS
    64  // ================================================================================================================
    65  
    66  // SQS struct encapsulates the AWS SQS access functionality
    67  type SQS struct {
    68  	// define the AWS region that SQS is located at
    69  	AwsRegion awsregion.AWSRegion
    70  
    71  	// custom http2 client options
    72  	HttpOptions *awshttp2.HttpClientSettings
    73  
    74  	// store SQS client object
    75  	sqsClient *awssqs.SQS
    76  
    77  	_parentSegment *xray.XRayParentSegment
    78  }
    79  
    80  // SQSMessageResult struct contains the message result via Send... operations
    81  //
    82  // MessageId = Message ID from SQS after send... operation
    83  // MD5of... = MD5 of given data from SQS, PRIOR TO DATA URL-ENCODED by SQS,
    84  //
    85  //	use this MD5 from SQS response to verify local value MD5 to check if SQS received data properly
    86  //
    87  // FifoSequenceNumber = For FIFO SQS Queue only
    88  type SQSMessageResult struct {
    89  	MessageId              string
    90  	MD5ofMessageBody       string
    91  	MD5ofMessageAttributes string
    92  	FifoSequenceNumber     string
    93  }
    94  
    95  // SQSStandardMessage struct represents a standard queue message to be used in Send... operations
    96  //
    97  // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch
    98  type SQSStandardMessage struct {
    99  	Id                string
   100  	MessageBody       string
   101  	MessageAttributes map[string]*awssqs.MessageAttributeValue
   102  	DelaySeconds      int64
   103  }
   104  
   105  // SQSFifoMessage struct represents a fifo queue message to be used in Send... operations
   106  //
   107  // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch
   108  type SQSFifoMessage struct {
   109  	Id                     string
   110  	MessageDeduplicationId string
   111  	MessageGroupId         string
   112  	MessageBody            string
   113  	MessageAttributes      map[string]*awssqs.MessageAttributeValue
   114  }
   115  
   116  // SQSSuccessResult struct represents a Send... batch operation success result
   117  //
   118  // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch
   119  type SQSSuccessResult struct {
   120  	Id                     string
   121  	MessageId              string
   122  	MD5ofMessageBody       string
   123  	MD5ofMessageAttributes string
   124  	SequenceNumber         string
   125  }
   126  
   127  // SQSFailResult struct represents a Send... batch operation failure result
   128  //
   129  // Id = up to 80 characters, alpha-numeric / dash, and unique, identifies the message within batch
   130  type SQSFailResult struct {
   131  	Id          string
   132  	Code        string
   133  	Message     string
   134  	SenderFault bool
   135  }
   136  
   137  // SQSReceivedMessage struct represents received message content elements
   138  type SQSReceivedMessage struct {
   139  	MessageId              string
   140  	Body                   string
   141  	MessageAttributes      map[string]*awssqs.MessageAttributeValue
   142  	SystemAttributes       map[sqssystemattribute.SQSSystemAttribute]string
   143  	MD5ofBody              string
   144  	MD5ofMessageAttributes string
   145  	ReceiptHandle          string
   146  }
   147  
   148  // SQSChangeVisibilityRequest struct represents the request data for change visibility for a message in sqs queue
   149  type SQSChangeVisibilityRequest struct {
   150  	Id                       string
   151  	ReceiptHandle            string
   152  	VisibilityTimeOutSeconds int64
   153  }
   154  
   155  // SQSDeleteMessageRequest struct represents the request data to delete a message from sqs queue
   156  type SQSDeleteMessageRequest struct {
   157  	Id            string
   158  	ReceiptHandle string
   159  }
   160  
   161  // ================================================================================================================
   162  // STRUCTS FUNCTIONS
   163  // ================================================================================================================
   164  
   165  // ----------------------------------------------------------------------------------------------------------------
   166  // utility functions
   167  // ----------------------------------------------------------------------------------------------------------------
   168  
   169  // Connect will establish a connection to the SQS service
   170  func (s *SQS) Connect(parentSegment ...*xray.XRayParentSegment) (err error) {
   171  	if xray.XRayServiceOn() {
   172  		if len(parentSegment) > 0 {
   173  			s._parentSegment = parentSegment[0]
   174  		}
   175  
   176  		seg := xray.NewSegment("SQS-Connect", s._parentSegment)
   177  		defer seg.Close()
   178  		defer func() {
   179  			_ = seg.Seg.AddMetadata("SQS-AWS-Region", s.AwsRegion)
   180  
   181  			if err != nil {
   182  				_ = seg.Seg.AddError(err)
   183  			}
   184  		}()
   185  
   186  		err = s.connectInternal()
   187  
   188  		if err == nil {
   189  			awsxray.AWS(s.sqsClient.Client)
   190  		}
   191  
   192  		return err
   193  	} else {
   194  		return s.connectInternal()
   195  	}
   196  }
   197  
   198  // Connect will establish a connection to the SQS service
   199  func (s *SQS) connectInternal() error {
   200  	// clean up prior sqs client reference
   201  	s.sqsClient = nil
   202  
   203  	if !s.AwsRegion.Valid() || s.AwsRegion == awsregion.UNKNOWN {
   204  		return errors.New("Connect to SQS Failed: (AWS Session Error) " + "Region is Required")
   205  	}
   206  
   207  	// create custom http2 client if needed
   208  	var httpCli *http.Client
   209  	var httpErr error
   210  
   211  	if s.HttpOptions == nil {
   212  		s.HttpOptions = new(awshttp2.HttpClientSettings)
   213  	}
   214  
   215  	// use custom http2 client
   216  	h2 := &awshttp2.AwsHttp2Client{
   217  		Options: s.HttpOptions,
   218  	}
   219  
   220  	if httpCli, httpErr = h2.NewHttp2Client(); httpErr != nil {
   221  		return errors.New("Connect to SQS Failed: (AWS Session Error) " + "Create Custom http2 Client Errored = " + httpErr.Error())
   222  	}
   223  
   224  	// establish aws session connection
   225  	if sess, err := session.NewSession(
   226  		&aws.Config{
   227  			Region:     aws.String(s.AwsRegion.Key()),
   228  			HTTPClient: httpCli,
   229  		}); err != nil {
   230  		// aws session error
   231  		return errors.New("Connect to SQS Failed: (AWS Session Error) " + err.Error())
   232  	} else {
   233  		// create cached objects for shared use
   234  		s.sqsClient = awssqs.New(sess)
   235  
   236  		if s.sqsClient == nil {
   237  			return errors.New("Connect to SQS Client Failed: (New SQS Client Connection) " + "Connection Object Nil")
   238  		}
   239  
   240  		// connect successful
   241  		return nil
   242  	}
   243  }
   244  
   245  // Disconnect will clear sqs client
   246  func (s *SQS) Disconnect() {
   247  	s.sqsClient = nil
   248  }
   249  
   250  // UpdateParentSegment updates this struct's xray parent segment, if no parent segment, set nil
   251  func (s *SQS) UpdateParentSegment(parentSegment *xray.XRayParentSegment) {
   252  	s._parentSegment = parentSegment
   253  }
   254  
   255  // ----------------------------------------------------------------------------------------------------------------
   256  // internal helper methods
   257  // ----------------------------------------------------------------------------------------------------------------
   258  
   259  // toAwsCreateQueueAttributes will convert from strongly typed to aws accepted map
   260  func (s *SQS) toAwsCreateQueueAttributes(attributes map[sqscreatequeueattribute.SQSCreateQueueAttribute]string) (newMap map[string]*string) {
   261  	// validate
   262  	if attributes == nil {
   263  		return nil
   264  	}
   265  
   266  	// make map
   267  	newMap = make(map[string]*string)
   268  
   269  	for k, v := range attributes {
   270  		if k.Valid() && k != sqscreatequeueattribute.UNKNOWN {
   271  			newMap[k.Key()] = aws.String(v)
   272  		}
   273  	}
   274  
   275  	return newMap
   276  }
   277  
   278  // fromAwsCreateQueueAttributes will convert from aws map to strongly typed map
   279  func (s *SQS) fromAwsCreateQueueAttributes(attributes map[string]*string) (newMap map[sqscreatequeueattribute.SQSCreateQueueAttribute]string) {
   280  	// validate
   281  	if attributes == nil {
   282  		return nil
   283  	}
   284  
   285  	// make map
   286  	newMap = make(map[sqscreatequeueattribute.SQSCreateQueueAttribute]string)
   287  	var conv sqscreatequeueattribute.SQSCreateQueueAttribute
   288  
   289  	for k, v := range attributes {
   290  		if util.LenTrim(k) > 0 {
   291  			v1 := aws.StringValue(v)
   292  
   293  			if k1, err := conv.ParseByKey(k); err == nil {
   294  				newMap[k1] = v1
   295  			}
   296  		}
   297  	}
   298  
   299  	return newMap
   300  }
   301  
   302  // toAwsGetQueueAttributes will convert from strongly typed to aws accepted map
   303  func (s *SQS) toAwsGetQueueAttributes(attributes map[sqsgetqueueattribute.SQSGetQueueAttribute]string) (newMap map[string]*string) {
   304  	// validate
   305  	if attributes == nil {
   306  		return nil
   307  	}
   308  
   309  	// make map
   310  	newMap = make(map[string]*string)
   311  
   312  	for k, v := range attributes {
   313  		if k.Valid() && k != sqsgetqueueattribute.UNKNOWN {
   314  			newMap[k.Key()] = aws.String(v)
   315  		}
   316  	}
   317  
   318  	return newMap
   319  }
   320  
   321  // fromAwsGetQueueAttributes will convert from aws map to strongly typed map
   322  func (s *SQS) fromAwsGetQueueAttributes(attributes map[string]*string) (newMap map[sqsgetqueueattribute.SQSGetQueueAttribute]string) {
   323  	// validate
   324  	if attributes == nil {
   325  		return nil
   326  	}
   327  
   328  	// make map
   329  	newMap = make(map[sqsgetqueueattribute.SQSGetQueueAttribute]string)
   330  	var conv sqsgetqueueattribute.SQSGetQueueAttribute
   331  
   332  	for k, v := range attributes {
   333  		if util.LenTrim(k) > 0 {
   334  			v1 := aws.StringValue(v)
   335  
   336  			if k1, err := conv.ParseByKey(k); err == nil {
   337  				newMap[k1] = v1
   338  			}
   339  		}
   340  	}
   341  
   342  	return newMap
   343  }
   344  
   345  // toAwsSetQueueAttributes will convert from strongly typed to aws accepted map
   346  func (s *SQS) toAwsSetQueueAttributes(attributes map[sqssetqueueattribute.SQSSetQueueAttribute]string) (newMap map[string]*string) {
   347  	// validate
   348  	if attributes == nil {
   349  		return nil
   350  	}
   351  
   352  	// make map
   353  	newMap = make(map[string]*string)
   354  
   355  	for k, v := range attributes {
   356  		if k.Valid() && k != sqssetqueueattribute.UNKNOWN {
   357  			newMap[k.Key()] = aws.String(v)
   358  		}
   359  	}
   360  
   361  	return newMap
   362  }
   363  
   364  // fromAwsSetQueueAttributes will convert from aws map to strongly typed map
   365  func (s *SQS) fromAwsSetQueueAttributes(attributes map[string]*string) (newMap map[sqssetqueueattribute.SQSSetQueueAttribute]string) {
   366  	// validate
   367  	if attributes == nil {
   368  		return nil
   369  	}
   370  
   371  	// make map
   372  	newMap = make(map[sqssetqueueattribute.SQSSetQueueAttribute]string)
   373  	var conv sqssetqueueattribute.SQSSetQueueAttribute
   374  
   375  	for k, v := range attributes {
   376  		if util.LenTrim(k) > 0 {
   377  			v1 := aws.StringValue(v)
   378  
   379  			if k1, err := conv.ParseByKey(k); err == nil {
   380  				newMap[k1] = v1
   381  			}
   382  		}
   383  	}
   384  
   385  	return newMap
   386  }
   387  
   388  // toAwsSystemAttributes will convert from strongly typed to aws accepted map
   389  func (s *SQS) toAwsSystemAttributes(attributes map[sqssystemattribute.SQSSystemAttribute]string) (newMap map[string]*string) {
   390  	// validate
   391  	if attributes == nil {
   392  		return nil
   393  	}
   394  
   395  	// make map
   396  	newMap = make(map[string]*string)
   397  
   398  	for k, v := range attributes {
   399  		if k.Valid() && k != sqssystemattribute.UNKNOWN {
   400  			newMap[k.Key()] = aws.String(v)
   401  		}
   402  	}
   403  
   404  	return newMap
   405  }
   406  
   407  // fromAwsSystemAttributes will convert from aws map to strongly typed map
   408  func (s *SQS) fromAwsSystemAttributes(attributes map[string]*string) (newMap map[sqssystemattribute.SQSSystemAttribute]string) {
   409  	// validate
   410  	if attributes == nil {
   411  		return nil
   412  	}
   413  
   414  	// make map
   415  	newMap = make(map[sqssystemattribute.SQSSystemAttribute]string)
   416  	var conv sqssystemattribute.SQSSystemAttribute
   417  
   418  	for k, v := range attributes {
   419  		if util.LenTrim(k) > 0 {
   420  			v1 := aws.StringValue(v)
   421  
   422  			if k1, err := conv.ParseByKey(k); err == nil {
   423  				newMap[k1] = v1
   424  			}
   425  		}
   426  	}
   427  
   428  	return newMap
   429  }
   430  
   431  // ----------------------------------------------------------------------------------------------------------------
   432  // queue management methods
   433  // ----------------------------------------------------------------------------------------------------------------
   434  
   435  // GetQueueArnFromQueueUrl encodes arn from url data
   436  func (s *SQS) GetQueueArnFromQueue(queueUrl string, timeoutDuration ...time.Duration) (arn string, err error) {
   437  	seg := xray.NewSegmentNullable("SQS-GetQueueArnFromQueue", s._parentSegment)
   438  
   439  	if seg != nil {
   440  		defer seg.Close()
   441  		defer func() {
   442  			_ = seg.Seg.AddMetadata("SQS-GetQueueArnFromQueue-QueueURL", queueUrl)
   443  			_ = seg.Seg.AddMetadata("SQS-GetQueueArnFromQueue-Result-ARN", arn)
   444  
   445  			if err != nil {
   446  				_ = seg.Seg.AddError(err)
   447  			}
   448  		}()
   449  	}
   450  
   451  	if attr, err := s.GetQueueAttributes(queueUrl, []sqsgetqueueattribute.SQSGetQueueAttribute{
   452  		sqsgetqueueattribute.QueueArn,
   453  	}, timeoutDuration...); err != nil {
   454  		// error
   455  		return "", err
   456  	} else {
   457  		// found attribute
   458  		arn = attr[sqsgetqueueattribute.QueueArn]
   459  		return arn, nil
   460  	}
   461  }
   462  
   463  // CreateQueue will create a queue in SQS,
   464  // if Queue is a FIFO, then queueName must suffix with .fifo, otherwise name it without .fifo suffix
   465  //
   466  // Parameters:
   467  //  1. queueName = required, up to 80 characters alpha-numeric and dash, case-sensitive
   468  //     if fifo queue, must suffix name with '.fifo' (fifo queue guarantees fifo and delivery once but only 300 / second rate)
   469  //  2. attributes = optional, map of create queue attribute key value pairs
   470  //  3. timeOutDuration = optional, time out duration to use for context if applicable
   471  //
   472  // Return Values:
   473  //  1. queueUrl = the queue url after queue was created
   474  //  2. err = error info if any
   475  //
   476  // Create Queue Attributes: (Key = Expected Value)
   477  //
   478  //	  The following lists the names, descriptions, and values of the special request parameters that the CreateQueue action uses:
   479  //			1) DelaySeconds = The length of time, in seconds, for which the delivery of all messages in the queue is delayed.
   480  //							  Valid values: An integer from 0 to 900 seconds (15 minutes). Default: 0.
   481  //			2)MaximumMessageSize = The limit of how many bytes a message can contain before Amazon SQS rejects it.
   482  //									Valid values: An integer from 1,024 bytes (1 KiB) to 262,144 bytes (256 KiB). Default: 262,144 (256 KiB).
   483  //			3) MessageRetentionPeriod = The length of time, in seconds, for which Amazon SQS retains a message.
   484  //										Valid values: An integer from 60 seconds (1 minute) to 1,209,600 seconds (14 days). Default: 345,600 (4 days).
   485  //			4) Policy = The queue's policy. A valid AWS policy.
   486  //						For more information about policy structure,
   487  //							see Overview of AWS IAM Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/PoliciesOverview.html)
   488  //							in the Amazon IAM User Guide.
   489  //			5) ReceiveMessageWaitTimeSeconds = The length of time, in seconds, for which a ReceiveMessage action waits for a message to arrive.
   490  //											   Valid values: An integer from 0 to 20 (seconds). Default: 0.
   491  //			6) RedrivePolicy = The string that includes the parameters for the dead-letter queue functionality of the source queue as a JSON object.
   492  //							   For more information about the redrive policy and dead-letter queues,
   493  //							   		see Using Amazon SQS Dead-Letter Queues (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)
   494  //							   		in the Amazon Simple Queue Service Developer Guide.
   495  //			7) deadLetterTargetArn = The Amazon Resource Name (ARN) of the dead-letter queue,
   496  //									 to which Amazon SQS moves messages after the value of maxReceiveCount is exceeded.
   497  //			8) maxReceiveCount = The number of times a message is delivered to the source queue before being moved to the dead-letter queue.
   498  //								 When the ReceiveCount for a message exceeds the maxReceiveCount for a queue,
   499  //								 	Amazon SQS moves the message to the dead-letter-queue.
   500  //								 The dead-letter queue of a FIFO queue must also be a FIFO queue.
   501  //								 Similarly, the dead-letter queue of a standard queue must also be a standard queue.
   502  //			9) VisibilityTimeout = The visibility timeout for the queue, in seconds.
   503  //								   Valid values: An integer from 0 to 43,200 (12 hours). Default: 30.
   504  //								   For more information about the visibility timeout,
   505  //								   		see Visibility Timeout (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)
   506  //								   		in the Amazon Simple Queue Service Developer Guide.
   507  //
   508  //	  The following attributes apply only to server-side-encryption,
   509  //	  (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html):
   510  //			10) KmsMasterKeyId = The ID of an AWS-managed customer master key (CMK) for Amazon SQS or a custom CMK.
   511  //								 For more information, see Key Terms (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-sse-key-terms).
   512  //								 While the alias of the AWS-managed CMK for Amazon SQS is always alias/aws/sqs,
   513  //								 	the alias of a custom CMK can, for example, be alias/MyAlias .
   514  //								 For more examples, see KeyId (https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html#API_DescribeKey_RequestParameters)
   515  //								 	in the AWS Key Management Service API Reference.
   516  //			11)KmsDataKeyReusePeriodSeconds = The length of time, in seconds, for which Amazon SQS can reuse a data key (https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys)
   517  //											   		to encrypt or decrypt messages before calling AWS KMS again.
   518  //											   An integer representing seconds,
   519  //												   between 60 seconds (1 minute) and 86,400 seconds (24 hours). Default: 300 (5 minutes).
   520  //											   A shorter time period provides better security but results in more calls to KMS,
   521  //											   		which might incur charges after Free Tier.
   522  //											   For more information, see How Does the Data Key Reuse Period Work?
   523  //												   (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-how-does-the-data-key-reuse-period-work).
   524  //
   525  //	  The following attributes apply only to FIFO (first-in-first-out) queues,
   526  //	  (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html):
   527  //		 	12) FifoQueue = (AT NEW QUEUE CREATION ONLY) Designates a queue as FIFO. Valid values: true, false.
   528  //							If you don't specify the FifoQueue attribute, Amazon SQS creates a standard queue.
   529  //							You can provide this attribute only during queue creation. You can't change it for an existing queue.
   530  //							When you set this attribute, you must also provide the MessageGroupId for your messages explicitly.
   531  //							For more information, see FIFO Queue Logic
   532  //								(https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-understanding-logic)
   533  //								in the Amazon Simple Queue Service Developer Guide.
   534  //			13) ContentBasedDeduplication = Enables content-based deduplication. Valid values: true, false.
   535  //											For more information, see Exactly-Once Processing
   536  //												(https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing)
   537  //												in the Amazon Simple Queue Service Developer Guide.
   538  //											Every message must have a unique MessageDeduplicationId, You may provide a MessageDeduplicationId explicitly.
   539  //											If you aren't able to provide a MessageDeduplicationId
   540  //												and you enable ContentBasedDeduplication for your queue,
   541  //												Amazon SQS uses a SHA-256 hash to generate the MessageDeduplicationId
   542  //												using the body of the message (but not the attributes of the message).
   543  //											If you don't provide a MessageDeduplicationId and the queue doesn't have ContentBasedDeduplication set,
   544  //												the action fails with an error.
   545  //											If the queue has ContentBasedDeduplication set, your MessageDeduplicationId overrides the generated one.
   546  //											When ContentBasedDeduplication is in effect,
   547  //												messages with identical content sent within the deduplication interval are treated as duplicates,
   548  //												and only one copy of the message is delivered.
   549  //											If you send one message with ContentBasedDeduplication enabled,
   550  //												and then another message with a MessageDeduplicationId that is the same as the one generated,
   551  //												for the first MessageDeduplicationId, the two messages are treated as duplicates,
   552  //												and only one copy of the message is delivered.
   553  func (s *SQS) CreateQueue(queueName string,
   554  	attributes map[sqscreatequeueattribute.SQSCreateQueueAttribute]string,
   555  	timeOutDuration ...time.Duration) (queueUrl string, err error) {
   556  	segCtx := context.Background()
   557  	segCtxSet := false
   558  
   559  	seg := xray.NewSegmentNullable("SQS-CreateQueue", s._parentSegment)
   560  
   561  	if seg != nil {
   562  		segCtx = seg.Ctx
   563  		segCtxSet = true
   564  
   565  		defer seg.Close()
   566  		defer func() {
   567  			_ = seg.Seg.AddMetadata("SQS-CreateQueue-QueueName", queueName)
   568  			_ = seg.Seg.AddMetadata("SQS-CreateQueue-Attributes", attributes)
   569  			_ = seg.Seg.AddMetadata("SQS-CreateQueue-Result-QueueURL", queueUrl)
   570  
   571  			if err != nil {
   572  				_ = seg.Seg.AddError(err)
   573  			}
   574  		}()
   575  	}
   576  
   577  	// validate
   578  	if s.sqsClient == nil {
   579  		err = errors.New("CreateQueue Failed: " + "SQS Client is Required")
   580  		return "", err
   581  	}
   582  
   583  	if util.LenTrim(queueName) <= 0 {
   584  		err = errors.New("CreateQueue Failed: " + "Queue Name is Required")
   585  		return "", err
   586  	}
   587  
   588  	// create input object
   589  	input := &awssqs.CreateQueueInput{
   590  		QueueName: aws.String(queueName),
   591  	}
   592  
   593  	if attributes != nil {
   594  		input.Attributes = s.toAwsCreateQueueAttributes(attributes)
   595  	}
   596  
   597  	// perform action
   598  	var output *awssqs.CreateQueueOutput
   599  
   600  	if len(timeOutDuration) > 0 {
   601  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   602  		defer cancel()
   603  
   604  		output, err = s.sqsClient.CreateQueueWithContext(ctx, input)
   605  	} else {
   606  		if segCtxSet {
   607  			output, err = s.sqsClient.CreateQueueWithContext(segCtx, input)
   608  		} else {
   609  			output, err = s.sqsClient.CreateQueue(input)
   610  		}
   611  	}
   612  
   613  	// evaluate result
   614  	if err != nil {
   615  		err = errors.New("CreateQueue Failed: (Create Action) " + err.Error())
   616  		return "", err
   617  	} else {
   618  		queueUrl = aws.StringValue(output.QueueUrl)
   619  		return queueUrl, nil
   620  	}
   621  }
   622  
   623  // GetQueueUrl returns the queue url for specific SQS queue
   624  //
   625  // queueName = required, case-sensitive
   626  func (s *SQS) GetQueueUrl(queueName string, timeOutDuration ...time.Duration) (queueUrl string, notFound bool, err error) {
   627  	segCtx := context.Background()
   628  	segCtxSet := false
   629  
   630  	seg := xray.NewSegmentNullable("SQS-GetQueueUrl", s._parentSegment)
   631  
   632  	if seg != nil {
   633  		segCtx = seg.Ctx
   634  		segCtxSet = true
   635  
   636  		defer seg.Close()
   637  		defer func() {
   638  			_ = seg.Seg.AddMetadata("SQS-GetQueueUrl-QueueName", queueName)
   639  			_ = seg.Seg.AddMetadata("SQS-GetQueueUrl-Result-Not-Found", notFound)
   640  			_ = seg.Seg.AddMetadata("SQS-GetQueueUrl-Result-QueueURL", queueUrl)
   641  
   642  			if err != nil {
   643  				_ = seg.Seg.AddError(err)
   644  			}
   645  		}()
   646  	}
   647  
   648  	// validate
   649  	if s.sqsClient == nil {
   650  		notFound = true
   651  		err = errors.New("GetQueueUrl Failed: " + "SQS Client is Required")
   652  		return "", notFound, err
   653  	}
   654  
   655  	if util.LenTrim(queueName) <= 0 {
   656  		notFound = true
   657  		err = errors.New("GetQueueUrl Failed: " + "Queue Name is Required")
   658  		return "", notFound, err
   659  	}
   660  
   661  	// create input object
   662  	input := &awssqs.GetQueueUrlInput{
   663  		QueueName: aws.String(queueName),
   664  	}
   665  
   666  	// perform action
   667  	var output *awssqs.GetQueueUrlOutput
   668  
   669  	if len(timeOutDuration) > 0 {
   670  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   671  		defer cancel()
   672  
   673  		output, err = s.sqsClient.GetQueueUrlWithContext(ctx, input)
   674  	} else {
   675  		if segCtxSet {
   676  			output, err = s.sqsClient.GetQueueUrlWithContext(segCtx, input)
   677  		} else {
   678  			output, err = s.sqsClient.GetQueueUrl(input)
   679  		}
   680  	}
   681  
   682  	// evaluate result
   683  	if err != nil {
   684  		if awshttp2.ToAwsError(err).Code() == awssqs.ErrCodeQueueDoesNotExist {
   685  			// queue does not exist - based on error code
   686  			notFound = true
   687  			return "", notFound, nil
   688  
   689  		} else if strings.Contains(strings.ToUpper(err.Error()), "THE SPECIFIED QUEUE DOES NOT EXIST") {
   690  			// queue does not exist - based on error message
   691  			notFound = true
   692  			return "", notFound, nil
   693  
   694  		} else {
   695  			// error
   696  			notFound = true
   697  			err = errors.New("GetQueueUrl Failed: (Get Action) " + err.Error())
   698  			return "", notFound, err
   699  
   700  		}
   701  	} else {
   702  		queueUrl = aws.StringValue(output.QueueUrl)
   703  		return queueUrl, false, nil
   704  
   705  	}
   706  }
   707  
   708  // PurgeQueue will delete all messages within the SQS queue indicated by the queueUrl,
   709  // deletion of messages will take up to 60 seconds,
   710  // it is advisable to wait 60 seconds before attempting to use the queue again (to ensure purge completion)
   711  //
   712  // queueUrl = required, case-sensitive
   713  func (s *SQS) PurgeQueue(queueUrl string, timeOutDuration ...time.Duration) (err error) {
   714  	segCtx := context.Background()
   715  	segCtxSet := false
   716  
   717  	seg := xray.NewSegmentNullable("SQS-PurgeQueue", s._parentSegment)
   718  
   719  	if seg != nil {
   720  		segCtx = seg.Ctx
   721  		segCtxSet = true
   722  
   723  		defer seg.Close()
   724  		defer func() {
   725  			_ = seg.Seg.AddMetadata("SQS-PurgeQueue-QueueURL", queueUrl)
   726  
   727  			if err != nil {
   728  				_ = seg.Seg.AddError(err)
   729  			}
   730  		}()
   731  	}
   732  
   733  	// validate
   734  	if s.sqsClient == nil {
   735  		err = errors.New("PurgeQueue Failed: " + "SQS Client is Required")
   736  		return err
   737  	}
   738  
   739  	if util.LenTrim(queueUrl) <= 0 {
   740  		err = errors.New("PurgeQueue Failed: " + "Queue Url is Required")
   741  		return err
   742  	}
   743  
   744  	// create input object
   745  	input := &awssqs.PurgeQueueInput{
   746  		QueueUrl: aws.String(queueUrl),
   747  	}
   748  
   749  	// perform action
   750  	if len(timeOutDuration) > 0 {
   751  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   752  		defer cancel()
   753  
   754  		_, err = s.sqsClient.PurgeQueueWithContext(ctx, input)
   755  	} else {
   756  		if segCtxSet {
   757  			_, err = s.sqsClient.PurgeQueueWithContext(segCtx, input)
   758  		} else {
   759  			_, err = s.sqsClient.PurgeQueue(input)
   760  		}
   761  	}
   762  
   763  	// evaluate result
   764  	if err != nil {
   765  		err = errors.New("PurgeQueue Failed: (Purge Action) " + err.Error())
   766  		return err
   767  	} else {
   768  		return nil
   769  	}
   770  }
   771  
   772  // DeleteQueue will delete the given SQS queue based on the queueUrl,
   773  // there is a 60 second backoff time for the queue deletion to complete,
   774  // do not send more messages to the queue within the 60 second deletion window of time
   775  //
   776  // queueUrl = required, case-sensitive
   777  func (s *SQS) DeleteQueue(queueUrl string, timeOutDuration ...time.Duration) (err error) {
   778  	segCtx := context.Background()
   779  	segCtxSet := false
   780  
   781  	seg := xray.NewSegmentNullable("SQS-DeleteQueue", s._parentSegment)
   782  
   783  	if seg != nil {
   784  		segCtx = seg.Ctx
   785  		segCtxSet = true
   786  
   787  		defer seg.Close()
   788  		defer func() {
   789  			_ = seg.Seg.AddMetadata("SQS-DeleteQueue-QueueURL", queueUrl)
   790  
   791  			if err != nil {
   792  				_ = seg.Seg.AddError(err)
   793  			}
   794  		}()
   795  	}
   796  
   797  	// validate
   798  	if s.sqsClient == nil {
   799  		err = errors.New("DeleteQueue Failed: " + "SQS Client is Required")
   800  		return err
   801  	}
   802  
   803  	if util.LenTrim(queueUrl) <= 0 {
   804  		err = errors.New("DeleteQueue Failed: " + "Queue Url is Required")
   805  		return err
   806  	}
   807  
   808  	// create input object
   809  	input := &awssqs.DeleteQueueInput{
   810  		QueueUrl: aws.String(queueUrl),
   811  	}
   812  
   813  	// perform action
   814  	if len(timeOutDuration) > 0 {
   815  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   816  		defer cancel()
   817  
   818  		_, err = s.sqsClient.DeleteQueueWithContext(ctx, input)
   819  	} else {
   820  		if segCtxSet {
   821  			_, err = s.sqsClient.DeleteQueueWithContext(segCtx, input)
   822  		} else {
   823  			_, err = s.sqsClient.DeleteQueue(input)
   824  		}
   825  	}
   826  
   827  	// evaluate result
   828  	if err != nil {
   829  		err = errors.New("DeleteQueue Failed: (Delete Action) " + err.Error())
   830  		return err
   831  	} else {
   832  		return nil
   833  	}
   834  }
   835  
   836  // ListQueues will return a string slice of queue Urls
   837  //
   838  // Parameters:
   839  //  1. queueNamePrefix = optional, match queues based on the queue name that starts with the specified prefix value, case-sensitive
   840  //  2. nextToken = optional, if the prior call to ListQueues expected more values, a more...token is returned, to be used in this parameter
   841  //  3. maxResults = optional, if > 0, the maximum results limited to
   842  //  4. timeOutDuration = optional, timeout value to use within context
   843  //
   844  // Return Values:
   845  //  1. queueUrlsList = string slice of queue urls
   846  //  2. moreQueueUrlsNextToken = if more queue urls expected, use this token in the next method call by passing into nextToken parameter
   847  //  3. err = error info if any
   848  func (s *SQS) ListQueues(queueNamePrefix string,
   849  	nextToken string,
   850  	maxResults int64,
   851  	timeOutDuration ...time.Duration) (queueUrlsList []string, moreQueueUrlsNextToken string, err error) {
   852  	segCtx := context.Background()
   853  	segCtxSet := false
   854  
   855  	seg := xray.NewSegmentNullable("SQS-ListQueues", s._parentSegment)
   856  
   857  	if seg != nil {
   858  		segCtx = seg.Ctx
   859  		segCtxSet = true
   860  
   861  		defer seg.Close()
   862  		defer func() {
   863  			_ = seg.Seg.AddMetadata("SQS-ListQueues-QueueNamePrefix", queueNamePrefix)
   864  			_ = seg.Seg.AddMetadata("SQS-ListQueues-NextToken", nextToken)
   865  			_ = seg.Seg.AddMetadata("SQS-ListQueues-MaxResults", maxResults)
   866  			_ = seg.Seg.AddMetadata("SQS-ListQueues-Result-QueueUrlsList", queueUrlsList)
   867  			_ = seg.Seg.AddMetadata("SQS-ListQueues-Result-NextToken", moreQueueUrlsNextToken)
   868  
   869  			if err != nil {
   870  				_ = seg.Seg.AddError(err)
   871  			}
   872  		}()
   873  	}
   874  
   875  	// validate
   876  	if s.sqsClient == nil {
   877  		err = errors.New("ListQueues Failed: " + "SQS Client is Required")
   878  		return nil, "", err
   879  	}
   880  
   881  	// create input object
   882  	input := &awssqs.ListQueuesInput{}
   883  
   884  	if util.LenTrim(queueNamePrefix) > 0 {
   885  		input.QueueNamePrefix = aws.String(queueNamePrefix)
   886  	}
   887  
   888  	if util.LenTrim(nextToken) > 0 {
   889  		input.NextToken = aws.String(nextToken)
   890  	}
   891  
   892  	if maxResults > 0 {
   893  		input.MaxResults = aws.Int64(maxResults)
   894  	}
   895  
   896  	// perform action
   897  	var output *awssqs.ListQueuesOutput
   898  
   899  	if len(timeOutDuration) > 0 {
   900  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   901  		defer cancel()
   902  
   903  		output, err = s.sqsClient.ListQueuesWithContext(ctx, input)
   904  	} else {
   905  		if segCtxSet {
   906  			output, err = s.sqsClient.ListQueuesWithContext(segCtx, input)
   907  		} else {
   908  			output, err = s.sqsClient.ListQueues(input)
   909  		}
   910  	}
   911  
   912  	// evaluate result
   913  	if err != nil {
   914  		err = errors.New("ListQueues Failed: (List Action) " + err.Error())
   915  		return nil, "", err
   916  	} else {
   917  		queueUrlsList = aws.StringValueSlice(output.QueueUrls)
   918  		moreQueueUrlsNextToken = aws.StringValue(output.NextToken)
   919  		return queueUrlsList, moreQueueUrlsNextToken, nil
   920  	}
   921  }
   922  
   923  // ListDeadLetterSourceQueues will retrieve a list of source queue urls,
   924  // that have its RedrivePolicy set to the given Dead Letter Queue as specified in queueUrl parameter
   925  //
   926  // Parameters:
   927  //  1. queueUrl= required, the dead letter queue url for which to list the dead letter source queues, case-sensitive
   928  //  2. nextToken = optional, if the prior call to ListDeadLetterSourceQueues expected more values, a more...token is returned, to be used in this parameter
   929  //  3. maxResults = optional, if > 0, the maximum results limited to
   930  //  4. timeOutDuration = optional, timeout value to use within context
   931  //
   932  // Return Values:
   933  //  1. queueUrlsList = string slice of source queue urls that points to the dead letter queue as indicated in queueUrl parameter
   934  //  2. moreQueueUrlsNextToken = if more queue urls expected, use this token in the next method call by passing into nextToken parameter
   935  //  3. err = error info if any
   936  func (s *SQS) ListDeadLetterSourceQueues(queueUrl string,
   937  	nextToken string,
   938  	maxResults int64,
   939  	timeOutDuration ...time.Duration) (queueUrlsList []string, moreQueueUrlsNextToken string, err error) {
   940  	segCtx := context.Background()
   941  	segCtxSet := false
   942  
   943  	seg := xray.NewSegmentNullable("SQS-ListDeadLetterSourceQueues", s._parentSegment)
   944  
   945  	if seg != nil {
   946  		segCtx = seg.Ctx
   947  		segCtxSet = true
   948  
   949  		defer seg.Close()
   950  		defer func() {
   951  			_ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-QueueURL", queueUrl)
   952  			_ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-NextToken", nextToken)
   953  			_ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-MaxResults", maxResults)
   954  			_ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-Result-QueueUrlsList", queueUrlsList)
   955  			_ = seg.Seg.AddMetadata("SQS-ListDeadLetterSourceQueues-Result-NextToken", moreQueueUrlsNextToken)
   956  
   957  			if err != nil {
   958  				_ = seg.Seg.AddError(err)
   959  			}
   960  		}()
   961  	}
   962  
   963  	// validate
   964  	if s.sqsClient == nil {
   965  		err = errors.New("ListDeadLetterSourceQueues Failed: " + "SQS Client is Required")
   966  		return nil, "", err
   967  	}
   968  
   969  	if util.LenTrim(queueUrl) <= 0 {
   970  		err = errors.New("ListDeadLetterSourceQueues Failed: " + "Dead Letter Queue Url is Required")
   971  		return nil, "", err
   972  	}
   973  
   974  	// create input object
   975  	input := &awssqs.ListDeadLetterSourceQueuesInput{
   976  		QueueUrl: aws.String(queueUrl),
   977  	}
   978  
   979  	if util.LenTrim(nextToken) > 0 {
   980  		input.NextToken = aws.String(nextToken)
   981  	}
   982  
   983  	if maxResults > 0 {
   984  		input.MaxResults = aws.Int64(maxResults)
   985  	}
   986  
   987  	// perform action
   988  	var output *awssqs.ListDeadLetterSourceQueuesOutput
   989  
   990  	if len(timeOutDuration) > 0 {
   991  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   992  		defer cancel()
   993  
   994  		output, err = s.sqsClient.ListDeadLetterSourceQueuesWithContext(ctx, input)
   995  	} else {
   996  		if segCtxSet {
   997  			output, err = s.sqsClient.ListDeadLetterSourceQueuesWithContext(segCtx, input)
   998  		} else {
   999  			output, err = s.sqsClient.ListDeadLetterSourceQueues(input)
  1000  		}
  1001  	}
  1002  
  1003  	// evaluate result
  1004  	if err != nil {
  1005  		err = errors.New("ListDeadLetterSourceQueues Failed: (List Action) " + err.Error())
  1006  		return nil, "", err
  1007  	} else {
  1008  		queueUrlsList = aws.StringValueSlice(output.QueueUrls)
  1009  		moreQueueUrlsNextToken = aws.StringValue(output.NextToken)
  1010  		return queueUrlsList, moreQueueUrlsNextToken, nil
  1011  	}
  1012  }
  1013  
  1014  // GetQueueAttributes will retrieve queue attributes for a given queueUrl, filtered by the attributeNames slice parameter
  1015  //
  1016  // Parameters:
  1017  //  1. queueUrl = required, the queue url for which queue attributes are retrieved against, case-sensitive
  1018  //  2. attributeNames = required, slice of attribute names to filter attributes for (see notes below for allowed attribute name values)
  1019  //  3. timeOutDuration = optional, timeout duration for context if applicable
  1020  //
  1021  // Return Values:
  1022  //  1. attributes = map of get queue attributes key value pairs retrieved
  1023  //  2. err = error info if any
  1024  //
  1025  // Get Queue Attributes: (Key = Expected Value)
  1026  //
  1027  //  1. All = Returns all values.
  1028  //
  1029  //  2. ApproximateNumberOfMessages = Returns the approximate number of messages available for retrieval from the queue.
  1030  //
  1031  //  3. ApproximateNumberOfMessagesDelayed = Returns the approximate number of messages in the queue that are delayed
  1032  //     and not available for reading immediately.
  1033  //     This can happen when the queue is configured as a delay queue
  1034  //     or when a message has been sent with a delay parameter.
  1035  //
  1036  //  4. ApproximateNumberOfMessagesNotVisible = Returns the approximate number of messages that are in flight.
  1037  //     Messages are considered to be in flight if they have been sent to a client
  1038  //     but have not yet been deleted, or have not yet reached the end of their visibility window.
  1039  //
  1040  //  5. CreatedTimestamp = Returns the time when the queue was created in seconds (epoch time (http://en.wikipedia.org/wiki/Unix_time)).
  1041  //
  1042  //  6. DelaySeconds = Returns the default delay on the queue in seconds.
  1043  //
  1044  //  7. LastModifiedTimestamp = Returns the time when the queue was last changed in seconds (epoch time (http://en.wikipedia.org/wiki/Unix_time)).
  1045  //
  1046  //  8. MaximumMessageSize = Returns the limit of how many bytes a message can contain before Amazon SQS rejects it.
  1047  //
  1048  //  9. MessageRetentionPeriod = Returns the length of time, in seconds, for which Amazon SQS retains a message.
  1049  //
  1050  //  10. Policy = Returns the policy of the queue.
  1051  //
  1052  //  11. QueueArn = Returns the Amazon resource name (ARN) of the queue.
  1053  //
  1054  //  12. ReceiveMessageWaitTimeSeconds = Returns the length of time, in seconds,
  1055  //     for which the ReceiveMessage action waits for a message to arrive.
  1056  //
  1057  //  13. RedrivePolicy = The string that includes the parameters for the dead-letter queue functionality of the source queue as a JSON object.
  1058  //     For more information about the redrive policy and dead-letter queues,
  1059  //     see Using Amazon SQS Dead-Letter Queues (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)
  1060  //     in the Amazon Simple Queue Service Developer Guide.
  1061  //
  1062  //  14. deadLetterTargetArn = The Amazon Resource Name (ARN) of the dead-letter queue to which
  1063  //     Amazon SQS moves messages after the value of maxReceiveCount is exceeded.
  1064  //
  1065  //  15. maxReceiveCount = The number of times a message is delivered to the source queue before being moved to the dead-letter queue.
  1066  //     When the ReceiveCount for a message exceeds the maxReceiveCount for a queue,
  1067  //     Amazon SQS moves the message to the dead-letter-queue.
  1068  //
  1069  //  16. VisibilityTimeout = Returns the visibility timeout for the queue.
  1070  //     For more information about the visibility timeout, see Visibility Timeout
  1071  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)
  1072  //     in the Amazon Simple Queue Service Developer Guide.
  1073  //
  1074  //     The following attributes apply only to server-side-encryption
  1075  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html):
  1076  //
  1077  //  17. KmsMasterKeyId = Returns the ID of an AWS-managed customer master key (CMK) for Amazon SQS or a custom CMK.
  1078  //     For more information, see Key Terms
  1079  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-sse-key-terms).
  1080  //     18)KmsDataKeyReusePeriodSeconds = Returns the length of time, in seconds,
  1081  //     for which Amazon SQS can reuse a data key to encrypt or decrypt messages before calling AWS KMS again.
  1082  //     For more information, see How Does the Data Key Reuse Period Work?
  1083  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-how-does-the-data-key-reuse-period-work).
  1084  //
  1085  //     The following attributes apply only to FIFO (first-in-first-out) queues
  1086  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html):
  1087  //
  1088  //  19. FifoQueue = Returns whether the queue is FIFO.
  1089  //     For more information, see FIFO Queue Logic
  1090  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-understanding-logic)
  1091  //     in the Amazon Simple Queue Service Developer Guide.
  1092  //     To determine whether a queue is FIFO
  1093  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html),
  1094  //     you can check whether QueueName ends with the .fifo suffix.
  1095  //
  1096  //  20. ContentBasedDeduplication = Returns whether content-based deduplication is enabled for the queue.
  1097  //     For more information, see Exactly-Once Processing
  1098  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing)
  1099  //     in the Amazon Simple Queue Service Developer Guide.
  1100  func (s *SQS) GetQueueAttributes(queueUrl string,
  1101  	attributeNames []sqsgetqueueattribute.SQSGetQueueAttribute,
  1102  	timeOutDuration ...time.Duration) (attributes map[sqsgetqueueattribute.SQSGetQueueAttribute]string, err error) {
  1103  	segCtx := context.Background()
  1104  	segCtxSet := false
  1105  
  1106  	seg := xray.NewSegmentNullable("SQS-GetQueueAttributes", s._parentSegment)
  1107  
  1108  	if seg != nil {
  1109  		segCtx = seg.Ctx
  1110  		segCtxSet = true
  1111  
  1112  		defer seg.Close()
  1113  		defer func() {
  1114  			_ = seg.Seg.AddMetadata("SQS-GetQueueAttributes-QueueURL", queueUrl)
  1115  			_ = seg.Seg.AddMetadata("SQS-GetQueueAttributes-AttributeNames", attributeNames)
  1116  			_ = seg.Seg.AddMetadata("SQS-GetQueueAttributes-Result-Attributes", attributes)
  1117  
  1118  			if err != nil {
  1119  				_ = seg.Seg.AddError(err)
  1120  			}
  1121  		}()
  1122  	}
  1123  
  1124  	// validate
  1125  	if s.sqsClient == nil {
  1126  		err = errors.New("GetQueueAttributes Failed: " + "SQS Client is Required")
  1127  		return nil, err
  1128  	}
  1129  
  1130  	if util.LenTrim(queueUrl) <= 0 {
  1131  		err = errors.New("GetQueueAttributes Failed: " + "Queue Url is Required")
  1132  		return nil, err
  1133  	}
  1134  
  1135  	if attributeNames == nil {
  1136  		err = errors.New("GetQueueAttributes Failed: " + "Attribute Names Map is Required (nil)")
  1137  		return nil, err
  1138  	}
  1139  
  1140  	if len(attributeNames) <= 0 {
  1141  		err = errors.New("GetQueueAttributes Failed: " + "Attribute Names Map is Required (len = 0)")
  1142  		return nil, err
  1143  	}
  1144  
  1145  	// create input object
  1146  	var keys []*string
  1147  
  1148  	for _, v := range attributeNames {
  1149  		if v.Valid() && v != sqsgetqueueattribute.UNKNOWN {
  1150  			keys = append(keys, aws.String(v.Key()))
  1151  		}
  1152  	}
  1153  
  1154  	input := &awssqs.GetQueueAttributesInput{
  1155  		QueueUrl:       aws.String(queueUrl),
  1156  		AttributeNames: keys,
  1157  	}
  1158  
  1159  	// perform action
  1160  	var output *awssqs.GetQueueAttributesOutput
  1161  
  1162  	if len(timeOutDuration) > 0 {
  1163  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1164  		defer cancel()
  1165  
  1166  		output, err = s.sqsClient.GetQueueAttributesWithContext(ctx, input)
  1167  	} else {
  1168  		if segCtxSet {
  1169  			output, err = s.sqsClient.GetQueueAttributesWithContext(segCtx, input)
  1170  		} else {
  1171  			output, err = s.sqsClient.GetQueueAttributes(input)
  1172  		}
  1173  	}
  1174  
  1175  	// evaluate result
  1176  	if err != nil {
  1177  		err = errors.New("GetQueueAttributes Failed: (Get Action) " + err.Error())
  1178  		return nil, err
  1179  	} else {
  1180  		attributes = s.fromAwsGetQueueAttributes(output.Attributes)
  1181  		return attributes, nil
  1182  	}
  1183  }
  1184  
  1185  // SetQueueAttributes will set attributes for a given queueUrl
  1186  //
  1187  // Parameters:
  1188  //  1. queueUrl = required, the queue to set attributes for, case-sensitive
  1189  //  2. attributes = required, map of attribute key value pairs to set for a queue based on the queueUrl
  1190  //  3. timeOutDuration = optional, timeout duration for context if applicable
  1191  //
  1192  // Return Values:
  1193  //  1. if successful, nil is returned
  1194  //  2. otherwise, error info is returned
  1195  //
  1196  // Set Queue Attributes: (Key = Expected Value)
  1197  //
  1198  //  1. DelaySeconds = The length of time, in seconds, for which the delivery of all messages in the queue is delayed.
  1199  //     Valid values: An integer from 0 to 900 (15 minutes). Default: 0.
  1200  //
  1201  //  2. MaximumMessageSize = The limit of how many bytes a message can contain before Amazon SQS rejects it.
  1202  //     Valid values: An integer from 1,024 bytes (1 KiB) up to 262,144 bytes (256 KiB). Default: 262,144 (256 KiB).
  1203  //
  1204  //  3. MessageRetentionPeriod = The length of time, in seconds, for which Amazon SQS retains a message.
  1205  //     Valid values: An integer representing seconds,
  1206  //     from 60 (1 minute) to 1,209,600 (14 days). Default: 345,600 (4 days).
  1207  //
  1208  //  4. Policy = The queue's policy. A valid AWS policy. For more information about policy structure,
  1209  //     see Overview of AWS IAM Policies
  1210  //     (https://docs.aws.amazon.com/IAM/latest/UserGuide/PoliciesOverview.html)
  1211  //     in the Amazon IAM User Guide.
  1212  //
  1213  //  5. ReceiveMessageWaitTimeSeconds = The length of time, in seconds, for which a ReceiveMessage action waits for a message to arrive.
  1214  //     Valid values: An integer from 0 to 20 (seconds). Default: 0.
  1215  //
  1216  //  6. RedrivePolicy = The string that includes the parameters for the dead-letter queue functionality of the source queue as a JSON object.
  1217  //     For more information about the redrive policy and dead-letter queues, see Using Amazon SQS Dead-Letter Queues
  1218  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html )
  1219  //     in the Amazon Simple Queue Service Developer Guide.
  1220  //
  1221  //  7. deadLetterTargetArn = The Amazon Resource Name (ARN) of the dead-letter queue to which Amazon SQS moves messages
  1222  //     after the value of maxReceiveCount is exceeded.
  1223  //
  1224  //  8. maxReceiveCount = The number of times a message is delivered to the source queue before being moved to the dead-letter queue.
  1225  //     When the ReceiveCount for a message exceeds the maxReceiveCount for a queue,
  1226  //     Amazon SQS moves the message to the dead-letter-queue.
  1227  //     The dead-letter queue of a FIFO queue must also be a FIFO queue.
  1228  //     Similarly, the dead-letter queue of a standard queue must also be a standard queue.
  1229  //
  1230  //  9. VisibilityTimeout = The visibility timeout for the queue, in seconds.
  1231  //     Valid values: An integer from 0 to 43,200 (12 hours). Default: 30.
  1232  //     For more information about the visibility timeout, see Visibility Timeout
  1233  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)
  1234  //     in the Amazon Simple Queue Service Developer Guide.
  1235  //
  1236  //     The following attributes apply only to server-side-encryption
  1237  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html):
  1238  //
  1239  //  10. KmsMasterKeyId = The ID of an AWS-managed customer master key (CMK) for Amazon SQS or a custom CMK.
  1240  //     For more information, see Key Terms
  1241  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-sse-key-terms).
  1242  //     While the alias of the AWS-managed CMK for Amazon SQS is always alias/aws/sqs,
  1243  //     the alias of a custom CMK can, for example, be alias/MyAlias.
  1244  //     For more examples, see KeyId (https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html#API_DescribeKey_RequestParameters)
  1245  //     in the AWS Key Management Service API Reference.
  1246  //
  1247  //  11. KmsDataKeyReusePeriodSeconds = The length of time, in seconds, for which Amazon SQS can reuse a data key,
  1248  //     to encrypt or decrypt messages before calling AWS KMS again.
  1249  //     See more info at (https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#data-keys)
  1250  //     Valid Value is an integer representing seconds,
  1251  //     between 60 seconds (1 minute) and 86,400 seconds (24 hours).
  1252  //     Default: 300 (5 minutes).
  1253  //     A shorter time period provides better security but results in more calls to KMS
  1254  //     which might incur charges after Free Tier.
  1255  //     For more information, see How Does the Data Key Reuse Period Work?
  1256  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-server-side-encryption.html#sqs-how-does-the-data-key-reuse-period-work).
  1257  //
  1258  //     The following attribute applies only to FIFO (first-in-first-out) queues
  1259  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html):
  1260  //
  1261  //  12. ContentBasedDeduplication = Enables content-based deduplication.
  1262  //     For more information, see Exactly-Once Processing
  1263  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing)
  1264  //     in the Amazon Simple Queue Service Developer Guide.
  1265  //     Every message must have a unique MessageDeduplicationId,
  1266  //     You may provide a MessageDeduplicationId explicitly.
  1267  //     If you aren't able to provide a MessageDeduplicationId and you enable ContentBasedDeduplication
  1268  //     for your queue, Amazon SQS uses a SHA-256 hash to generate the MessageDeduplicationId
  1269  //     using the body of the message (but not the attributes of the message).
  1270  //     If you don't provide a MessageDeduplicationId and the queue doesn't have ContentBasedDeduplication set,
  1271  //     the action fails with an error.
  1272  //     If the queue has ContentBasedDeduplication set, your MessageDeduplicationId overrides the generated one.
  1273  //     When ContentBasedDeduplication is in effect,
  1274  //     messages with identical content sent within the deduplication interval
  1275  //     are treated as duplicates and only one copy of the message is delivered.
  1276  //     If you send one message with ContentBasedDeduplication enabled
  1277  //     and then another message with a MessageDeduplicationId that is the same as the one generated
  1278  //     for the first MessageDeduplicationId, the two messages are treated as duplicates
  1279  //     and only one copy of the message is delivered.
  1280  func (s *SQS) SetQueueAttributes(queueUrl string,
  1281  	attributes map[sqssetqueueattribute.SQSSetQueueAttribute]string,
  1282  	timeOutDuration ...time.Duration) (err error) {
  1283  	segCtx := context.Background()
  1284  	segCtxSet := false
  1285  
  1286  	seg := xray.NewSegmentNullable("SQS-SetQueueAttributes", s._parentSegment)
  1287  
  1288  	if seg != nil {
  1289  		segCtx = seg.Ctx
  1290  		segCtxSet = true
  1291  
  1292  		defer seg.Close()
  1293  		defer func() {
  1294  			_ = seg.Seg.AddMetadata("SQS-SetQueueAttributes-QueueURL", queueUrl)
  1295  			_ = seg.Seg.AddMetadata("SQS-SetQueueAttributes-Attributes", attributes)
  1296  
  1297  			if err != nil {
  1298  				_ = seg.Seg.AddError(err)
  1299  			}
  1300  		}()
  1301  	}
  1302  
  1303  	// validate
  1304  	if s.sqsClient == nil {
  1305  		err = errors.New("SetQueueAttributes Failed: " + "SQS Client is Required")
  1306  		return err
  1307  	}
  1308  
  1309  	if util.LenTrim(queueUrl) <= 0 {
  1310  		err = errors.New("SetQueueAttributes Failed: " + "Queue Url is Required")
  1311  		return err
  1312  	}
  1313  
  1314  	if attributes == nil {
  1315  		err = errors.New("SetQueueAttributes Failed: " + "Attributes Map is Required")
  1316  		return err
  1317  	}
  1318  
  1319  	// create input object
  1320  	input := &awssqs.SetQueueAttributesInput{
  1321  		QueueUrl:   aws.String(queueUrl),
  1322  		Attributes: s.toAwsSetQueueAttributes(attributes),
  1323  	}
  1324  
  1325  	// perform action
  1326  	if len(timeOutDuration) > 0 {
  1327  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1328  		defer cancel()
  1329  
  1330  		_, err = s.sqsClient.SetQueueAttributesWithContext(ctx, input)
  1331  	} else {
  1332  		if segCtxSet {
  1333  			_, err = s.sqsClient.SetQueueAttributesWithContext(segCtx, input)
  1334  		} else {
  1335  			_, err = s.sqsClient.SetQueueAttributes(input)
  1336  		}
  1337  	}
  1338  
  1339  	// evaluate result
  1340  	if err != nil {
  1341  		err = errors.New("SetQueueAttributes Failed: (Set Action) " + err.Error())
  1342  		return err
  1343  	} else {
  1344  		return nil
  1345  	}
  1346  }
  1347  
  1348  // ----------------------------------------------------------------------------------------------------------------
  1349  // messaging related methods
  1350  // ----------------------------------------------------------------------------------------------------------------
  1351  
  1352  // SendMessage will send a standard message to SQS standard queue via queue url
  1353  //
  1354  // Parameters:
  1355  //  1. queueUrl = required, the queue to send message to
  1356  //  2. messageBody = required, the message to send to the queue
  1357  //  3. messageAttributes = optional, map of message attribute key value pairs.
  1358  //     Each message attribute consists of a Name, Type, and Value.
  1359  //     For more information, see Amazon SQS Message Attributes:
  1360  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html)
  1361  //     in the Amazon Simple Queue Service Developer Guide.
  1362  //     Example: use message attributes to define meta data about the message being sent:
  1363  //     a) {
  1364  //     "Title": { DataType: "String", StringValue: "The Whistler"},
  1365  //     "Author": { DataType: "String", StringValue: "John Grisham"},
  1366  //     "WeeksOn": { DataType: "Number", StringValue: "6"}
  1367  //     }
  1368  //  4. delaySeconds = optional, if greater than 0, indicates how many seconds to delay before message is available to consumers
  1369  //  5. timeOutDuration = optional, timeout value for context if any
  1370  //
  1371  // Return Values:
  1372  //  1. result = struct containing Send... action message result
  1373  //  2. err = error info if any
  1374  func (s *SQS) SendMessage(queueUrl string,
  1375  	messageBody string,
  1376  	messageAttributes map[string]*awssqs.MessageAttributeValue,
  1377  	delaySeconds int64,
  1378  	timeOutDuration ...time.Duration) (result *SQSMessageResult, err error) {
  1379  	segCtx := context.Background()
  1380  	segCtxSet := false
  1381  
  1382  	seg := xray.NewSegmentNullable("SQS-SendMessage", s._parentSegment)
  1383  
  1384  	if seg != nil {
  1385  		segCtx = seg.Ctx
  1386  		segCtxSet = true
  1387  
  1388  		defer seg.Close()
  1389  		defer func() {
  1390  			_ = seg.Seg.AddMetadata("SQS-SendMessage-QueueURL", queueUrl)
  1391  			_ = seg.Seg.AddMetadata("SQS-SendMessage-MessageBody", messageBody)
  1392  			_ = seg.Seg.AddMetadata("SQS-SendMessage-MessageAttributes", messageAttributes)
  1393  			_ = seg.Seg.AddMetadata("SQS-SendMessage-DelaySeconds", delaySeconds)
  1394  			_ = seg.Seg.AddMetadata("SQS-SendMessage-Result", result)
  1395  
  1396  			if err != nil {
  1397  				_ = seg.Seg.AddError(err)
  1398  			}
  1399  		}()
  1400  	}
  1401  
  1402  	// validate
  1403  	if s.sqsClient == nil {
  1404  		err = errors.New("SendMessage Failed: " + "SQS Client is Required")
  1405  		return nil, err
  1406  	}
  1407  
  1408  	if util.LenTrim(queueUrl) <= 0 {
  1409  		err = errors.New("SendMessage Failed: " + "Queue Url is Required")
  1410  		return nil, err
  1411  	}
  1412  
  1413  	if util.LenTrim(messageBody) <= 0 {
  1414  		err = errors.New("SendMessage Failed: " + "Message Body is Required")
  1415  		return nil, err
  1416  	}
  1417  
  1418  	// create input object
  1419  	input := &awssqs.SendMessageInput{
  1420  		QueueUrl:    aws.String(queueUrl),
  1421  		MessageBody: aws.String(messageBody),
  1422  	}
  1423  
  1424  	if messageAttributes != nil {
  1425  		input.MessageAttributes = messageAttributes
  1426  	}
  1427  
  1428  	if delaySeconds > 0 {
  1429  		input.DelaySeconds = aws.Int64(delaySeconds)
  1430  	}
  1431  
  1432  	// perform action
  1433  	var output *awssqs.SendMessageOutput
  1434  
  1435  	if len(timeOutDuration) > 0 {
  1436  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1437  		defer cancel()
  1438  
  1439  		output, err = s.sqsClient.SendMessageWithContext(ctx, input)
  1440  	} else {
  1441  		if segCtxSet {
  1442  			output, err = s.sqsClient.SendMessageWithContext(segCtx, input)
  1443  		} else {
  1444  			output, err = s.sqsClient.SendMessage(input)
  1445  		}
  1446  	}
  1447  
  1448  	// evaluate result
  1449  	if err != nil {
  1450  		err = errors.New("SendMessage Failed: (Send Action) " + err.Error())
  1451  		return nil, err
  1452  	} else {
  1453  		result = &SQSMessageResult{
  1454  			MessageId:              aws.StringValue(output.MessageId),
  1455  			MD5ofMessageBody:       aws.StringValue(output.MD5OfMessageBody),
  1456  			MD5ofMessageAttributes: aws.StringValue(output.MD5OfMessageAttributes),
  1457  			FifoSequenceNumber:     "",
  1458  		}
  1459  		return result, nil
  1460  	}
  1461  }
  1462  
  1463  // SendMessageFifo will send a fifo message to SQS fifo queue via queue url
  1464  //
  1465  // Parameters:
  1466  //  1. queueUrl = required, the queue to send message to
  1467  //  2. messageDeduplicationId = required, The token used for deduplication of sent messages.
  1468  //     If a message with a particular MessageDeduplicationId is sent successfully,
  1469  //     any messages sent with the same MessageDeduplicationId are accepted successfully
  1470  //     but aren't delivered during the 5-minute deduplication interval.
  1471  //     For more information, see Exactly-Once Processing
  1472  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-exactly-once-processing)
  1473  //     in the Amazon Simple Queue Service Developer Guide.
  1474  //     Every message must have a unique MessageDeduplicationId, You may provide a MessageDeduplicationId explicitly.
  1475  //     If you aren't able to provide a MessageDeduplicationId,
  1476  //     and you enable ContentBasedDeduplication for your queue,
  1477  //     Amazon SQS uses a SHA-256 hash to generate the MessageDeduplicationId,
  1478  //     using the body of the message (but not the attributes of the message).
  1479  //     If you don't provide a MessageDeduplicationId and the queue doesn't have ContentBasedDeduplication set,
  1480  //     the action fails with an error.
  1481  //     If the queue has ContentBasedDeduplication set, your MessageDeduplicationId overrides the generated one.
  1482  //     When ContentBasedDeduplication is in effect,
  1483  //     messages with identical content sent within the deduplication interval are treated as duplicates
  1484  //     and only one copy of the message is delivered.
  1485  //     If you send one message with ContentBasedDeduplication enabled,
  1486  //     and then another message with a MessageDeduplicationId that is
  1487  //     the same as the one generated for the first MessageDeduplicationId,
  1488  //     the two messages are treated as duplicates and only one copy of the message is delivered.
  1489  //     The MessageDeduplicationId is available to the consumer of the message,
  1490  //     (this can be useful for troubleshooting delivery issues).
  1491  //     If a message is sent successfully but the acknowledgement is lost and the message is resent
  1492  //     with the same MessageDeduplicationId after the deduplication interval,
  1493  //     Amazon SQS can't detect duplicate messages.
  1494  //     Amazon SQS continues to keep track of the message deduplication ID,
  1495  //     even after the message is received and deleted.
  1496  //     The maximum length of MessageDeduplicationId is 128 characters.
  1497  //     MessageDeduplicationId can contain alphanumeric characters (a-z, A-Z, 0-9)
  1498  //     and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~).
  1499  //     For best practices of using MessageDeduplicationId,
  1500  //     see Using the MessageDeduplicationId Property
  1501  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagededuplicationid-property.html)
  1502  //     in the Amazon Simple Queue Service Developer Guide.
  1503  //  3. messageGroupId = required, The tag that specifies that a message belongs to a specific message group.
  1504  //     Messages that belong to the same message group are processed in a FIFO manner,
  1505  //     however, messages in different message groups might be processed out of order.
  1506  //     To interleave multiple ordered streams within a single queue,
  1507  //     use MessageGroupId values (for example, session data for multiple users).
  1508  //     In this scenario, multiple consumers can process the queue,
  1509  //     but the session data of each user is processed in a FIFO fashion.
  1510  //     You must associate a non-empty MessageGroupId with a message,
  1511  //     if you don't provide a MessageGroupId, the action fails.
  1512  //     ReceiveMessage might return messages with multiple MessageGroupId values,
  1513  //     For each MessageGroupId, the messages are sorted by time sent,
  1514  //     The caller can't specify a MessageGroupId.
  1515  //     The length of MessageGroupId is 128 characters,
  1516  //     Valid values: alphanumeric characters and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~).
  1517  //     For best practices of using MessageGroupId,
  1518  //     see Using the MessageGroupId Property
  1519  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html)
  1520  //     in the Amazon Simple Queue Service Developer Guide.
  1521  //     MessageGroupId is required for FIFO queues. You can't use it for Standard queues.
  1522  //  4. messageBody = required, the message to send to the queue
  1523  //  5. messageAttributes = optional, map of message attribute key value pairs.
  1524  //     Each message attribute consists of a Name, Type, and Value.
  1525  //     For more information, see Amazon SQS Message Attributes:
  1526  //     (https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-attributes.html)
  1527  //     in the Amazon Simple Queue Service Developer Guide.
  1528  //     Example: use message attributes to define meta data about the message being sent:
  1529  //     a) {
  1530  //     "Title": { DataType: "String", StringValue: "The Whistler"},
  1531  //     "Author": { DataType: "String", StringValue: "John Grisham"},
  1532  //     "WeeksOn": { DataType: "Number", StringValue: "6"}
  1533  //     }
  1534  //  6. timeOutDuration = optional, timeout value for context if any
  1535  //
  1536  // Return Values:
  1537  //  1. result = struct containing Send... action message result
  1538  //  2. err = error info if any
  1539  func (s *SQS) SendMessageFifo(queueUrl string,
  1540  	messageDeduplicationId string,
  1541  	messageGroupId string,
  1542  	messageBody string,
  1543  	messageAttributes map[string]*awssqs.MessageAttributeValue,
  1544  	timeOutDuration ...time.Duration) (result *SQSMessageResult, err error) {
  1545  	segCtx := context.Background()
  1546  	segCtxSet := false
  1547  
  1548  	seg := xray.NewSegmentNullable("SQS-SendMessageFifo", s._parentSegment)
  1549  
  1550  	if seg != nil {
  1551  		segCtx = seg.Ctx
  1552  		segCtxSet = true
  1553  
  1554  		defer seg.Close()
  1555  		defer func() {
  1556  			_ = seg.Seg.AddMetadata("SQS-SendMessageFifo-QueueURL", queueUrl)
  1557  			_ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageDeduplicationID", messageDeduplicationId)
  1558  			_ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageGroupID", messageGroupId)
  1559  			_ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageBody", messageBody)
  1560  			_ = seg.Seg.AddMetadata("SQS-SendMessageFifo-MessageAttributes", messageAttributes)
  1561  			_ = seg.Seg.AddMetadata("SQS-SendMessageFifo-Result", result)
  1562  
  1563  			if err != nil {
  1564  				_ = seg.Seg.AddError(err)
  1565  			}
  1566  		}()
  1567  	}
  1568  
  1569  	// validate
  1570  	if s.sqsClient == nil {
  1571  		err = errors.New("SendMessageFifo Failed: " + "SQS Client is Required")
  1572  		return nil, err
  1573  	}
  1574  
  1575  	if util.LenTrim(queueUrl) <= 0 {
  1576  		err = errors.New("SendMessageFifo Failed: " + "Queue Url is Required")
  1577  		return nil, err
  1578  	}
  1579  
  1580  	if util.LenTrim(messageDeduplicationId) <= 0 {
  1581  		err = errors.New("SendMessageFifo Failed: " + "Message Deduplication Id is Required")
  1582  		return nil, err
  1583  	}
  1584  
  1585  	if util.LenTrim(messageGroupId) <= 0 {
  1586  		err = errors.New("SendMessageFifo Failed: " + "Message Group Id is Required")
  1587  		return nil, err
  1588  	}
  1589  
  1590  	if util.LenTrim(messageBody) <= 0 {
  1591  		err = errors.New("SendMessageFifo Failed: " + "Message Body is Required")
  1592  		return nil, err
  1593  	}
  1594  
  1595  	// create input object
  1596  	input := &awssqs.SendMessageInput{
  1597  		QueueUrl:               aws.String(queueUrl),
  1598  		MessageDeduplicationId: aws.String(messageDeduplicationId),
  1599  		MessageGroupId:         aws.String(messageGroupId),
  1600  		MessageBody:            aws.String(messageBody),
  1601  	}
  1602  
  1603  	if messageAttributes != nil {
  1604  		input.MessageAttributes = messageAttributes
  1605  	}
  1606  
  1607  	// perform action
  1608  	var output *awssqs.SendMessageOutput
  1609  
  1610  	if len(timeOutDuration) > 0 {
  1611  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1612  		defer cancel()
  1613  
  1614  		output, err = s.sqsClient.SendMessageWithContext(ctx, input)
  1615  	} else {
  1616  		if segCtxSet {
  1617  			output, err = s.sqsClient.SendMessageWithContext(segCtx, input)
  1618  		} else {
  1619  			output, err = s.sqsClient.SendMessage(input)
  1620  		}
  1621  	}
  1622  
  1623  	// evaluate result
  1624  	if err != nil {
  1625  		err = errors.New("SendMessageFifo Failed: (Send Action) " + err.Error())
  1626  		return nil, err
  1627  	} else {
  1628  		result = &SQSMessageResult{
  1629  			MessageId:              aws.StringValue(output.MessageId),
  1630  			MD5ofMessageBody:       aws.StringValue(output.MD5OfMessageBody),
  1631  			MD5ofMessageAttributes: aws.StringValue(output.MD5OfMessageAttributes),
  1632  			FifoSequenceNumber:     aws.StringValue(output.SequenceNumber),
  1633  		}
  1634  		return result, nil
  1635  	}
  1636  }
  1637  
  1638  // SendMessageBatch will send up to 10 standard messages in a batch to SQS standard queue as indicated by queueUrl
  1639  func (s *SQS) SendMessageBatch(queueUrl string,
  1640  	messageEntries []*SQSStandardMessage,
  1641  	timeOutDuration ...time.Duration) (successList []*SQSSuccessResult, failedList []*SQSFailResult, err error) {
  1642  	segCtx := context.Background()
  1643  	segCtxSet := false
  1644  
  1645  	seg := xray.NewSegmentNullable("SQS-SendMessageBatch", s._parentSegment)
  1646  
  1647  	if seg != nil {
  1648  		segCtx = seg.Ctx
  1649  		segCtxSet = true
  1650  
  1651  		defer seg.Close()
  1652  		defer func() {
  1653  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatch-QueueURL", queueUrl)
  1654  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatch-MessageEntries", messageEntries)
  1655  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatch-Result-SuccessList", successList)
  1656  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatch-Result-FailedList", failedList)
  1657  
  1658  			if err != nil {
  1659  				_ = seg.Seg.AddError(err)
  1660  			}
  1661  		}()
  1662  	}
  1663  
  1664  	// validate
  1665  	if s.sqsClient == nil {
  1666  		err = errors.New("SendMessageBatch Failed: " + "SQS Client is Required")
  1667  		return nil, nil, err
  1668  	}
  1669  
  1670  	if util.LenTrim(queueUrl) <= 0 {
  1671  		err = errors.New("SendMessageBatch Failed: " + "Queue Url is Required")
  1672  		return nil, nil, err
  1673  	}
  1674  
  1675  	if messageEntries == nil {
  1676  		err = errors.New("SendMessageBatch Failed: " + "Message Entries Required (nil)")
  1677  		return nil, nil, err
  1678  	}
  1679  
  1680  	if len(messageEntries) <= 0 {
  1681  		err = errors.New("SendMessageBatch Failed: " + "Message Entries Required (count = 0)")
  1682  		return nil, nil, err
  1683  	}
  1684  
  1685  	if len(messageEntries) > 10 {
  1686  		err = errors.New("SendMessageBatch Failed: " + "Message Entries Per Batch Limited to 10")
  1687  		return nil, nil, err
  1688  	}
  1689  
  1690  	// create input object
  1691  	var entries []*awssqs.SendMessageBatchRequestEntry
  1692  
  1693  	for _, v := range messageEntries {
  1694  		if util.LenTrim(v.Id) > 0 && util.LenTrim(v.MessageBody) > 0 {
  1695  			entries = append(entries, &awssqs.SendMessageBatchRequestEntry{
  1696  				Id:                aws.String(v.Id),
  1697  				MessageBody:       aws.String(v.MessageBody),
  1698  				MessageAttributes: v.MessageAttributes,
  1699  				DelaySeconds:      aws.Int64(v.DelaySeconds),
  1700  			})
  1701  		}
  1702  	}
  1703  
  1704  	if len(entries) <= 0 {
  1705  		err = errors.New("SendMessageBatch Failed: " + "Message Entries Elements Count Must Not Be Zero")
  1706  		return nil, nil, err
  1707  	}
  1708  
  1709  	input := &awssqs.SendMessageBatchInput{
  1710  		QueueUrl: aws.String(queueUrl),
  1711  		Entries:  entries,
  1712  	}
  1713  
  1714  	// perform action
  1715  	var output *awssqs.SendMessageBatchOutput
  1716  
  1717  	if len(timeOutDuration) > 0 {
  1718  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1719  		defer cancel()
  1720  
  1721  		output, err = s.sqsClient.SendMessageBatchWithContext(ctx, input)
  1722  	} else {
  1723  		if segCtxSet {
  1724  			output, err = s.sqsClient.SendMessageBatchWithContext(segCtx, input)
  1725  		} else {
  1726  			output, err = s.sqsClient.SendMessageBatch(input)
  1727  		}
  1728  	}
  1729  
  1730  	// evaluate result
  1731  	if err != nil {
  1732  		err = errors.New("SendMessageBatch Failed: (Send Action) " + err.Error())
  1733  		return nil, nil, err
  1734  	} else {
  1735  		if len(output.Successful) > 0 {
  1736  			for _, v := range output.Successful {
  1737  				successList = append(successList, &SQSSuccessResult{
  1738  					Id:                     aws.StringValue(v.Id),
  1739  					MessageId:              aws.StringValue(v.MessageId),
  1740  					MD5ofMessageBody:       aws.StringValue(v.MD5OfMessageBody),
  1741  					MD5ofMessageAttributes: aws.StringValue(v.MD5OfMessageAttributes),
  1742  				})
  1743  			}
  1744  		}
  1745  
  1746  		if len(output.Failed) > 0 {
  1747  			for _, v := range output.Failed {
  1748  				failedList = append(failedList, &SQSFailResult{
  1749  					Id:          aws.StringValue(v.Id),
  1750  					Code:        aws.StringValue(v.Code),
  1751  					Message:     aws.StringValue(v.Message),
  1752  					SenderFault: aws.BoolValue(v.SenderFault),
  1753  				})
  1754  			}
  1755  		}
  1756  
  1757  		return successList, failedList, nil
  1758  	}
  1759  }
  1760  
  1761  // SendMessageBatchFifo will send up to 10 fifo messages in a batch to SQS fifo queue as indicated by queueUrl
  1762  func (s *SQS) SendMessageBatchFifo(queueUrl string,
  1763  	messageEntries []*SQSFifoMessage,
  1764  	timeOutDuration ...time.Duration) (successList []*SQSSuccessResult, failedList []*SQSFailResult, err error) {
  1765  	segCtx := context.Background()
  1766  	segCtxSet := false
  1767  
  1768  	seg := xray.NewSegmentNullable("SQS-SendMessageBatchFifo", s._parentSegment)
  1769  
  1770  	if seg != nil {
  1771  		segCtx = seg.Ctx
  1772  		segCtxSet = true
  1773  
  1774  		defer seg.Close()
  1775  		defer func() {
  1776  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-QueueURL", queueUrl)
  1777  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-MessageEntries", messageEntries)
  1778  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-Result-SuccessList", successList)
  1779  			_ = seg.Seg.AddMetadata("SQS-SendMessageBatchFifo-Result-FailedList", failedList)
  1780  
  1781  			if err != nil {
  1782  				_ = seg.Seg.AddError(err)
  1783  			}
  1784  		}()
  1785  	}
  1786  
  1787  	// validate
  1788  	if s.sqsClient == nil {
  1789  		err = errors.New("SendMessageBatchFifo Failed: " + "SQS Client is Required")
  1790  		return nil, nil, err
  1791  	}
  1792  
  1793  	if util.LenTrim(queueUrl) <= 0 {
  1794  		err = errors.New("SendMessageBatchFifo Failed: " + "Queue Url is Required")
  1795  		return nil, nil, err
  1796  	}
  1797  
  1798  	if messageEntries == nil {
  1799  		err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Required (nil)")
  1800  		return nil, nil, err
  1801  	}
  1802  
  1803  	if len(messageEntries) <= 0 {
  1804  		err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Required (count = 0)")
  1805  		return nil, nil, err
  1806  	}
  1807  
  1808  	if len(messageEntries) > 10 {
  1809  		err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Per Batch Limited to 10")
  1810  		return nil, nil, err
  1811  	}
  1812  
  1813  	// create input object
  1814  	var entries []*awssqs.SendMessageBatchRequestEntry
  1815  
  1816  	for _, v := range messageEntries {
  1817  		if util.LenTrim(v.Id) > 0 && util.LenTrim(v.MessageBody) > 0 && util.LenTrim(v.MessageGroupId) > 0 && util.LenTrim(v.MessageDeduplicationId) > 0 {
  1818  			entries = append(entries, &awssqs.SendMessageBatchRequestEntry{
  1819  				Id:                     aws.String(v.Id),
  1820  				MessageDeduplicationId: aws.String(v.MessageDeduplicationId),
  1821  				MessageGroupId:         aws.String(v.MessageGroupId),
  1822  				MessageBody:            aws.String(v.MessageBody),
  1823  				MessageAttributes:      v.MessageAttributes,
  1824  			})
  1825  		}
  1826  	}
  1827  
  1828  	if len(entries) <= 0 {
  1829  		err = errors.New("SendMessageBatchFifo Failed: " + "Message Entries Elements Count Must Not Be Zero")
  1830  		return nil, nil, err
  1831  	}
  1832  
  1833  	input := &awssqs.SendMessageBatchInput{
  1834  		QueueUrl: aws.String(queueUrl),
  1835  		Entries:  entries,
  1836  	}
  1837  
  1838  	// perform action
  1839  	var output *awssqs.SendMessageBatchOutput
  1840  
  1841  	if len(timeOutDuration) > 0 {
  1842  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1843  		defer cancel()
  1844  
  1845  		output, err = s.sqsClient.SendMessageBatchWithContext(ctx, input)
  1846  	} else {
  1847  		if segCtxSet {
  1848  			output, err = s.sqsClient.SendMessageBatchWithContext(segCtx, input)
  1849  		} else {
  1850  			output, err = s.sqsClient.SendMessageBatch(input)
  1851  		}
  1852  	}
  1853  
  1854  	// evaluate result
  1855  	if err != nil {
  1856  		err = errors.New("SendMessageBatchFifo Failed: (Send Action) " + err.Error())
  1857  		return nil, nil, err
  1858  	} else {
  1859  		if len(output.Successful) > 0 {
  1860  			for _, v := range output.Successful {
  1861  				successList = append(successList, &SQSSuccessResult{
  1862  					Id:                     aws.StringValue(v.Id),
  1863  					MessageId:              aws.StringValue(v.MessageId),
  1864  					MD5ofMessageBody:       aws.StringValue(v.MD5OfMessageBody),
  1865  					MD5ofMessageAttributes: aws.StringValue(v.MD5OfMessageAttributes),
  1866  					SequenceNumber:         aws.StringValue(v.SequenceNumber),
  1867  				})
  1868  			}
  1869  		}
  1870  
  1871  		if len(output.Failed) > 0 {
  1872  			for _, v := range output.Failed {
  1873  				failedList = append(failedList, &SQSFailResult{
  1874  					Id:          aws.StringValue(v.Id),
  1875  					Code:        aws.StringValue(v.Code),
  1876  					Message:     aws.StringValue(v.Message),
  1877  					SenderFault: aws.BoolValue(v.SenderFault),
  1878  				})
  1879  			}
  1880  		}
  1881  
  1882  		return successList, failedList, nil
  1883  	}
  1884  }
  1885  
  1886  // ReceiveMessage will retrieve 1 or more (up to 10) messages from the SQS (standard or fifo) queue indicated by queueUrl,
  1887  // note that this method retrieves the message(s), and blocks them from other consumer view for a short time, but does not delete such messages,
  1888  // to delete the messages, consumer must call the DeleteMessage methods accordingly
  1889  //
  1890  // Parameters:
  1891  //  1. queueUrl = required, retrieve message(s) from this queue as indicated by queueUrl, either standard or fifo queue, case-sensitive
  1892  //  2. maxNumberOfMessages = required, valid value is 1 - 10, indicates the maximum number of messages to retrieve during the method call
  1893  //  3. messageAttributeNames = optional, string slice of message attribute names to retrieve as related to the received messages.
  1894  //     Attribute names are case-sensitive, alphanumeric, -, _, . are allowed.
  1895  //     To receive all message attributes, use filter name as 'All' or '.*'.
  1896  //     To receive all message attributes with a prefix pattern, use filter name as 'xyz.*',
  1897  //     where attribute names prefix with xyz are included in the return list.
  1898  //  4. systemAttributeNames = optional, string slice of system attribute names to retrieve as related to the received messages.
  1899  //     Attribute names are case-sensitive, alphanumeric, -, _, . are allowed.
  1900  //     Key-Value Pairs:
  1901  //     a) All = Return all system attributes and values.
  1902  //     b) ApproximateFirstReceiveTimestamp = Returns the time the message was first received
  1903  //     from the queue in milliseconds.
  1904  //     (epoch time (http://en.wikipedia.org/wiki/Unix_time)
  1905  //     c) ApproximateReceiveCount = Returns the number of times a message has been received
  1906  //     across all queues but not deleted.
  1907  //     d) AWSTraceHeader = Returns the AWS X-Ray trace header string.
  1908  //     e) SenderId = For an IAM user, returns the IAM user ID, for example ABCDEFGHI1JKLMNOPQ23R.
  1909  //     For an IAM role, returns the IAM role ID, for example ABCDE1F2GH3I4JK5LMNOP:i-a123b456.
  1910  //     f) SentTimestamp = Returns the time the message was sent to the queue,
  1911  //     Epoch time = http://en.wikipedia.org/wiki/Unix_time in milliseconds.
  1912  //     g) MessageDeduplicationId = Returns the value provided by the producer that calls the SendMessage action.
  1913  //     h) MessageGroupId = Returns the value provided by the producer that calls the SendMessage action.
  1914  //     Messages with the same MessageGroupId are returned in sequence.
  1915  //     i) SequenceNumber = Returns the value provided by Amazon SQS.
  1916  //  5. visibilityTimeOutSeconds = optional, The duration (in seconds) that the received messages are hidden
  1917  //     from subsequent retrieve requests after being retrieved by a ReceiveMessage request.
  1918  //  6. waitTimeSeconds = optional, The duration (in seconds) for which the call waits for a message to arrive in the queue before returning.
  1919  //     If a message is available, the call returns sooner than WaitTimeSeconds.
  1920  //     If no messages are available and the wait time expires,
  1921  //     the call returns successfully with an empty list of messages.
  1922  //     To avoid HTTP errors, ensure that the HTTP response timeout
  1923  //     for ReceiveMessage requests is longer than the WaitTimeSeconds parameter.
  1924  //  7. receiveRequestAttemptId = optional, applies to FIFO queue ONLY. The token used for deduplication of ReceiveMessage calls.
  1925  //     If a networking issue occurs after a ReceiveMessage action,
  1926  //     and instead of a response you receive a generic error.
  1927  //     It is possible to retry the same action with an identical ReceiveRequestAttemptId,
  1928  //     to retrieve the same set of messages, even if their visibility timeout has not yet expired.
  1929  //
  1930  // More About FIFO's receiveRequestAttemptId:
  1931  //
  1932  //	a) You can use ReceiveRequestAttemptId only for 5 minutes after a ReceiveMessage action.
  1933  //	b) When you set FifoQueue, a caller of the ReceiveMessage action can provide a ReceiveRequestAttemptId explicitly.
  1934  //	c) If a caller of the ReceiveMessage action doesn't provide a ReceiveRequestAttemptId, Amazon SQS generates a ReceiveRequestAttemptId.
  1935  //	d) It is possible to retry the ReceiveMessage action with the same ReceiveRequestAttemptId,
  1936  //			if none of the messages have been modified (deleted or had their visibility changes).
  1937  //	e) During a visibility timeout, subsequent calls with the same ReceiveRequestAttemptId return the same messages and receipt handles.
  1938  //			If a retry occurs within the deduplication interval, it resets the visibility timeout.
  1939  //			For more information, see Visibility Timeout in the Amazon Simple Queue Service Developer Guide.
  1940  //				(https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)
  1941  //			If a caller of the ReceiveMessage action still processes messages when the visibility timeout expires
  1942  //				and messages become visible, another worker consuming from the same queue can receive the same messages
  1943  //				and therefore process duplicates.
  1944  //			Also, if a consumer whose message processing time is longer than the visibility timeout tries to delete the processed messages,
  1945  //				the action fails with an error. To mitigate this effect, ensure that your application observes
  1946  //				a safe threshold before the visibility timeout expires and extend the visibility timeout as necessary.
  1947  //	f) While messages with a particular MessageGroupId are invisible,
  1948  //			no more messages belonging to the same MessageGroupId are returned until the visibility timeout expires.
  1949  //			You can still receive messages with another MessageGroupId as long as it is also visible.
  1950  //	g) If a caller of ReceiveMessage can't track the ReceiveRequestAttemptId, no retries work until the original visibility timeout expires.
  1951  //			As a result, delays might occur but the messages in the queue remain in a strict order.
  1952  //	h) The maximum length of ReceiveRequestAttemptId is 128 characters.
  1953  //			ReceiveRequestAttemptId can contain alphanumeric characters (a-z, A-Z, 0-9) and punctuation (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~).
  1954  //	i) For best practices of using ReceiveRequestAttemptId,
  1955  //			see Using the ReceiveRequestAttemptId Request Parameter in the Amazon Simple Queue Service Developer Guide.
  1956  //			(https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-receiverequestattemptid-request-parameter.html)
  1957  func (s *SQS) ReceiveMessage(queueUrl string,
  1958  	maxNumberOfMessages int64,
  1959  	messageAttributeNames []string,
  1960  	systemAttributeNames []sqssystemattribute.SQSSystemAttribute,
  1961  	visibilityTimeOutSeconds int64,
  1962  	waitTimeSeconds int64,
  1963  	receiveRequestAttemptId string,
  1964  	timeOutDuration ...time.Duration) (messagesList []*SQSReceivedMessage, err error) {
  1965  	segCtx := context.Background()
  1966  	segCtxSet := false
  1967  
  1968  	seg := xray.NewSegmentNullable("SQS-ReceiveMessage", s._parentSegment)
  1969  
  1970  	if seg != nil {
  1971  		segCtx = seg.Ctx
  1972  		segCtxSet = true
  1973  
  1974  		defer seg.Close()
  1975  		defer func() {
  1976  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-QueueURL", queueUrl)
  1977  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-MaxNumberOfMessages", maxNumberOfMessages)
  1978  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-MessageAttributeNames", messageAttributeNames)
  1979  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-SystemAttributeNames", systemAttributeNames)
  1980  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-VisibilityTimeOutSeconds", visibilityTimeOutSeconds)
  1981  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-WaitTimeSeconds", waitTimeSeconds)
  1982  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-ReceiveRequestAttemptID", receiveRequestAttemptId)
  1983  			_ = seg.Seg.AddMetadata("SQS-ReceiveMessage-Result-MessagesList", messagesList)
  1984  
  1985  			if err != nil {
  1986  				_ = seg.Seg.AddError(err)
  1987  			}
  1988  		}()
  1989  	}
  1990  
  1991  	// validate
  1992  	if s.sqsClient == nil {
  1993  		err = errors.New("ReceiveMessage Failed: " + "SQS Client is Required")
  1994  		return nil, err
  1995  	}
  1996  
  1997  	if util.LenTrim(queueUrl) <= 0 {
  1998  		err = errors.New("ReceiveMessage Failed: " + "Queue Url is Required")
  1999  		return nil, err
  2000  	}
  2001  
  2002  	if maxNumberOfMessages <= 0 || maxNumberOfMessages > 10 {
  2003  		err = errors.New("ReceiveMessage Failed: " + "Max Number of Messages Must Be 1 to 10")
  2004  		return nil, err
  2005  	}
  2006  
  2007  	if visibilityTimeOutSeconds < 0 {
  2008  		visibilityTimeOutSeconds = 0
  2009  	}
  2010  
  2011  	if waitTimeSeconds < 0 {
  2012  		waitTimeSeconds = 0
  2013  	}
  2014  
  2015  	// create input object
  2016  	input := &awssqs.ReceiveMessageInput{
  2017  		QueueUrl:            aws.String(queueUrl),
  2018  		MaxNumberOfMessages: aws.Int64(maxNumberOfMessages),
  2019  	}
  2020  
  2021  	if len(messageAttributeNames) > 0 {
  2022  		input.MessageAttributeNames = aws.StringSlice(messageAttributeNames)
  2023  	}
  2024  
  2025  	if len(systemAttributeNames) > 0 {
  2026  		var keys []*string
  2027  
  2028  		for _, v := range systemAttributeNames {
  2029  			if v.Valid() && v != sqssystemattribute.UNKNOWN {
  2030  				keys = append(keys, aws.String(v.Key()))
  2031  			}
  2032  		}
  2033  
  2034  		input.AttributeNames = keys
  2035  	}
  2036  
  2037  	if visibilityTimeOutSeconds > 0 {
  2038  		input.VisibilityTimeout = aws.Int64(visibilityTimeOutSeconds)
  2039  	}
  2040  
  2041  	if waitTimeSeconds > 0 {
  2042  		input.WaitTimeSeconds = aws.Int64(waitTimeSeconds)
  2043  	}
  2044  
  2045  	if util.LenTrim(receiveRequestAttemptId) > 0 {
  2046  		input.ReceiveRequestAttemptId = aws.String(receiveRequestAttemptId)
  2047  	}
  2048  
  2049  	// perform action
  2050  	var output *awssqs.ReceiveMessageOutput
  2051  
  2052  	if len(timeOutDuration) > 0 {
  2053  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  2054  		defer cancel()
  2055  
  2056  		output, err = s.sqsClient.ReceiveMessageWithContext(ctx, input)
  2057  	} else {
  2058  		if segCtxSet {
  2059  			output, err = s.sqsClient.ReceiveMessageWithContext(segCtx, input)
  2060  		} else {
  2061  			output, err = s.sqsClient.ReceiveMessage(input)
  2062  		}
  2063  	}
  2064  
  2065  	// evaluate result
  2066  	if err != nil {
  2067  		err = errors.New("ReceiveMessage Failed: (Receive Action) " + err.Error())
  2068  		return nil, err
  2069  	} else {
  2070  		for _, v := range output.Messages {
  2071  			if v != nil {
  2072  				messagesList = append(messagesList, &SQSReceivedMessage{
  2073  					MessageId:              aws.StringValue(v.MessageId),
  2074  					Body:                   aws.StringValue(v.Body),
  2075  					MessageAttributes:      v.MessageAttributes,
  2076  					SystemAttributes:       s.fromAwsSystemAttributes(v.Attributes),
  2077  					MD5ofBody:              aws.StringValue(v.MD5OfBody),
  2078  					MD5ofMessageAttributes: aws.StringValue(v.MD5OfMessageAttributes),
  2079  					ReceiptHandle:          aws.StringValue(v.ReceiptHandle),
  2080  				})
  2081  			}
  2082  		}
  2083  
  2084  		return messagesList, nil
  2085  	}
  2086  }
  2087  
  2088  // ChangeMessageVisibility will update a message's visibility time out seconds,
  2089  // the message's receiptHandle is used along with queueUrl to identify which message in which queue is to be updated the new timeout value
  2090  func (s *SQS) ChangeMessageVisibility(queueUrl string,
  2091  	receiptHandle string,
  2092  	visibilityTimeOutSeconds int64,
  2093  	timeOutDuration ...time.Duration) (err error) {
  2094  	segCtx := context.Background()
  2095  	segCtxSet := false
  2096  
  2097  	seg := xray.NewSegmentNullable("SQS-ChangeMessageVisibility", s._parentSegment)
  2098  
  2099  	if seg != nil {
  2100  		segCtx = seg.Ctx
  2101  		segCtxSet = true
  2102  
  2103  		defer seg.Close()
  2104  		defer func() {
  2105  			_ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibility-QueueURL", queueUrl)
  2106  			_ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibility-ReceiptHandle", receiptHandle)
  2107  			_ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibility-VisibilityTimeOutSeconds", visibilityTimeOutSeconds)
  2108  
  2109  			if err != nil {
  2110  				_ = seg.Seg.AddError(err)
  2111  			}
  2112  		}()
  2113  	}
  2114  
  2115  	// validate
  2116  	if s.sqsClient == nil {
  2117  		err = errors.New("ChangeMessageVisibility Failed: " + "SQS Client is Required")
  2118  		return err
  2119  	}
  2120  
  2121  	if util.LenTrim(queueUrl) <= 0 {
  2122  		err = errors.New("ChangeMessageVisibility Failed: " + "Queue Url is Required")
  2123  		return err
  2124  	}
  2125  
  2126  	if util.LenTrim(receiptHandle) <= 0 {
  2127  		err = errors.New("ChangeMessageVisibility Failed: " + "Receipt Handle is Required")
  2128  		return err
  2129  	}
  2130  
  2131  	if visibilityTimeOutSeconds < 0 {
  2132  		visibilityTimeOutSeconds = 0
  2133  	}
  2134  
  2135  	// create input object
  2136  	input := &awssqs.ChangeMessageVisibilityInput{
  2137  		QueueUrl:      aws.String(queueUrl),
  2138  		ReceiptHandle: aws.String(receiptHandle),
  2139  	}
  2140  
  2141  	if visibilityTimeOutSeconds > 0 {
  2142  		input.VisibilityTimeout = aws.Int64(visibilityTimeOutSeconds)
  2143  	}
  2144  
  2145  	// perform action
  2146  	if len(timeOutDuration) > 0 {
  2147  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  2148  		defer cancel()
  2149  
  2150  		_, err = s.sqsClient.ChangeMessageVisibilityWithContext(ctx, input)
  2151  	} else {
  2152  		if segCtxSet {
  2153  			_, err = s.sqsClient.ChangeMessageVisibilityWithContext(segCtx, input)
  2154  		} else {
  2155  			_, err = s.sqsClient.ChangeMessageVisibility(input)
  2156  		}
  2157  	}
  2158  
  2159  	// evaluate result
  2160  	if err != nil {
  2161  		err = errors.New("ChangeMessageVisibility Failed: (Change Action) " + err.Error())
  2162  		return err
  2163  	} else {
  2164  		return nil
  2165  	}
  2166  }
  2167  
  2168  // ChangeMessageVisibilityBatch will update up to 10 messages' visibility time out values in a batch
  2169  func (s *SQS) ChangeMessageVisibilityBatch(queueUrl string,
  2170  	messageEntries []*SQSChangeVisibilityRequest,
  2171  	timeOutDuration ...time.Duration) (successIDsList []string, failedList []*SQSFailResult, err error) {
  2172  	segCtx := context.Background()
  2173  	segCtxSet := false
  2174  
  2175  	seg := xray.NewSegmentNullable("SQS-ChangeMessageVisibilityBatch", s._parentSegment)
  2176  
  2177  	if seg != nil {
  2178  		segCtx = seg.Ctx
  2179  		segCtxSet = true
  2180  
  2181  		defer seg.Close()
  2182  		defer func() {
  2183  			_ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-QueueURL", queueUrl)
  2184  			_ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-MessageEntries", messageEntries)
  2185  			_ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-Result-SuccessIDsList", successIDsList)
  2186  			_ = seg.Seg.AddMetadata("SQS-ChangeMessageVisibilityBatch-Result-FailedList", failedList)
  2187  
  2188  			if err != nil {
  2189  				_ = seg.Seg.AddError(err)
  2190  			}
  2191  		}()
  2192  	}
  2193  
  2194  	// validate
  2195  	if s.sqsClient == nil {
  2196  		err = errors.New("ChangeMessageVisibilityBatch Failed: " + "SQS Client is Required")
  2197  		return nil, nil, err
  2198  	}
  2199  
  2200  	if util.LenTrim(queueUrl) <= 0 {
  2201  		err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Queue Url is Required")
  2202  		return nil, nil, err
  2203  	}
  2204  
  2205  	if messageEntries == nil {
  2206  		err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Required (nil)")
  2207  		return nil, nil, err
  2208  	}
  2209  
  2210  	if len(messageEntries) <= 0 {
  2211  		err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Required (count = 0")
  2212  		return nil, nil, err
  2213  	}
  2214  
  2215  	if len(messageEntries) > 10 {
  2216  		err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Per Batch Limited to 10")
  2217  		return nil, nil, err
  2218  	}
  2219  
  2220  	// create input object
  2221  	var entries []*awssqs.ChangeMessageVisibilityBatchRequestEntry
  2222  
  2223  	for _, v := range messageEntries {
  2224  		if v != nil {
  2225  			if util.LenTrim(v.Id) > 0 && util.LenTrim(v.ReceiptHandle) > 0 {
  2226  				timeout := v.VisibilityTimeOutSeconds
  2227  
  2228  				if timeout < 0 {
  2229  					timeout = 0
  2230  				}
  2231  
  2232  				entries = append(entries, &awssqs.ChangeMessageVisibilityBatchRequestEntry{
  2233  					Id:                aws.String(v.Id),
  2234  					ReceiptHandle:     aws.String(v.ReceiptHandle),
  2235  					VisibilityTimeout: aws.Int64(timeout),
  2236  				})
  2237  			}
  2238  		}
  2239  	}
  2240  
  2241  	if len(entries) <= 0 {
  2242  		err = errors.New("ChangeMessageVisibilityBatch Failed: " + "Message Entries Elements Count Must Not Be Zero")
  2243  		return nil, nil, err
  2244  	}
  2245  
  2246  	input := &awssqs.ChangeMessageVisibilityBatchInput{
  2247  		QueueUrl: aws.String(queueUrl),
  2248  		Entries:  entries,
  2249  	}
  2250  
  2251  	// perform action
  2252  	var output *awssqs.ChangeMessageVisibilityBatchOutput
  2253  
  2254  	if len(timeOutDuration) > 0 {
  2255  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  2256  		defer cancel()
  2257  
  2258  		output, err = s.sqsClient.ChangeMessageVisibilityBatchWithContext(ctx, input)
  2259  	} else {
  2260  		if segCtxSet {
  2261  			output, err = s.sqsClient.ChangeMessageVisibilityBatchWithContext(segCtx, input)
  2262  		} else {
  2263  			output, err = s.sqsClient.ChangeMessageVisibilityBatch(input)
  2264  		}
  2265  	}
  2266  
  2267  	// evaluate result
  2268  	if err != nil {
  2269  		err = errors.New("ChangeMessageVisibilityBatch Failed: (Change Action) " + err.Error())
  2270  		return nil, nil, err
  2271  	} else {
  2272  		if len(output.Successful) > 0 {
  2273  			for _, v := range output.Successful {
  2274  				if v != nil {
  2275  					successIDsList = append(successIDsList, aws.StringValue(v.Id))
  2276  				}
  2277  			}
  2278  		}
  2279  
  2280  		if len(output.Failed) > 0 {
  2281  			for _, v := range output.Failed {
  2282  				if v != nil {
  2283  					failedList = append(failedList, &SQSFailResult{
  2284  						Id:          aws.StringValue(v.Id),
  2285  						Code:        aws.StringValue(v.Code),
  2286  						Message:     aws.StringValue(v.Message),
  2287  						SenderFault: aws.BoolValue(v.SenderFault),
  2288  					})
  2289  				}
  2290  			}
  2291  		}
  2292  
  2293  		return successIDsList, failedList, nil
  2294  	}
  2295  }
  2296  
  2297  // DeleteMessage will delete a message from sqs queue based on receiptHandle and queueUrl specified
  2298  func (s *SQS) DeleteMessage(queueUrl string,
  2299  	receiptHandle string,
  2300  	timeOutDuration ...time.Duration) (err error) {
  2301  	segCtx := context.Background()
  2302  	segCtxSet := false
  2303  
  2304  	seg := xray.NewSegmentNullable("SQS-DeleteMessage", s._parentSegment)
  2305  
  2306  	if seg != nil {
  2307  		segCtx = seg.Ctx
  2308  		segCtxSet = true
  2309  
  2310  		defer seg.Close()
  2311  		defer func() {
  2312  			_ = seg.Seg.AddMetadata("SQS-DeleteMessage-QueueURL", queueUrl)
  2313  			_ = seg.Seg.AddMetadata("SQS-DeleteMessage-ReceiptHandle", receiptHandle)
  2314  
  2315  			if err != nil {
  2316  				_ = seg.Seg.AddError(err)
  2317  			}
  2318  		}()
  2319  	}
  2320  
  2321  	// validate
  2322  	if s.sqsClient == nil {
  2323  		err = errors.New("DeleteMessage Failed: " + "SQS Client is Required")
  2324  		return err
  2325  	}
  2326  
  2327  	if util.LenTrim(queueUrl) <= 0 {
  2328  		err = errors.New("DeleteMessage Failed: " + "Queue Url is Required")
  2329  		return err
  2330  	}
  2331  
  2332  	if util.LenTrim(receiptHandle) <= 0 {
  2333  		err = errors.New("DeleteMessage Failed: " + "Receipt Handle is Required")
  2334  		return err
  2335  	}
  2336  
  2337  	// create input object
  2338  	input := &awssqs.DeleteMessageInput{
  2339  		QueueUrl:      aws.String(queueUrl),
  2340  		ReceiptHandle: aws.String(receiptHandle),
  2341  	}
  2342  
  2343  	// perform action
  2344  	if len(timeOutDuration) > 0 {
  2345  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  2346  		defer cancel()
  2347  
  2348  		_, err = s.sqsClient.DeleteMessageWithContext(ctx, input)
  2349  	} else {
  2350  		if segCtxSet {
  2351  			_, err = s.sqsClient.DeleteMessageWithContext(segCtx, input)
  2352  		} else {
  2353  			_, err = s.sqsClient.DeleteMessage(input)
  2354  		}
  2355  	}
  2356  
  2357  	// evaluate result
  2358  	if err != nil {
  2359  		err = errors.New("DeleteMessage Failed: (Delete Action) " + err.Error())
  2360  		return err
  2361  	} else {
  2362  		return nil
  2363  	}
  2364  }
  2365  
  2366  // DeleteMessageBatch will delete up to 10 messages from given queue by queueUrl and message receiptHandles
  2367  func (s *SQS) DeleteMessageBatch(queueUrl string,
  2368  	messageEntries []*SQSDeleteMessageRequest,
  2369  	timeOutDuration ...time.Duration) (successIDsList []string, failedList []*SQSFailResult, err error) {
  2370  	segCtx := context.Background()
  2371  	segCtxSet := false
  2372  
  2373  	seg := xray.NewSegmentNullable("SQS-DeleteMessageBatch", s._parentSegment)
  2374  
  2375  	if seg != nil {
  2376  		segCtx = seg.Ctx
  2377  		segCtxSet = true
  2378  
  2379  		defer seg.Close()
  2380  		defer func() {
  2381  			_ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-QueueURL", queueUrl)
  2382  			_ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-MessageEntries", messageEntries)
  2383  			_ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-Result-SuccessIDsList", successIDsList)
  2384  			_ = seg.Seg.AddMetadata("SQS-DeleteMessageBatch-Result-FailedList", failedList)
  2385  
  2386  			if err != nil {
  2387  				_ = seg.Seg.AddError(err)
  2388  			}
  2389  		}()
  2390  	}
  2391  
  2392  	// validate
  2393  	if s.sqsClient == nil {
  2394  		err = errors.New("DeleteMessageBatch Failed: " + "SQS Client is Required")
  2395  		return nil, nil, err
  2396  	}
  2397  
  2398  	if util.LenTrim(queueUrl) <= 0 {
  2399  		err = errors.New("DeleteMessageBatch Failed: " + "Queue Url is Required")
  2400  		return nil, nil, err
  2401  	}
  2402  
  2403  	if messageEntries == nil {
  2404  		err = errors.New("DeleteMessageBatch Failed: " + "Message Entries Required (nil)")
  2405  		return nil, nil, err
  2406  	}
  2407  
  2408  	if len(messageEntries) <= 0 {
  2409  		err = errors.New("DeleteMessageBatch Failed: " + "Message Entries Required (count = 0)")
  2410  		return nil, nil, err
  2411  	}
  2412  
  2413  	if len(messageEntries) > 10 {
  2414  		err = errors.New("DeleteMessageBatch Failed: " + "Message Entries Per Batch Limited to 10")
  2415  		return nil, nil, err
  2416  	}
  2417  
  2418  	// create input object
  2419  	var entries []*awssqs.DeleteMessageBatchRequestEntry
  2420  
  2421  	for _, v := range messageEntries {
  2422  		if v != nil {
  2423  			if util.LenTrim(v.Id) > 0 && util.LenTrim(v.ReceiptHandle) > 0 {
  2424  				entries = append(entries, &awssqs.DeleteMessageBatchRequestEntry{
  2425  					Id:            aws.String(v.Id),
  2426  					ReceiptHandle: aws.String(v.ReceiptHandle),
  2427  				})
  2428  			}
  2429  		}
  2430  	}
  2431  
  2432  	if len(entries) <= 0 {
  2433  		err = errors.New("DeleteMessagseBatch Failed: " + "Message Entries Elements Must Not Be Zero")
  2434  		return nil, nil, err
  2435  	}
  2436  
  2437  	input := &awssqs.DeleteMessageBatchInput{
  2438  		QueueUrl: aws.String(queueUrl),
  2439  		Entries:  entries,
  2440  	}
  2441  
  2442  	// perform action
  2443  	var output *awssqs.DeleteMessageBatchOutput
  2444  
  2445  	if len(timeOutDuration) > 0 {
  2446  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  2447  		defer cancel()
  2448  
  2449  		output, err = s.sqsClient.DeleteMessageBatchWithContext(ctx, input)
  2450  	} else {
  2451  		if segCtxSet {
  2452  			output, err = s.sqsClient.DeleteMessageBatchWithContext(segCtx, input)
  2453  		} else {
  2454  			output, err = s.sqsClient.DeleteMessageBatch(input)
  2455  		}
  2456  	}
  2457  
  2458  	// evaluate result
  2459  	if err != nil {
  2460  		err = errors.New("DeleteMessageBatch Failed: (Delete Action) " + err.Error())
  2461  		return nil, nil, err
  2462  	} else {
  2463  		if len(output.Successful) > 0 {
  2464  			for _, v := range output.Successful {
  2465  				if v != nil {
  2466  					successIDsList = append(successIDsList, aws.StringValue(v.Id))
  2467  				}
  2468  			}
  2469  		}
  2470  
  2471  		if len(output.Failed) > 0 {
  2472  			for _, v := range output.Failed {
  2473  				if v != nil {
  2474  					failedList = append(failedList, &SQSFailResult{
  2475  						Id:          aws.StringValue(v.Id),
  2476  						Code:        aws.StringValue(v.Code),
  2477  						Message:     aws.StringValue(v.Message),
  2478  						SenderFault: aws.BoolValue(v.SenderFault),
  2479  					})
  2480  				}
  2481  			}
  2482  		}
  2483  
  2484  		return successIDsList, failedList, nil
  2485  	}
  2486  }