File Coverage

blib/lib/Amazon/SQS/ProducerConsumer/Base.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Amazon::SQS::ProducerConsumer::Base;
2              
3 1     1   19 use 5.006;
  1         3  
  1         80  
4 1     1   6 use strict;
  1         2  
  1         32  
5 1     1   4 use warnings;
  1         2  
  1         27  
6              
7 1     1   509 use XML::Simple;
  0            
  0            
8             use LWP::UserAgent;
9             use Digest::HMAC_SHA1;
10             use URI::Escape qw(uri_escape_utf8);
11             use MIME::Base64 qw(encode_base64);
12              
13              
14             =head1 NAME
15              
16             Amazon::SQS::ProducerConsumer::Base - Perl interface to the Amazon Simple Queue Service (SQS) environment
17              
18             =head1 VERSION
19              
20             Version 0.04
21              
22             =cut
23              
24             our $VERSION = '0.04';
25              
26             =head1 SYNOPSIS
27              
28             use Amazon::SQS::ProducerConsumer::Base;
29              
30             my $sqs = new Amazon::SQS::ProducerConsumer::Base
31             AWSAccessKeyId => 'PUBLIC_KEY_HERE',
32             SecretAccessKey => 'SECRET_KEY_HERE';
33              
34             # Create a queue
35             my $queueURL = $sqs->create_queue( QueueName => 'TestQueue' );
36              
37             # Send a message to that queue
38             my $messageID = $sqs->send_message( Queue => $queueURL, MessageBody => 'Test message' );
39              
40             # Get a message from that queue
41             my $message = $sqs->receive_message( Queue => $queueURL );
42             print 'Message ID: ', $message->{MessageId}, "\n";
43             print 'Message: ', $message->{MessageBody}, "\n";
44              
45             # Delete the message you got
46             my $message = $sqs->delete_message( Queue => $queueURL, MessageId => $message->{MessageId} );
47              
48             If an error occurs in communicating with SQS, the return value will be undef and $sqs->{error} will be populated with the message.
49              
50             =cut
51              
52             sub new {
53             my ($class, %args) = @_;
54              
55             my $me = \%args;
56             bless $me, $class;
57             $me->initialize;
58             return $me;
59             }
60              
61             sub initialize {
62             my $me = shift;
63             $me->{signature_version} = 2;
64             $me->{version} = '2009-02-01';
65             $me->{host} ||= 'queue.amazonaws.com';
66             }
67              
68             sub create_queue {
69             my ($me, %args) = @_;
70              
71             my $xml = $me->sign_and_post( Action => 'CreateQueue', %args );
72             return undef if $me->check_error( $xml );
73             return $xml->{CreateQueueResult}{QueueUrl};
74             }
75              
76             sub list_queues {
77             my ($me, %args) = @_;
78              
79             my $xml = $me->sign_and_post( Action => 'ListQueues', %args );
80             return undef if $me->check_error( $xml );
81              
82             my $result;
83             $result = $xml->{ListQueuesResult}{QueueUrl};
84             map { $_ = (split '/', $_)[-1] } @$result if ref $result eq 'ARRAY';
85             return ref $result eq 'ARRAY' ? @$result : $result;
86             }
87              
88             sub delete_queue {
89             my ($me, %args) = @_;
90              
91             delete $args{ForceDeletion};
92             my $xml = $me->sign_and_post( Action => 'DeleteQueue', %args );
93             return undef if $me->check_error( $xml );
94              
95             return $xml->{ResponseMetadata}{RequestId};
96             }
97              
98             sub send_message {
99             my ($me, %args) = @_;
100              
101             my $xml = $me->sign_and_post( Action => 'SendMessage', %args );
102             return undef if $me->check_error( $xml );
103              
104             return $xml->{SendMessageResult}{MessageId};
105             }
106              
107             sub receive_message {
108             my ($me, %args) = @_;
109              
110             delete $args{NumberOfMessages};
111             my $xml = $me->sign_and_post( Action => 'ReceiveMessage', %args );
112             return undef if $me->check_error( $xml );
113              
114             return $xml->{ReceiveMessageResult}{Message};
115             }
116              
117             sub receive_messages {
118             my ($me, %args) = @_;
119              
120             my $xml = $me->sign_and_post( Action => 'ReceiveMessage', %args );
121             return undef if $me->check_error( $xml );
122             my $result = $xml->{ReceiveMessageResult}{Message};
123             return ref $result eq 'ARRAY' ? $result : [ $result ];
124             }
125              
126             sub delete_message {
127             my ($me, %args) = @_;
128              
129             my $xml = $me->sign_and_post( Action => 'DeleteMessage', %args );
130             return undef if $me->check_error( $xml );
131             return $xml->{ResponseMetadata}{RequestId};
132             }
133              
134             sub get_queue_attributes {
135             my ($me, %args) = @_;
136              
137             my $xml = $me->sign_and_post( Action => 'GetQueueAttributes', %args );
138             return undef if $me->check_error( $xml );
139             return $xml->{GetQueueAttributesResult}{Attribute}[0]{Value};
140             }
141              
142             sub set_queue_attributes {
143             my ($me, %args) = @_;
144              
145             my $xml = $me->sign_and_post( Action => 'SetQueueAttributes', %args );
146             return undef if $me->check_error( $xml );
147             return $xml->{ResponseMetadata}{RequestId};
148             }
149              
150             sub sign_and_post {
151             my ($me, %args) = @_;
152              
153             $me->{resource_path} = join '/', '', grep $_, $args{AWSAccessKeyId}, delete $args{Queue} if exists $args{Queue};
154             $me->{resource_path} ||= '/';
155              
156             my @t = gmtime;
157              
158             $args{AWSAccessKeyId} = $me->{AWSAccessKeyId};
159             $args{SignatureVersion} = $me->{signature_version};
160             $args{SignatureMethod} = 'HmacSHA1';
161             $args{Version} = $me->{version};
162             $args{Timestamp} = sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ", $t[5]+1900, $t[4]+1, @t[3,2,1,0];
163             $args{MaxNumberOfMessages} = delete $args{NumberOfMessages} if $args{NumberOfMessages};
164              
165             my @params;
166             for ( sort keys %args ) {
167             push @params, join '=', $_, uri_escape_utf8( $args{$_}, "^A-Za-z0-9\-_.~" );
168             }
169              
170             $me->{resource_path} =~ s|http://$me->{host}/||;
171             my $string_to_sign = join( "\n",
172             'POST', $me->{host}, $me->{resource_path}, join( '&', @params )
173             );
174              
175             $me->debug("QUERY TO SIGN: $string_to_sign");
176              
177             my $hashed = Digest::HMAC_SHA1->new( $me->{SecretAccessKey} );
178             $hashed->add( $string_to_sign );
179             my $encoded = encode_base64( $hashed->digest, '' );
180             $me->debug("ENCODED SIGNATURE: $encoded");
181             $args{Signature} = $encoded;
182              
183             my $result = LWP::UserAgent->new->post( "http://$me->{host}$me->{resource_path}", \%args );
184              
185             $me->debug("REQUEST RETURNED: " . $result->content);
186              
187             if ( $result->is_success ) {
188             my $parser = XML::Simple->new( ForceArray => [ 'item', 'QueueURL','AttributedValue', 'Attribute' ] );
189             return $parser->XMLin( $result->content() );
190             } else {
191             return { Errors => { Error => { Message => 'HTTP POST failed with error ' . $result->status_line } } };
192             }
193              
194             }
195              
196             sub check_error {
197             my ($me, $xml) = @_;
198              
199             if ( defined $xml->{Errors} && defined $xml->{Errors}{Error} ) {
200             $me->debug("ERROR: $xml->{Errors}{Error}{Message}");
201             $me->{error} = $xml->{Errors}{Error}{Message};
202             warn $me->{error};
203             return 1;
204             }
205             }
206              
207             sub error { $_[0]->{error} }
208              
209             sub debug {
210             my ($me, $message) = @_;
211              
212             if ((grep { defined && length } $me->{debug}) && $me->{debug} == 1) {
213             warn "$message\n";
214             }
215             }
216              
217              
218             =head1 AUTHOR
219              
220             Nic Wolff,
221              
222             =head1 BUGS
223              
224             Please report any bugs or feature requests to C, or through
225             the web interface at L. I will be notified, and then you'll
226             automatically be notified of progress on your bug as I make changes.
227              
228              
229              
230              
231             =head1 SUPPORT
232              
233             You can find documentation for this module with the perldoc command.
234              
235             perldoc Amazon::SQS::ProducerConsumer::Base
236              
237              
238             You can also look for information at:
239              
240             =over 4
241              
242             =item * RT: CPAN's request tracker (report bugs here)
243              
244             L
245              
246             =item * AnnoCPAN: Annotated CPAN documentation
247              
248             L
249              
250             =item * CPAN Ratings
251              
252             L
253              
254             =item * Search CPAN
255              
256             L
257              
258             =back
259              
260              
261             =head1 ACKNOWLEDGEMENTS
262              
263              
264             =head1 LICENSE AND COPYRIGHT
265              
266             Copyright 2011 Nic Wolff.
267              
268             This program is free software; you can redistribute it and/or modify it
269             under the terms of either: the GNU General Public License as published
270             by the Free Software Foundation; or the Artistic License.
271              
272             See http://dev.perl.org/licenses/ for more information.
273              
274              
275             =cut
276              
277             1;