File Coverage

blib/lib/AWS/SQS/Simple.pm
Criterion Covered Total %
statement 33 150 22.0
branch 0 24 0.0
condition 0 3 0.0
subroutine 11 24 45.8
pod 7 7 100.0
total 51 208 24.5


line stmt bran cond sub pod time code
1             package AWS::SQS::Simple;
2              
3 1     1   23718 use warnings ;
  1         3  
  1         37  
4 1     1   8 use strict ;
  1         2  
  1         36  
5              
6 1     1   7 use Carp ;
  1         7  
  1         89  
7              
8 1     1   1079 use utf8 ;
  1         12  
  1         6  
9              
10 1     1   1061 use LWP::UserAgent ;
  1         61823  
  1         39  
11 1     1   12 use HTTP::Headers ;
  1         2  
  1         28  
12              
13 1     1   6 use URI::Escape ;
  1         2  
  1         92  
14              
15 1     1   1116 use Encode qw( encode ) ;
  1         13207  
  1         110  
16              
17 1     1   8776 use Digest::SHA qw(hmac_sha256 hmac_sha256_base64) ;
  1         4976  
  1         106  
18 1     1   846 use Digest::HMAC_SHA1 ;
  1         1788  
  1         53  
19              
20 1     1   1071 use MIME::Base64 qw(encode_base64) ;
  1         893  
  1         2075  
