File Coverage

blib/lib/POE/Component/SmokeBox/Uploads/RSS.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package POE::Component::SmokeBox::Uploads::RSS;
2              
3 1     1   32198 use strict;
  1         2  
  1         35  
4 1     1   5 use warnings;
  1         2  
  1         26  
5 1     1   5 use Carp;
  1         5  
  1         87  
6 1     1   896 use POE qw(Component::RSSAggregator Component::Client::HTTP);
  1         68525  
  1         6  
7             use HTTP::Request;
8             use HTML::LinkExtor;
9             use vars qw($VERSION);
10              
11             $VERSION = '1.00';
12              
13             sub spawn {
14             my $package = shift;
15             my %opts = @_;
16             $opts{lc $_} = delete $opts{$_} for keys %opts;
17             croak "$package requires an 'event' argument\n" unless $opts{event};
18             $opts{feed} = 'http://search.cpan.org/uploads.rdf' unless $opts{feed};
19             $opts{name} = 'search-cpan-recent' unless $opts{name};
20             $opts{delay} = 1800 unless $opts{delay};
21             my $options = delete $opts{options};
22             my $self = bless \%opts, $package;
23             $self->{session_id} = POE::Session->create(
24             object_states => [
25             $self => { shutdown => '_shutdown', },
26             $self => [ qw(_start _dispatch _feed_url _handle_feed _real_shutdown) ],
27             ],
28             heap => $self,
29             ( ref($options) eq 'HASH' ? ( options => $options ) : () ),
30             )->ID();
31             return $self;
32             }
33              
34             sub session_id {
35             return $_[0]->{session_id};
36             }
37              
38             sub shutdown {
39             my $self = shift;
40             $poe_kernel->post( $self->{session_id}, 'shutdown' );
41             return;
42             }
43              
44             sub _shutdown {
45             my ($kernel,$self) = @_[KERNEL,OBJECT];
46             $self->{_shutdown} = 1;
47             return if $self->{_http_requests};
48             $kernel->yield( '_real_shutdown' );
49             return;
50             }
51              
52             sub _real_shutdown {
53             my ($kernel,$self) = @_[KERNEL,OBJECT];
54             $kernel->alias_remove( $_ ) for $kernel->alias_list();
55             $kernel->refcount_decrement( $self->{session_id}, __PACKAGE__ ) unless $self->{alias};
56             $kernel->refcount_decrement( $self->{sender_id}, __PACKAGE__ );
57             $kernel->post( $self->{http_id}, 'shutdown' ) unless $self->{http_alias};
58             $kernel->post( $self->{rssagg}, 'shutdown' );
59             return;
60             }
61              
62             sub _start {
63             my ($kernel,$session,$sender,$self) = @_[KERNEL,SESSION,SENDER,OBJECT];
64             $self->{session_id} = $session->ID();
65             if ( $kernel == $sender and !$self->{session} ) {
66             croak "Not called from another POE session and 'session' wasn't set\n";
67             }
68             my $sender_id;
69             if ( $self->{session} ) {
70             if ( my $ref = $kernel->alias_resolve( $self->{session} ) ) {
71             $sender_id = $ref->ID();
72             }
73             else {
74             croak "Could not resolve 'session' to a valid POE session\n";
75             }
76             }
77             else {
78             $sender_id = $sender->ID();
79             }
80             $kernel->refcount_increment( $sender_id, __PACKAGE__ );
81             $self->{sender_id} = $sender_id;
82             if ( $self->{http_alias} ) {
83             my $http_ref = $kernel->alias_resolve( $self->{http_alias} );
84             $self->{http_id} = $http_ref->ID() if $http_ref;
85             }
86             unless ( $self->{http_id} ) {
87             $self->{http_id} = 'smokeboxrss' . $$ . $self->{session_id};
88             POE::Component::Client::HTTP->spawn(
89             Alias => $self->{http_id},
90             FollowRedirects => 2,
91             Timeout => 60,
92             Agent => 'Mozilla/5.0 (X11; U; Linux i686; en-US; '
93             . 'rv:1.1) Gecko/20020913 Debian/1.1-1',
94             );
95             }
96             $self->{rssagg} = 'rssagg' . $self->{session_id};
97             POE::Component::RSSAggregator->new(
98             alias => $self->{rssagg},
99             callback => $session->postback('_handle_feed'),
100             http_alias => $self->{http_id},
101             tmpdir => $self->{tmpdir} || '.', # optional caching
102             );
103             my $feed = {
104             url => $self->{feed},
105             name => $self->{name},
106             delay => $self->{delay},
107             };
108             $kernel->post( $self->{rssagg}, 'add_feed', $feed );
109             return;
110             }
111              
112             sub _handle_feed {
113             my ($kernel,$self,$feed) = (@_[KERNEL,OBJECT], $_[ARG1]->[0]);
114             for my $headline ( reverse $feed->late_breaking_news ) {
115             $kernel->post(
116             $self->{http_id},
117             'request',
118             '_feed_url',
119             HTTP::Request->new( GET => $headline->url ),
120             $headline->headline,
121             );
122             $self->{_http_requests}++;
123             }
124             return;
125             }
126              
127             sub _feed_url {
128             my ($kernel,$self,$request_packet,$response_packet) = @_[KERNEL,OBJECT,ARG0,ARG1];
129             my $http_resp = $response_packet->[0];
130             $self->{_http_requests}--;
131             return unless $http_resp and $http_resp->code() == 200;
132             my $tag = $request_packet->[1];
133             my $p = HTML::LinkExtor->new();
134             $p->parse( $http_resp->content() );
135             foreach my $link ( $p->links() ) {
136             if ( $link->[0] eq 'a' and $link->[2] =~ /\Q$tag\E/ ) {
137             ( my $module = $link->[2] ) =~ s#/CPAN/authors/id/##;
138             $kernel->call( $self->{session_id}, '_dispatch', $module );
139             last;
140             }
141             }
142             $kernel->yield( '_real_shutdown' ) if $self->{_shutdown} and $self->{_http_requests} == 0;
143             return;
144             }
145              
146             sub _dispatch {
147             my ($kernel,$self,$module) = @_[KERNEL,OBJECT,ARG0];
148             $kernel->post( $self->{sender_id}, $self->{event}, $module );
149             return;
150             }
151              
152             "This town ain't big enough for the both of us";
153              
154             __END__