Amazon-SQS-Client

 view release on metacpan or  search on metacpan

lib/Amazon/SQS/Client.pm  view on Meta::CPAN

      $client_options->{SecurityToken} = $args[2];
    }
  }

  return $class->SUPER::new(
    { aws_access_key_id     => $args[0],
      aws_secret_access_key => $args[1],
      $client_options->{SecurityToken} ? ( token    => $client_options->{SecurityToken} ) : (),
      $client_options->{loglevel}      ? ( loglevel => $client_options->{loglevel} )      : (),
    }
  );
}

################################################################################
#  Copyright 2008 Amazon Technologies, Inc.
#  Licensed under the Apache License, Version 2.0 (the "License");
#
#  You may not use this file except in compliance with the License.
#  You may obtain a copy of the License at: http://aws.amazon.com/apache2.0
#  This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
#  CONDITIONS OF ANY KIND, either express or implied. See the License for the
#  specific language governing permissions and limitations under the License.
#
#  Copyright 2024 Robert C. Lauer
#
#  Note: The software contained in this distribution has been modified from the
#  original. You may freely use and distribute this software under the
#  terms of the original license.

package Amazon::SQS::Client;

use strict;
use warnings;

use Amazon::Credentials;
use Amazon::SQS::Constants qw(:all);
use Amazon::SQS::Exception;
use Carp qw(croak);
use Data::Dumper;
use Digest::SHA qw (hmac_sha1_base64 hmac_sha256_base64);
use English qw(-no_match_vars);
use LWP::UserAgent;
use Scalar::Util qw(reftype);
use Time::HiRes qw(usleep);
use URI::Escape;
use URI;
use XML::Simple;

__PACKAGE__->follow_best_practice();
__PACKAGE__->mk_accessors(
  qw(
    ServiceURL
    UserAgent
    SignatureVersion
    SignatureMethod
    MaxErrorRetry
    ServiceVersion
    SecurityToken
    Region
    v4_signer
    credentials
    last_request
    last_response
  )
);

use parent qw(Class::Accessor::Fast);

our $VERSION = '@PACKAGE_VERSION';

########################################################################
sub new {
########################################################################
  my ( $class, @args ) = @_;

  my $options;

  if ( ref $args[0] ) {
    $options = $args[0];
  }
  elsif ( $args[0] && $args[1] ) {
    my $credentials = Amazon::SQS::Credentials->new(@args);

    $options = { credentials => $credentials };

    if ( ref $args[2] ) {
      $options = { %{$options}, %{ $args[2] } };
    }
  }
  else {
    $options = ref $args[2] ? $args[2] : {};
    $options->{credentials} //= Amazon::Credentials->new();
  }

  set_defaults($options);

  my $self = $class->SUPER::new($options);

  $self->init_v4_signer;

  return $self;
}

########################################################################
sub set_defaults {
########################################################################
  my ($options) = @_;

  $options->{SignatureVersion} //= 2;
  $options->{SignatureMethod}  //= 'HmacSHA256';
  $options->{MaxErrorRetry}    //= 3;
  $options->{ServiceVersion}   //= '2012-11-05';

  if ( $options->{Region} && !$options->{ServiceURL} ) {
    $options->{ServiceURL} = sprintf 'https://sqs.%s.amazonaws.com', $options->{Region};
  }
  elsif ( !$options->{ServiceURL} ) {
    $options->{ServiceURL} = 'https://queue.amazonaws.com';
  }

  if ( !$options->{UserAgent} ) {
    require LWP::UserAgent;
    $options->{UserAgent} = LWP::UserAgent->new;
  }

  return $options;
}

########################################################################
sub init_v4_signer {
########################################################################
  my ($self) = @_;

  return
    if $self->get_SignatureVersion ne '4';

  my $credentials = $self->get_credentials;

  my $aws_access_key_id     = $credentials->get_aws_access_key_id;
  my $aws_secret_access_key = $credentials->get_aws_secret_access_key;
  my $token                 = $credentials->get_token;

  require AWS::Signature4;

  $self->set_v4_signer(
    AWS::Signature4->new(
      '-access_key' => $aws_access_key_id,
      '-secret_key' => $aws_secret_access_key,
      $token
      ? ( '-security_token' => $token )
      : ()

    )
  );

  return;
}

# setter/getters for resetting credentials
########################################################################
sub aws_access_key_id {
########################################################################
  my ( $self, @args ) = @_;

  if (@args) {
    $self->get_credentials->set_aws_access_key_id( $args[0] );
  }

  return $self->get_credentials->get_aws_access_key_id();
}

########################################################################
sub aws_secret_access_key {
########################################################################
  my ( $self, @args ) = @_;

  if (@args) {
    $self->get_credentials->set_aws_secret_access_key( $args[0] );
  }

  return $self->get_credentials->get_aws_secret_access_key();
}