21              
22              
23              
24             =head1 NAME
25              
26             AWS::SQS::Simple - This module is used to access amazon simple queue services.
27              
28             =head1 VERSION
29              
30             Version 0.02
31              
32             =cut
33              
34             our $VERSION = '0.02';
35              
36              
37             =head1 SYNOPSIS
38              
39             This module is used to access amazon simple queue services.
40              
41              
42             use AWS::SQS::Simple ;
43              
44             my $ob = AWS::SQS::Simple->new(
45             ACCESS_KEY => '..' ,
46             SECRET_ACCESS_KEY => '..' ,
47              
48             AWS_ACCOUNT_ID => '..' ,
49              
50             END_POINT => '..' ,
51              
52             );
53              
54              
55              
56             my %params_hash = (
57              
58             QUEUE_NAME => QUEUE Name ,
59              
60             'AttributeName.1.Name' => Attribute Name ,
61             'AttributeName.1.Value' => Attribute Value , [ Required if there is a corresponding Name Attribute.n.name parameter ]
62              
63             'AttributeName.2.Name' => Attribute Name ,
64             'AttributeName.2.Value' => Attribute Value , [ Required if there is a corresponding Name Attribute.n.name parameter ]
65              
66             .....
67              
68             );
69              
70             $ob->create_queue( \%params_hash ) ;
71              
72             my %params_hash = (
73              
74             QUEUE_NAME => QUEUE Name ,
75              
76             'MessageBody' => Message to send ,
77             'DelaySeconds' => The number of seconds to delay a specific message , [ OPTIONAL ]
78              
79             );
80              
81             $ob->send_message( \%params_hash ) ;
82              
83              
84             my %params_hash = (
85              
86             QUEUE_NAME => QUEUE Name ,
87              
88             'AttributeName.n' => The attribute you want to get. Valid values: All | SenderId | SentTimestamp | ApproximateReceiveCount | ApproximateFirstReceiveTimestamp , [ OPTIONAL ]
89             'MaxNumberOfMessages' => Maximum number of messages to return. Default - 1 , [ OPTIONAL ]
90             'VisibilityTimeout' => The duration in seconds that the received messages are hidden from subsequent retrieve requests after being retrieved by a ReceiveMessage request. Default - The visibility timeout for the queue , [ OPTIONAL ]
91             'WaitTimeSeconds' => Long poll support (integer from 1 to 20 , [ OPTIONAL ]
92              
93             );
94              
95             $ob->receive_message->( \%params_hash )
96              
97              
98             =head1 CONSTRUCTOR
99              
100             =head2 new
101              
102             Constructs a new AWS::SQS::Simple object
103              
104             Following are the parametes taken by the constructor
105              
106             my $ob = AWS::SQS::Simple->new(
107             ACCESS_KEY => '..' ,
108             SECRET_ACCESS_KEY => '..' ,
109              
110             AWS_ACCOUNT_ID => '..' ,
111              
112             END_POINT => '..' ,
113              
114             );
115              
116             =cut
117              
118             sub new {
119            
120 0     0 1   my $class = shift;
121            
122 0           my %parameter_hash;
123              
124 0           my $count = @_;
125              
126 0           my $usage_howto = "
127              
128             Usage:
129              
130             my \$ob = AWS::SQS::Simple->new(
131             ACCESS_KEY => '..' ,
132             SECRET_ACCESS_KEY => '..' ,
133              
134             AWS_ACCOUNT_ID => '..' ,
135              
136             END_POINT => '..' ,
137              
138             );
139              
140             ";
141              
142 0           %parameter_hash = @_;
143              
144 0 0         croak $usage_howto unless( $parameter_hash{ AWS_ACCOUNT_ID } ) ;
145              
146 0 0         croak $usage_howto unless( $parameter_hash{ ACCESS_KEY } ) ;
147 0 0         croak $usage_howto unless( $parameter_hash{ SECRET_ACCESS_KEY } ) ;
148              
149 0 0         croak $usage_howto unless( $parameter_hash{ END_POINT } ) ;
150              
151             my $self = {
152              
153             ACCESS_KEY => $parameter_hash{ ACCESS_KEY } ,
154             SECRET_ACCESS_KEY => $parameter_hash{ SECRET_ACCESS_KEY } ,
155              
156             AWS_ACCOUNT_ID => $parameter_hash{ AWS_ACCOUNT_ID } ,
157              
158             END_POINT => $parameter_hash{ END_POINT } ,
159              
160 0           };
161              
162             ## Private and class data here.
163              
164 0           bless( $self, $class );
165              
166 0           return $self;
167              
168             }
169              
170              
171             =head1 FUNCTIONS
172              
173             No functions are exported by default.
174              
175             Following functions are all available through the AWS::SQS::Simple Object.
176              
177             =head2 create_queue
178            
179             This function creates a new queue.
180              
181             Usage :
182              
183             my %params_hash = (
184              
185             QUEUE_NAME => QUEUE Name ,
186              
187             'AttributeName.1.Name' => Attribute Name ,
188             'AttributeName.1.Value' => Attribute Value , [ Required if there is a corresponding Name Attribute.n.name parameter ]
189              
190             'AttributeName.2.Name' => Attribute Name ,
191             'AttributeName.2.Value' => Attribute Value , [ Required if there is a corresponding Name Attribute.n.name parameter ]
192              
193             .....
194              
195             );
196              
197             $ob->create_queue->( \%params_hash )
198              
199              
200             =cut
201              
202             sub create_queue {
203              
204 0     0 1   my $self = shift ;
205 0           my $params = shift ;
206              
207             my $params_to_pass = {
208             'Action' => 'CreateQueue' ,
209             'QueueName' => $params->{ QUEUE_NAME } ,
210             'AWSAccessKeyId' => $self->{ ACCESS_KEY } ,
211 0           'Timestamp' => _generate_timestamp() ,
212             'SignatureVersion' => 2 ,
213             'Version' => '2011-10-01' ,
214             'SignatureMethod' => 'HmacSHA256' ,
215              
216 0           %{ $params }
217             };
218              
219 0           my $url = $self->_get_url( $params_to_pass ) ;
220 0           my $response = $self->_make_request( $url ) ;
221            
222 0           return $response ;
223              
224             }
225              
226             =head2 send_message
227            
228             This function sends a message to the queue.
229              
230             Usage :
231              
232             my %params_hash = (
233              
234             QUEUE_NAME => QUEUE Name ,
235              
236             'MessageBody' => Message to send ,
237             'DelaySeconds' => The number of seconds to delay a specific message , [ OPTIONAL ]
238              
239             );
240              
241             $ob->send_message->( \%params_hash )
242              
243              
244             =cut
245              
246             sub send_message {
247              
248 0     0 1   my $self = shift ;
249 0           my $params = shift ;
250              
251 0           my $message_body = $params->{ MessageBody } ;
252              
253 0 0         unless( defined $message_body ){
254 0           print STDERR "Error : Message Body not defined" ;
255 0           return 0 ;
256             }
257              
258             my $params_to_pass = {
259             'Action' => 'SendMessage' ,
260             'AWSAccessKeyId' => $self->{ ACCESS_KEY } ,
261 0           'Timestamp' => _generate_timestamp() ,
262             'SignatureVersion' => 2 ,
263             'Version' => '2009-02-01' ,
264             'SignatureMethod' => 'HmacSHA256' ,
265              
266 0           %{ $params }
267             };
268              
269              
270 0           my $url = $self->_get_url( $params_to_pass ) ;
271              
272 0           my $response = $self->_make_request( $url ) ;
273            
274 0           return $response ;
275             }
276              
277              
278             =head2 receive_message
279            
280             This function returns mesaages already in the queue specified.
281              
282             Usage :
283              
284             my %params_hash = (
285              
286             QUEUE_NAME => QUEUE Name ,
287              
288             'AttributeName.n' => The attribute you want to get. Valid values: All | SenderId | SentTimestamp | ApproximateReceiveCount | ApproximateFirstReceiveTimestamp , [ OPTIONAL ]
289             'MaxNumberOfMessages' => Maximum number of messages to return. Default - 1 , [ OPTIONAL ]
290             'VisibilityTimeout' => The duration in seconds that the received messages are hidden from subsequent retrieve requests after being retrieved by a ReceiveMessage request. Default - The visibility timeout for the queue , [ OPTIONAL ]
291             'WaitTimeSeconds' => Long poll support (integer from 1 to 20 , [ OPTIONAL ]
292              
293             );
294              
295             $ob->receive_message->( \%params_hash )
296              
297             =cut
298              
299             sub receive_message {
300              
301 0     0 1   my $self = shift ;
302 0           my $params = shift ;
303              
304             my $params_to_pass = {
305             'Action' => 'ReceiveMessage' ,
306             'AWSAccessKeyId' => $self->{ ACCESS_KEY } ,
307 0           'Timestamp' => _generate_timestamp() ,
308             'SignatureVersion' => 2 ,
309             'Version' => '2009-02-01' ,
310             'SignatureMethod' => 'HmacSHA256' ,
311              
312 0           %{ $params }
313             };
314            
315 0           my $url = $self->_get_url( $params_to_pass ) ;
316 0           my $response = $self->_make_request( $url ) ;
317            
318 0           return $response ;
319             }
320              
321             =head2 delete_message
322            
323             This function deletes a message from the queue.
324              
325             Usage :
326              
327             my %params_hash = (
328              
329             QUEUE_NAME => QUEUE Name ,
330              
331             'ReceiptHandle' => The receipt handle associated with the message you want to delete ,
332             );
333              
334             $ob->delete_message->( \%params_hash )
335              
336              
337             =cut
338              
339             sub delete_message {
340              
341 0     0 1   my $self = shift ;
342 0           my $params = shift ;
343              
344 0           my $receipt_handle = $params->{ ReceiptHandle } ;
345              
346 0 0         unless( defined $receipt_handle ){
347 0           print STDERR "Error : Receipt Handle not defined" ;
348 0           return 0 ;
349             }
350              
351             my $params_to_pass = {
352             'Action' => 'DeleteMessage' ,
353             'AWSAccessKeyId' => $self->{ ACCESS_KEY } ,
354 0           'Timestamp' => _generate_timestamp() ,
355             'SignatureVersion' => 2 ,
356             'Version' => '2009-02-01' ,
357             'SignatureMethod' => 'HmacSHA256' ,
358              
359 0           %{ $params }
360             };
361              
362 0           my $url = $self->_get_url( $params_to_pass ) ;
363 0           my $response = $self->_make_request( $url ) ;
364            
365 0           return $response ;
366             }
367              
368             =head2 get_queue_attributes
369            
370             This function returns queue attributes.
371              
372             Usage :
373              
374             my %params_hash = (
375              
376             QUEUE_NAME => QUEUE Name ,
377              
378             'AttributeName.n' => The attribute you want to get ,
379             );
380              
381             $ob->get_queue_attributes->( \%params_hash )
382              
383              
384             =cut
385              
386             sub get_queue_attributes {
387              
388 0     0 1   my $self = shift ;
389 0           my $params = shift ;
390              
391             my $params_to_pass = {
392             'Action' => 'GetQueueAttributes' ,
393             'AWSAccessKeyId' => $self->{ ACCESS_KEY } ,
394 0           'Timestamp' => _generate_timestamp() ,
395             'SignatureVersion' => 2 ,
396             'Version' => '2012-11-05' ,
397             'SignatureMethod' => 'HmacSHA256' ,
398              
399 0           %{ $params }
400             };
401              
402              
403 0           my $url = $self->_get_url( $params_to_pass ) ;
404 0           my $response = $self->_make_request( $url ) ;
405            
406 0           return $response ;
407             }
408              
409              
410             =head1 INTERNAL SUBROUTINES/METHODS
411              
412             Following methods are used only by the modules.
413              
414             =head2 _get_url
415            
416             This function creates and returns url as per the parameters passed.
417              
418             =cut
419              
420             sub _get_url {
421            
422 0     0     my $self = shift ;
423 0           my $params = shift ;
424              
425 0           my $url_additional_str = $self->{ AWS_ACCOUNT_ID } . '/' . delete( $params->{ QUEUE_NAME } ) ;
426              
427 0           my $sign_query = _get_signed_query( $params ) ;
428            
429 0           my $to_escape = qr{^(?:Signature|MessageBody|ReceiptHandle)|\.\d+\.(?:MessageBody|ReceiptHandle)$} ;
430 0           foreach my $key( keys %$params ) {
431              
432 0 0         next unless $key =~ m/$to_escape/ ;
433 0 0         next unless exists $params->{ $key } ;
434              
435 0           my $octets = encode( 'utf-8-strict', $params->{ $key } ) ;
436 0           $params->{ $key } = escape( $octets ) ;
437              
438             }
439              
440 0           my $uri_str = join('&', map { $_ . '=' . $params->{$_} } keys %$params ) ;
  0            
441              
442 0           my $sign_str = "GET\n".$self->{ END_POINT }."\n/" ;
443 0 0         $sign_str .= $url_additional_str . "/" if( $params->{ Action } ne "CreateQueue" ) ;
444 0           $sign_str .= "\n" . $sign_query ;
445              
446              
447 0           my $signature = $self->_generate_signatue( $sign_str ) ;
448            
449 0           $uri_str .= '&Signature=' . escape( $signature ) ;
450              
451 0           my $url = "http://".$self->{ END_POINT } ;
452 0 0         $url .= '/' . $url_additional_str . '/' if( $params->{ Action } ne "CreateQueue" ) ;
453 0           $url .= '?' . $uri_str ;
454              
455 0           return $url ;
456              
457             }
458              
459             =head2 _generate_signatue
460            
461             This function generate signature using HMACSHA256 method and version 2.
462              
463             =cut
464              
465             sub _generate_signatue {
466              
467 0     0     my $self = shift ;
468 0           my $query = shift ;
469            
470 0           my $secret_access_key = $self->{ SECRET_ACCESS_KEY } ;
471              
472 0           my $digest = encode_base64( hmac_sha256($query, $secret_access_key ),'' ) ;
473              
474 0           return $digest ;
475             }
476              
477             =head2 _get_signed_query
478            
479             This function utf8 encodes and uri escapes the parameters passed to generate the signed string.
480              
481             =cut
482              
483             sub _get_signed_query {
484              
485 0     0     my $params = shift ;
486              
487 0           my $to_sign ;
488 0           for my $key( sort keys %$params ) {
489              
490 0 0         $to_sign .= '&' if $to_sign ;
491              
492 0           my $key_octets = encode('utf-8-strict', $key ) ;
493 0           my $value_octets = encode('utf-8-strict', $params->{ $key } ) ;
494              
495 0           $to_sign .= escape( $key_octets ) . '=' . escape( $value_octets ) ;
496              
497             }
498            
499 0           return $to_sign ;
500             }
501              
502              
503             =head2 escape
504              
505             URI escape only the characters that should be escaped, according to RFC 3986
506              
507             =cut
508              
509             sub escape {
510              
511 0     0 1   my ($str) = @_;
512              
513 0           return uri_escape_utf8( $str,'^A-Za-z0-9\-_.~' ) ;
514             }
515              
516             =head2 _generate_timestamp
517              
518             Calculate current TimeStamp
519              
520             =cut
521              
522             sub _generate_timestamp {
523              
524             return sprintf("%04d-%02d-%02dT%02d:%02d:%02d.000Z",
525 0     0     sub { ($_[5]+1900,
526             $_[4]+1,
527             $_[3],
528             $_[2],
529             $_[1],
530             $_[0])
531 0     0     }->(gmtime(time)));
532             }
533              
534             =head2 _make_request
535              
536             =cut
537              
538             sub _make_request {
539              
540 0     0     my $self = shift ;
541 0           my $url_to_access = shift ;
542              
543 0           my $contents ;
544 0           my $attempts = 0 ;
545 0           my $got_data = 0 ;
546            
547 0           my $this_profile_location ;
548            
549             my $response;
550            
551 0   0       until( $got_data or $attempts > 5 ) {
552            
553 0           my $request = HTTP::Request->new(
554             GET => $url_to_access
555             );
556            
557 0           my $ua = LWP::UserAgent->new ;
558 0           $ua->timeout(60) ;
559 0           $ua->env_proxy ;
560 0           $ua->agent( 'AWIS-INFO_GET/'.$VERSION ) ;
561            
562 0           $response = $ua->request( $request ) ;
563              
564 0 0         if( $response->is_success() ) {
565            
566 0           $contents = $response->content;
567 0           $got_data = 1;
568            
569             } else {
570              
571 0           $contents = $response->content ;
572            
573 0           print STDERR "ERROR : $contents" ;
574              
575 0           $attempts++ ;
576 0           sleep( $attempts * 10 ) ;
577            
578             }
579            
580 0           $contents = $response->content ;
581            
582 0           $attempts++ ;
583            
584             }
585            
586              
587 0           my $response_content = $response->content ;
588              
589 0           return $response_content ;
590              
591             }
592              
593              
594             =head1 AUTHOR
595              
596             Ankita, C<< >>
597              
598              
599             =head1 COPYRIGHT & LICENSE
600              
601             Copyright 2014 Ankita Singhal, all rights reserved.
602              
603             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
604              
605             =cut
606              
607             1; # End of AWS::SQS::Simple
608