File Coverage

blib/lib/POE/Component/Client/Pastebot.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package POE::Component::Client::Pastebot;
2              
3 1     1   33308 use strict;
  1         3  
  1         305  
4 1     1   8 use warnings;
  1         3  
  1         45  
5 1     1   2088 use POE qw(Component::Client::HTTP);
  0            
  0            
6             use HTTP::Request::Common;
7             use URI;
8             use HTML::TokeParser;
9             use vars qw($VERSION);
10              
11             $VERSION = '1.16';
12              
13             # Stolen from POE::Wheel. This is static data, shared by all
14             my $current_id = 0;
15             my %active_identifiers;
16              
17             sub _allocate_identifier {
18             while (1) {
19             last unless exists $active_identifiers{ ++$current_id };
20             }
21             return $active_identifiers{$current_id} = $current_id;
22             }
23              
24             sub _free_identifier {
25             my $id = shift;
26             delete $active_identifiers{$id};
27             }
28              
29             sub spawn {
30             my $package = shift;
31             my %opts = @_;
32             $opts{lc $_} = delete $opts{$_} for keys %opts;
33             my $options = delete $opts{options};
34             my $self = bless \%opts, $package;
35             $self->{session_id} = POE::Session->create(
36             object_states => [
37             $self => { shutdown => '_shutdown',
38             paste => '_command',
39             fetch => '_command',
40             },
41             $self => [ qw(_start _dispatch _http_request _http_response) ],
42             ],
43             heap => $self,
44             ( ref($options) eq 'HASH' ? ( options => $options ) : () ),
45             )->ID();
46             return $self;
47             }
48              
49             sub session_id {
50             return $_[0]->{session_id};
51             }
52              
53             sub shutdown {
54             my $self = shift;
55             $poe_kernel->post( $self->{session_id}, 'shutdown' );
56             }
57              
58             sub _start {
59             my ($kernel,$self) = @_[KERNEL,OBJECT];
60             $self->{session_id} = $_[SESSION]->ID();
61             if ( $self->{alias} ) {
62             $kernel->alias_set( $self->{alias} );
63             }
64             else {
65             $kernel->refcount_increment( $self->{session_id} => __PACKAGE__ );
66             }
67             $self->{_httpc} = 'httpc-' . $self->{session_id};
68             POE::Component::Client::HTTP->spawn(
69             Alias => $self->{_httpc},
70             FollowRedirects => 2,
71             );
72             undef;
73             }
74              
75             sub _shutdown {
76             my ($kernel,$self) = @_[KERNEL,OBJECT];
77             $kernel->alias_remove( $_ ) for $kernel->alias_list();
78             $kernel->refcount_decrement( $self->{session_id} => __PACKAGE__ ) unless $self->{alias};
79             $self->{_shutdown} = 1;
80             $kernel->post( $self->{_httpc}, 'shutdown' );
81             undef;
82             }
83              
84             sub _dispatch {
85             my ($kernel,$self,$input) = @_[KERNEL,OBJECT,ARG0];
86             my $session = delete $input->{sender};
87             my $event = delete $input->{event};
88             $kernel->post( $session, $event, $input );
89             $kernel->refcount_decrement( $session => __PACKAGE__ );
90             undef;
91             }
92              
93             sub _command {
94             my ($kernel,$self,$state) = @_[KERNEL,OBJECT,STATE];
95             my $sender = $_[SENDER]->ID();
96             return if $self->{_shutdown};
97             my $args;
98             if ( ref( $_[ARG0] ) eq 'HASH' ) {
99             $args = { %{ $_[ARG0] } };
100             } else {
101             $args = { @_[ARG0..$#_] };
102             }
103              
104             $args->{lc $_} = delete $args->{$_} for grep { $_ !~ /^_/ } keys %{ $args };
105              
106             unless ( $args->{event} ) {
107             warn "No 'event' specified for $state";
108             return;
109             }
110              
111             unless ( $args->{url} ) {
112             warn "No 'url' specified for $state";
113             return;
114             }
115              
116             if ( $state eq 'paste' and !$args->{paste} ) {
117             warn "No 'paste' specified for paste";
118             return;
119             }
120              
121             if ( $state eq 'paste' and ref ( $args->{paste} ) eq 'ARRAY' ) {
122             my $paste = delete $args->{paste};
123             $args->{paste} = join "\n", @{ $paste };
124             }
125              
126             $args->{sender} = $sender;
127             $args->{command} = $state;
128             $kernel->refcount_increment( $sender => __PACKAGE__ );
129             $kernel->yield( '_http_request', $args );
130             undef;
131             }
132              
133             sub _http_request {
134             my ($kernel,$self,$req) = @_[KERNEL,OBJECT,ARG0];
135             if ( $req->{command} eq 'paste' ) {
136             my $url =
137             URI->new(
138             $req->{'url'} . ( ( $req->{'url'} !~ m,/$, ) ? '/' : '' ) . 'paste' )
139             ->canonical;
140             unless ( defined $url ) {
141             $req->{error} = "could not determine url from $req->{url}";
142             $kernel->yield( '_dispatch', $req );
143             }
144             else {
145             $req->{'channel'} =~ s/^/#/ if $req->{'channel'} and $req->{'channel'} !~ /^#/;
146             my %postargs = map {
147             ( defined $req->{$_} and $req->{$_} ne '' )
148             ? ( $_ => $req->{$_} )
149             : ()
150             } qw(channel nick summary);
151             $postargs{'paste'} = $req->{paste};
152             my $id = _allocate_identifier();
153             $self->{_requests}->{ $id } = $req;
154             $kernel->post(
155             $self->{_httpc},
156             'request',
157             '_http_response',
158             POST( $url, \%postargs ),
159             "$id",
160             );
161             }
162             return;
163             }
164             if ( $req->{command} eq 'fetch' ) {
165             my $url;
166             my $urltmp = URI->new( $req->{url} . ( ( $req->{url} !~ m,\?tx=on$, ) ? '?tx=on' : '' ) );
167             if ( defined $urltmp and defined $urltmp->scheme and $urltmp->scheme =~ /http/ ) {
168             $url = $urltmp->canonical;
169             my $id = _allocate_identifier();
170             $self->{_requests}->{ $id } = $req;
171             $kernel->post(
172             $self->{_httpc},
173             'request',
174             '_http_response',
175             GET( $url ),
176             "$id",
177             );
178             }
179             else {
180             $req->{error} = 'problem with url provided';
181             $kernel->yield( '_dispatch', $req );
182             }
183             return;
184             }
185             return;
186             }
187              
188             sub _http_response {
189             my ($kernel,$self,$request_packet,$response_packet) = @_[KERNEL,OBJECT,ARG0,ARG1];
190             my $id = $request_packet->[1];
191             my $req = delete $self->{_requests}->{ $id };
192             _free_identifier( $id );
193             my $response = $response_packet->[0];
194             $req->{response} = $response;
195             unless ( $response->is_success ) {
196             if ( $response->is_error ) {
197             $req->{error} = $response->as_string;
198             }
199             else {
200             $req->{error} = 'unknown error';
201             }
202             }
203             else {
204             if ( $req->{command} eq 'paste' and $response->content ) {
205             my $p = HTML::TokeParser->new( \$response->content );
206             $p->get_tag('a');
207             $req->{pastelink} = $p->get_text('/a');
208             }
209             if ( $req->{command} eq 'fetch' and $response->content ) {
210             $req->{content} = $response->content;
211             }
212             }
213             $kernel->yield( '_dispatch', $req );
214             return;
215             }
216              
217             'Paste and cut';
218             __END__