########################################################################
sub token {
########################################################################
  my ( $self, @args ) = @_;

  if (@args) {
    $self->get_credentials->set_token( $args[0] );
  }

  return $self->get_credentials->get_token();
}

########################################################################
sub createQueue {
########################################################################
  my ( $self, $request ) = @_;

  if ( ref $request ne 'Amazon::SQS::Model::CreateQueueRequest' ) {
    require Amazon::SQS::Model::CreateQueueRequest;
    $request = Amazon::SQS::Model::CreateQueueRequest->new($request);
  }

  require Amazon::SQS::Model::CreateQueueResponse;

  return Amazon::SQS::Model::CreateQueueResponse->fromXML(
    $self->_invoke( $self->_convertCreateQueue($request) ) );
}

########################################################################
sub listQueues {
########################################################################
  my ( $self, $request ) = @_;

  if ( not ref $request eq 'Amazon::SQS::Model::ListQueuesRequest' ) {
    require Amazon::SQS::Model::ListQueuesRequest;
    $request = Amazon::SQS::Model::ListQueuesRequest->new($request);
  }

  require Amazon::SQS::Model::ListQueuesResponse;

  return Amazon::SQS::Model::ListQueuesResponse->fromXML(
    $self->_invoke( $self->_convertListQueues($request) ) );
}

########################################################################
sub listDeadLetterSourceQueues {
########################################################################
  my ( $self, $request ) = @_;

  if ( not ref $request eq 'Amazon::SQS::Model::ListDeadLetterSourceQueuesRequest' ) {
    require Amazon::SQS::Model::ListDeadLetterSourceQueuesRequest;
    $request = Amazon::SQS::Model::ListDeadLetterSourceQueuesRequest->new($request);
  }

  require Amazon::SQS::Model::ListDeadLetterSourceQueuesResponse;

  return Amazon::SQS::Model::ListDeadLetterSourceQueuesResponse->fromXML(
    $self->_invoke( $self->_convertListDeadLetterSourceQueues($request) ) );
}

########################################################################
sub addPermission {
########################################################################
  my ( $self, $request ) = @_;

  if ( not ref $request eq 'Amazon::SQS::Model::AddPermissionRequest' ) {
    require Amazon::SQS::Model::AddPermissionRequest;
    $request = Amazon::SQS::Model::AddPermissionRequest->new($request);
  }
  require Amazon::SQS::Model::AddPermissionResponse;

lib/Amazon/SQS/Client.pm  view on Meta::CPAN


  return $ex
    if ref $ex;

  return Amazon::SQS::Exception->new(
    { Message      => 'Internal Error',
      StatusCode   => $status,
      ResponseBody => $responseBody,
    }
  );
}

#
# perform http post
#
########################################################################
sub _httpPost {
########################################################################
  my ( $self, $queueUrl, $parameters ) = @_;

  my $url = $queueUrl;

  my $ua = $self->get_UserAgent;

  my $request = HTTP::Request->new( POST => $url );
  $request->content_type('application/x-www-form-urlencoded; charset=utf-8');

  my $data = $EMPTY;

  foreach my $parameterName ( keys %{$parameters} ) {
    no warnings 'uninitialized';  ## no critic

    $data .= $parameterName . $EQUALS . $self->_urlencode( $parameters->{$parameterName}, 0 );
    $data .= $AMPERSAND;
  }

  chop $data;

  $request->content($data);

  # sign request here if v4 else, it is done in _addRequiredParameters()
  if ( defined $self->get_v4_signer ) {
    $self->get_v4_signer->sign($request);
  }

  $self->set_last_request($request);

  my $response = $ua->request($request);

  $self->set_last_response($response);

  return $response;
}

#
# Add authentication related and version parameters
#
sub _addRequiredParameters {
  my ( $self, $parameters, $queueUrl ) = @_;

  my $credentials           = $self->get_credentials;
  my $token                 = $credentials->get_token;
  my $aws_access_key_id     = $credentials->get_aws_access_key_id;
  my $aws_secret_access_key = $credentials->get_aws_secret_access_key;

  $parameters->{AWSAccessKeyId} = $aws_access_key_id;
  $parameters->{Timestamp}      = $self->_getFormattedTimestamp();
  $parameters->{Version}        = $self->get_ServiceVersion;

  # v2 signing
  if ( !defined $self->{_v4_signer} ) {
    if ($token) {
      $parameters->{SecurityToken} = $token;
    }

    $parameters->{SignatureVersion} = $self->get_SignatureVersion || '1';
    $parameters->{Signature}        = $self->_signParameters( $parameters, $queueUrl, $aws_secret_access_key );
  }

  return $parameters;
}

