File Coverage

blib/lib/MojoX/Twitter.pm
Criterion Covered Total %
statement 29 65 44.6
branch 0 18 0.0
condition 0 14 0.0
subroutine 10 12 83.3
pod 0 1 0.0
total 39 110 35.4


line stmt bran cond sub pod time code
1             package MojoX::Twitter;
2              
3 1     1   12836 use strict;
  1         2  
  1         23  
4 1     1   3 use warnings;
  1         0  
  1         16  
5 1     1   10 use v5.10;
  1         1  
6 1     1   3 use Carp qw/croak/;
  1         1  
  1         45  
7 1     1   404 use Mojo::Base -base;
  1         6691  
  1         5  
8 1     1   562 use Mojo::UserAgent;
  1         158791  
  1         7  
9 1     1   28 use Mojo::URL;
  1         1  
  1         3  
10 1     1   18 use Digest::SHA 'hmac_sha1';
  1         1  
  1         45  
11 1     1   4 use MIME::Base64 'encode_base64';
  1         1  
  1         35  
12 1     1   453 use URI::Escape 'uri_escape_utf8';
  1         925  
  1         575  
13              
14             our $VERSION = '0.05';
15              
16             has 'ua' => sub {
17             my $ua = Mojo::UserAgent->new;
18             $ua->transactor->name("MojoX-Twitter $VERSION");
19             return $ua;
20             };
21              
22             has 'consumer_key';
23             has 'consumer_secret';
24             has 'access_token';
25             has 'access_token_secret';
26              
27             sub request {
28 0     0 0   my ($self, $method, $command, $params) = @_;
29              
30 0           my ($consumer_key, $consumer_secret, $access_token, $access_token_secret) =
31             ($self->consumer_key, $self->consumer_secret, $self->access_token, $self->access_token_secret);
32              
33 0 0 0       croak 'consumer_key, consumer_secret, access_token and access_token_secret are all required'
      0        
      0        
34             unless $consumer_key and $consumer_secret and $access_token and $access_token_secret;
35              
36 0 0         $command = '/' . $command if $command !~ m{^/};
37 0           my $url = "https://api.twitter.com/1.1" . $command . ".json";
38 0           my %oauth_params = (
39             oauth_consumer_key => $consumer_key,
40             oauth_nonce => __nonce(),
41             oauth_signature_method => 'HMAC-SHA1',
42             oauth_timestamp => time(),
43             oauth_token => $access_token,
44             oauth_version => '1.0',
45             );
46              
47             ## sign
48 0 0         my %params = ( %{$params || {}}, %oauth_params );
  0            
49 0           my $params_str = join('&', map { $_ . '=' . uri_escape_utf8($params{$_}) } sort keys %params);
  0            
50 0           my $base_str = uc($method) . '&' . uri_escape_utf8($url) . '&' . uri_escape_utf8($params_str);
51 0           my $signing_key = uri_escape_utf8($consumer_secret) . '&' . uri_escape_utf8($access_token_secret);
52 0           my $sign = encode_base64(hmac_sha1($base_str, $signing_key), '');
53              
54 0           $oauth_params{oauth_signature} = $sign;
55 0           my $auth_str = join ', ', map { $_ . '="' . uri_escape_utf8($oauth_params{$_}) . '"' } sort keys %oauth_params;
  0            
56              
57 0           my @extra;
58 0 0         if ($method eq 'GET') {
    0          
59 0           my $uri = Mojo::URL->new($url);
60 0           $uri->query($params);
61 0           $url = $uri->to_string();
62             } elsif ($method eq 'POST') {
63 0           @extra = (form => $params);
64             }
65              
66 0           my $tx = $self->ua->build_tx($method => $url => { Authorization => "OAuth $auth_str" } => @extra );
67 0           $tx = $self->ua->start($tx);
68              
69 0           my $remaing = $tx->res->headers->header('X-Rate-Limit-Remaining');
70 0 0 0       if (defined $remaing and $remaing < 1) {
71 0           my $sleep = $tx->res->headers->header('X-Rate-Limit-Reset') - time();
72 0           sleep $sleep; # wait until limit reset
73             }
74              
75 0 0         if (my $res = $tx->success) {
76             # check Rate Limit
77             # print Dumper(\$res); use Data::Dumper;
78              
79 0           return $res->json;
80             } else {
81 0           my $err = $tx->error;
82              
83             # for 429 response: Too Many Requests
84 0 0 0       if ( ($err->{code} || 0) == 429 ) {
85 0           return $self->request($method, $command, $params); # REDO
86             }
87              
88 0 0         croak "$err->{code} response: $err->{message}" if $err->{code};
89 0           croak "Connection error: $err->{message}";
90             }
91             }
92              
93             sub __nonce {
94 0     0     return time ^ $$ ^ int(rand 2**32);
95             }
96              
97             1;
98             __END__