File Coverage

blib/lib/POE/Component/CPANIDX.pm
Criterion Covered Total %
statement 97 106 91.5
branch 15 28 53.5
condition 3 9 33.3
subroutine 18 19 94.7
pod 4 4 100.0
total 137 166 82.5


line stmt bran cond sub pod time code
1             package POE::Component::CPANIDX;
2             $POE::Component::CPANIDX::VERSION = '0.12';
3             #ABSTRACT: A POE mechanism for querying the CPANIDX
4              
5 2     2   178542 use strict;
  2         3  
  2         46  
6 2     2   8 use warnings;
  2         2  
  2         54  
7 2     2   7 use Carp;
  2         3  
  2         88  
8 2     2   6 use POE qw(Component::Client::HTTP);
  2         3  
  2         19  
9 2     2   150123 use YAML::Tiny;
  2         7558  
  2         109  
10 2     2   875 use HTTP::Request::Common;
  2         5002  
  2         106  
11 2     2   10 use File::Spec::Unix;
  2         2  
  2         1650  
12              
13             my $cmds = {
14             mod => 1,
15             dist => 1,
16             auth => 1,
17             corelist => 1,
18             dists => 1,
19             timestamp => 0,
20             topten => 0,
21             mirrors => 0,
22             };
23              
24             # Stolen from POE::Wheel. This is static data, shared by all
25             my $current_id = 0;
26             my %active_identifiers;
27              
28             sub _allocate_identifier {
29 2     2   2 while (1) {
30 2 50       9 last unless exists $active_identifiers{ ++$current_id };
31             }
32 2         6 return $active_identifiers{$current_id} = $current_id;
33             }
34              
35             sub _free_identifier {
36 2     2   6 my $id = shift;
37 2         5 delete $active_identifiers{$id};
38             }
39              
40             sub spawn {
41 2     2 1 22 my $package = shift;
42 2         4 my %opts = @_;
43 2         5 $opts{lc $_} = delete $opts{$_} for keys %opts;
44 2         4 my $options = delete $opts{options};
45 2         5 my $self = bless \%opts, $package;
46 2 50       27 $self->{session_id} = POE::Session->create(
47             object_states => [
48             $self => { shutdown => '_shutdown',
49             query_idx => '_query_idx',
50             },
51             $self => [ qw(_start _query_idx _dispatch _http_request _http_response) ],
52             ],
53             heap => $self,
54             ( ref($options) eq 'HASH' ? ( options => $options ) : () ),
55             )->ID();
56 2         139 return $self;
57             }
58              
59             sub session_id {
60 0     0 1 0 return $_[0]->{session_id};
61             }
62              
63             sub shutdown {
64 2     2 1 2696 my $self = shift;
65 2         8 $poe_kernel->call( $self->{session_id}, 'shutdown' );
66             }
67              
68             sub _start {
69 2     2   462 my ($kernel,$self) = @_[KERNEL,OBJECT];
70 2         6 $self->{session_id} = $_[SESSION]->ID();
71 2 50       9 if ( $self->{alias} ) {
72 0         0 $kernel->alias_set( $self->{alias} );
73             }
74             else {
75 2         9 $kernel->refcount_increment( $self->{session_id} => __PACKAGE__ );
76             }
77 2         55 $self->{_httpc} = 'httpc-' . $self->{session_id};
78             POE::Component::Client::HTTP->spawn(
79             Alias => $self->{_httpc},
80 2         20 FollowRedirects => 2,
81             );
82 2         2138 return;
83             }
84              
85             sub _shutdown {
86 2     2   76 my ($kernel,$self) = @_[KERNEL,OBJECT];
87 2         7 $kernel->alias_remove( $_ ) for $kernel->alias_list();
88 2 50       54 $kernel->refcount_decrement( $self->{session_id} => __PACKAGE__ ) unless $self->{alias};
89 2         42 $self->{_shutdown} = 1;
90 2         6 $kernel->post( $self->{_httpc}, 'shutdown' );
91 2         119 undef;
92             }
93              
94             sub query_idx {
95 2     2 1 1746 my $self = shift;
96 2         10 $poe_kernel->post( $self->{session_id}, '_query_idx', @_ );
97             }
98              
99             sub _query_idx {
100 2     2   548 my ($kernel,$self,$state) = @_[KERNEL,OBJECT,STATE];
101 2         5 my $sender = $_[SENDER]->ID();
102 2 50       9 return if $self->{_shutdown};
103 2         4 my $args;
104 2 50       8 if ( ref( $_[ARG0] ) eq 'HASH' ) {
105 0         0 $args = { %{ $_[ARG0] } };
  0         0  
106             } else {
107 2         10 $args = { @_[ARG0..$#_] };
108             }
109              
110 2         3 $args->{lc $_} = delete $args->{$_} for grep { $_ !~ /^_/ } keys %{ $args };
  8         23  
  2         5  
111              
112 2 50       7 unless ( $args->{event} ) {
113 0         0 warn "No 'event' specified for $state";
114 0         0 return;
115             }
116              
117             croak
118             "You must provide a valid 'url' of a CPANIDX site"
119 2 50 33     23 unless $args->{url} and URI->new($args->{url}) and URI->new($args->{url})->scheme eq 'http';
      33        
120              
121 2 50       11688 $args->{cmd} = 'timestamp' unless $args->{cmd};
122 2         5 $args->{cmd} = lc $args->{cmd};
123              
124 2         6 my $arg = $cmds->{ $args->{cmd} };
125              
126 2 50       5 croak
127             "'cmd' that was specified is unknown"
128             unless defined $arg;
129              
130             croak
131             "'cmd' requires that you specify a 'search' term"
132 2 50 33     11 if $arg and !$args->{search};
133              
134 2         28 $args->{sender} = $sender;
135 2         7 $kernel->refcount_increment( $sender => __PACKAGE__ );
136 2         47 $kernel->yield( '_http_request', $args );
137              
138 2         96 return;
139             }
140              
141             sub _http_request {
142 2     2   213 my ($kernel,$self,$req) = @_[KERNEL,OBJECT,ARG0];
143 2         8 my $url = URI->new( $req->{url} );
144              
145 2 50       91 $url->path( File::Spec::Unix->catfile( $url->path, 'yaml', $req->{cmd}, ( $req->{search} ? $req->{search} : () ) ) );
146              
147 2         114 my $id = _allocate_identifier();
148              
149             $kernel->post(
150             $self->{_httpc},
151 2         15 'request',
152             '_http_response',
153             GET( $url->as_string ),
154             "$id",
155             );
156              
157 2         367 $self->{_requests}->{ $id } = $req;
158 2         6 return;
159             }
160              
161             sub _http_response {
162 2     2   79451 my ($kernel,$self,$request_packet,$response_packet) = @_[KERNEL,OBJECT,ARG0,ARG1];
163 2         6 my $id = $request_packet->[1];
164 2         6 my $req = delete $self->{_requests}->{ $id };
165 2         8 _free_identifier( $id );
166 2         3 my $resp = $response_packet->[0];
167 2 100       11 if ( $resp->is_success ) {
168 1         8 my $data;
169 1         1 eval { $data = YAML::Tiny::Load( $resp->content ); };
  1         5  
170 1 50       453 unless ( $data ) {
171 0         0 $req->{error} = 'No valid YAML data was found';
172 0         0 $kernel->yield( '_dispatch', $req );
173 0         0 return;
174             }
175 1         3 $req->{data} = $data;
176             }
177             else {
178 1         15 $req->{error} = $resp->as_string;
179             }
180              
181 2         106 $kernel->yield( '_dispatch', $req );
182 2         91 return;
183             }
184              
185             sub _dispatch {
186 2     2   578 my ($kernel,$self,$input) = @_[KERNEL,OBJECT,ARG0];
187 2         5 my $session = delete $input->{sender};
188 2         3 my $event = delete $input->{event};
189 2         9 $kernel->post( $session, $event, $input );
190 2         115 $kernel->refcount_decrement( $session => __PACKAGE__ );
191 2         42 return;
192             }
193              
194             qq[CAPTCH!];
195              
196             __END__