#
# Computes RFC 2104-compliant HMAC signature for request parameters
# Implements AWS Signature, as per following spec:
#
# If Signature Version is 0, it signs concatenated Action and Timestamp
#
# If Signature Version is 1, it performs the following:
#
# Sorts all  parameters (including SignatureVersion and excluding Signature,
# the value of which is being created), ignoring case.
#
# Iterate over the sorted list and append the parameter name (in original case)
# and then its value. It will not URL-encode the parameter values before
# constructing this string. There are no separators.
#
sub _signParameters {
  my ( $self, $parameters, $queueUrl, $key ) = @_;

  my $algorithm = 'HmacSHA1';
  my $data      = $EMPTY;

  my $signatureVersion = $parameters->{SignatureVersion};

  if ( '0' eq $signatureVersion ) {
    $data = $self->_calculateStringToSignV0($parameters);
  }
  elsif ( '1' eq $signatureVersion ) {
    $data = $self->_calculateStringToSignV1($parameters);
  }
  elsif ( '2' eq $signatureVersion ) {
    $algorithm                     = $self->get_SignatureMethod;
    $parameters->{SignatureMethod} = $algorithm;
    $data                          = $self->_calculateStringToSignV2( $parameters, $queueUrl );
  }
  else {
    Carp::croak('Invalid Signature Version specified');
  }

  return $self->_sign( $data, $key, $algorithm );
}

sub _calculateStringToSignV0 {

lib/Amazon/SQS/Client.pm  view on Meta::CPAN

losing messages or requiring each component to be always available.
Amazon SQS works by exposing Amazon's web-scale messaging
infrastructure as a web service. Any computer on the Internet can add
or read messages without any installed software or special firewall
configurations. Components of applications using Amazon SQS can run
independently, and do not need to be on the same network, developed
with the same technologies, or running at the same time.

=head1 METHODS AND SUBROUTINES

=head2 new 

 new( aws-access-key-id, aws-secret-access-key, [token], [options] )

=over 5

=item aws-access-key-id

The AWS I<access key> your were given when you signed up for AWS services.

You can create a new account by visiting L</http://aws.amazon.com/>.

=item aws-secret-access-key

The AWS I<secret access key> you were given when you signed up for AWS services.

=item token

Pass the session token as the third argument on as SecurityToken in
the options hash described below.

=item options

C<options> is an optional hash reference containing the options listed
below.

=over 5

=item * ServiceURL

default: C<https://queue.amazonaws.com>

Set the ServiceUrl when you want to use a mocking service like
L<LocalStack|https://www.localstack.cloud>.

=item * UserAgent

default: LWP::UserAgent

=item * SignatureVersion

default: 2

I<Note: Signature Version 4 is supported by AWS::Signature4. If you
use the Signature 4 signing facility, make sure your ServiceURL
includes the region endpoint.  Ex:
https://sqs.us-east-1.amazonaws.com.>

=item * SecurityToken

For temporary credentials, add the security token returned from the
AWS Security Token Service.

=item * ServiceVersion

default: 2012-11-05

=item * MaxErrorRetry

default: 3

=item * credentials

An instance of a class (e.g. Amazon::Credentials) which supports the getters:

 get_aws_access_key_id
 get_aws_secret_access_key
 get_token

You are encouraged to use this option rather than sending the
credentials in the constructor.

=back

=back

=head2 createQueue

 createQueue( request )

The C<CreateQueue> action creates a new queue, or returns the URL of an
existing one.  When you request C<CreateQueue>, you provide a name for
the queue. To successfully create a new queue, you must provide a name
that is unique within the scope of your own queues. If you provide the
name of an existing queue, a new queue isnE<039>t created and an error
isnE<039>t returned. Instead, the request succeeds and the queue URL for
the existing queue is returned.

I<Exception: if you provide a value for C<DefaultVisibilityTimeout> that is
different from the value for the existing queue, you receive an error.>

See
L</http://docs.amazonwebservices.com/AWSSimpleQueueService/2009-02-01/SQSDeveloperGuide/Query_QueryCreateQueue.html>.

Returns an C<Amazon::SQS::Model::CreateQueueResponse> object.

Throws an C<Amazon::SQS::Exception>. Use eval to catch it.

=over 5

=item request

C<request> is either a hash reference of parameters for
a C<Amazon::SQS::Model::CreateQueueRequest> object or
a C<Amazon::SQS::Model::CreateQueueRequest> object itself.

See C<Amazon::SQS::Model::CreateQueueRequest> for valid arguments.

=back

=head2 listQueues

 listQueues( request )

The ListQueues action returns a list of your queues.

Returns an C<Amazon::SQS::Model::ListQueuesResponse> object.

Throws an C<Amazon::SQS::Exception>. Use eval to catch it

See L</http://docs.amazonwebservices.com/AWSSimpleQueueService/2009-02-01/SQSDeveloperGuide/Query_QueryListQueues.html>

=over 5

=item request

Argument either hash reference of parameters for
C<Amazon::SQS::Model::ListQueuesRequest> request or
C<Amazon::SQS::Model::ListQueuesRequest> object itself.

See C<Amazon::SQS::Model::ListQueuesRequest> for valid arguments.



( run in 0.767 second using v1.01-cache-2.11-cpan-39bf76dae61 )