Show
Ignore:
Timestamp:
03/01/08 19:04:48 (5 years ago)
Author:
woremacx
Message:

lang/perl/POE-Component-Client-Nowa: rewriting by PoCo::HTTP

Location:
lang/perl/POE-Component-Client-Nowa/branches/poco-http
Files:
1 modified
1 copied

Legend:

Unmodified
Added
Removed
  • lang/perl/POE-Component-Client-Nowa/branches/poco-http/lib/POE/Component/Client/Nowa.pm

    r6549 r7328  
    11package POE::Component::Client::Nowa; 
     2 
    23use strict; 
    34use warnings; 
    4 use base qw/Class::Accessor::Fast/; 
    5  
    6 __PACKAGE__->mk_accessors(qw/nowa/); 
    7  
    8 use POE; 
    9 use WebService::Nowa; 
     5our $VERSION = '0.01'; 
     6 
     7use HTTP::Request::Common; 
     8use HTTP::Date (); 
     9use JSON::Any; 
     10use POE::Component::SSLify; 
     11use POE qw( Component::Client::HTTP ); 
     12use URI; 
     13use WWW::Mechanize; 
     14use Web::Scraper; 
     15use Data::Dumper; 
     16use Scalar::Util qw(blessed); 
     17use JSON::Syck (); 
    1018 
    1119sub spawn { 
     
    1321 
    1422    my $self = bless {}, $class; 
     23    %args = ( 
     24        NOWA_HOME     => 'http://my.nowa.jp/home/', 
     25        NOWA_API_HOME => 'https://api.nowa.jp/', 
     26 
     27        alias         => 'nowa', 
     28 
     29        %args, 
     30    ); 
     31    $args{apis} = { 
     32        recent => { 
     33            json   => '/status_message/friends_timeline.json', 
     34            notify => 'recent_success', 
     35        }, 
     36    }; 
     37    $args{scrapers} = { 
     38        scrape_channel => $args{NOWA_HOME}, 
     39        scrape_channel_recent => 'http://my.nowa.jp/channel/recent', 
     40    }; 
     41 
    1542 
    1643    $self->{session_id} = POE::Session->create( 
    1744        object_states => [ 
    1845            $self => { 
    19                 map { $_ => "poe_$_" } qw/_start _stop register unregister _unregister notify attach update recent channels channel_recent/ 
     46                map { $_ => "poe_$_" } qw/_start _stop register unregister _unregister notify 
     47                                          _api _httpget _api_response _httpget_response 
     48                                          channels _scrape_channels 
     49                                          recent 
     50                                          channel_recent _scrape_channel_recent 
     51                                         / 
    2052            }, 
    2153        ], 
     
    2456    )->ID; 
    2557 
     58    POE::Component::Client::HTTP->spawn( 
     59        Agent => __PACKAGE__ . '/' . $VERSION, 
     60        Alias => $self->ua_alias, 
     61        CookieJar => $self->_cookie_jar($args{nowa_id}, $args{password}), 
     62    ); 
     63 
    2664    $self; 
     65} 
     66 
     67sub _cookie_jar { 
     68    my ($self, $id, $pass) = @_; 
     69 
     70    my $mech = WWW::Mechanize->new; 
     71    $mech->agent_alias('Windows IE 6'); 
     72    $mech->get("http://my.nowa.jp/home/"); 
     73    my $uri = $mech->uri; 
     74    $mech->submit_form( 
     75        form_number => 1, 
     76        fields      => +{ 
     77            nowa_id    => $id, 
     78            password   => $pass, 
     79            auto_login => 1, 
     80        }, 
     81    ); 
     82    die("login failed.") if $mech->uri eq $uri; 
     83 
     84    return $mech->cookie_jar; 
     85} 
     86 
     87sub ua_alias { 
     88    my $self = shift; 
     89    return "poco_nowa_ua_" . $self->session_id; 
    2790} 
    2891 
     
    3699sub poe_notify { 
    37100    my($kernel, $heap, $name, $args) = @_[KERNEL, HEAP, ARG0, ARG1]; 
     101warn "notify: $name"; 
    38102    $kernel->post($_ => "nowa.$name" => $args) for keys %{$heap->{listeners}}; 
    39103} 
     
    41105sub poe__start { 
    42106    my ($self, $kernel, $heap, $args) = @_[OBJECT, KERNEL, HEAP, ARG0]; 
    43  
    44     $kernel->alias_set('nowa'); 
    45  
    46     $heap->{nowa} = WebService::Nowa->new({ 
    47             nowa_id  => $heap->{args}->{nowa_id}, 
    48             password => $heap->{args}->{password}, 
    49             api_pass => $heap->{args}->{api_pass}, 
    50         }); 
    51  
    52     $kernel->yield('attach'); 
     107    $kernel->alias_set($args->{alias}) if $args->{alias}; 
     108 
     109    $kernel->yield('channel_recent'); 
    53110} 
    54111 
     
    62119} 
    63120 
    64  
    65121sub poe_unregister { 
    66122    my($kernel, $heap, $sender) = @_[KERNEL, HEAP, SENDER]; 
     
    74130} 
    75131 
    76  
    77 sub poe_attach { 
    78     my ($kernel, $heap, $args) = @_[KERNEL, HEAP, ARG0]; 
    79  
    80 #    $kernel->delay( attach => 1 ); 
    81 } 
    82  
    83 sub poe_update { 
    84     my ($self, $kernel, $heap, $message) = @_[OBJECT, KERNEL, HEAP, ARG0]; 
    85     $heap->{nowa}->update_nanishiteru($message); 
    86 } 
     132sub _scrape { 
     133    my ($self, $param) = @_; 
     134 
     135    my $url = $param->{uri}; 
     136    my $stuff = $url; 
     137    $stuff = $url->as_string if (blessed($url) && $url->isa('URI')); 
     138 
     139    my $html = $param->{content}; 
     140    $html = Encode::decode('utf-8', $param->{content}) unless utf8::is_utf8($param->{content}); 
     141 
     142    my $base = ($html =~ /<base\s+href="([^"]+?)"/)[0] || $stuff; 
     143 
     144    $param->{scraper}->scrape($html, URI->new($base)); 
     145} 
     146 
     147sub poe__api { 
     148    my ($self, $kernel, $heap, $method, $content) = @_[OBJECT, KERNEL, HEAP, ARG0, ARG1]; 
     149 
     150    my $uri = URI->new_abs($method, $heap->{args}->{NOWA_API_HOME}); 
     151    my $req; 
     152    if (defined($content)) { 
     153        $req = HTTP::Request::Common::POST( 
     154            $uri, 
     155            $content, 
     156        ); 
     157    } else { 
     158        $req = HTTP::Request::Common::GET( 
     159            $uri, 
     160        ); 
     161    } 
     162    $req->authorization_basic($heap->{args}->{nowa_id}, $heap->{args}->{api_pass}); 
     163 
     164    $kernel->post($self->ua_alias => request => '_api_response', $req); 
     165} 
     166 
     167sub poe__httpget { 
     168    my ($self, $kernel, $heap, $uri) = @_[OBJECT, KERNEL, HEAP, ARG0]; 
     169 
     170    my $req = HTTP::Request::Common::GET( 
     171        $uri, 
     172    ); 
     173    $kernel->post($self->ua_alias => request => '_httpget_response', $req); 
     174} 
     175 
     176sub poe__api_response { 
     177    my($kernel, $heap, $session, $request_packet, $response_packet) = @_[KERNEL, HEAP, SESSION, ARG0, ARG1]; 
     178 
     179    my $request  = $request_packet->[0]; 
     180    my $response = $response_packet->[0]; 
     181 
     182    unless ($response->is_success) { 
     183        $kernel->yield(notify => 'response_error', $response); 
     184        return; 
     185    } 
     186 
     187    my $uri = URI->new($request->uri)->path; 
     188    my $content = $response->content; 
     189    $content = Encode::decode('utf-8', $content) unless utf8::is_utf8($content); 
     190    local $JSON::Syck::ImplicitUnicode = 1; 
     191    my $res = JSON::Syck::Load($content); 
     192 
     193    if (ref($res) eq 'HASH' and $res->{result} eq 'fail') { 
     194        return; 
     195    } 
     196 
     197    my %apis = %{ $heap->{args}->{apis} }; 
     198    while (my ($apiname, $api) = each(%apis)) { 
     199        if ($uri eq $api->{json}) { 
     200            $kernel->yield(notify => $api->{notify}, $res); 
     201            return; 
     202        } 
     203    } 
     204    warn "unknown " . $uri; 
     205} 
     206 
     207sub poe__httpget_response { 
     208    my($kernel, $heap, $session, $request_packet, $response_packet) = @_[KERNEL, HEAP, SESSION, ARG0, ARG1]; 
     209 
     210    my $request  = $request_packet->[0]; 
     211    my $response = $response_packet->[0]; 
     212 
     213    unless ($response->is_success) { 
     214        $kernel->yield(notify => 'response_error', $response); 
     215        return; 
     216    } 
     217 
     218    my %scrapers = %{ $heap->{args}->{scrapers} }; 
     219    while (my ($scraper, $uri) = each(%scrapers)) { 
     220        if ($request->uri eq $uri) { 
     221            $kernel->yield("_$scraper" => { uri => $uri, content => $response->content }); 
     222            return; 
     223        } 
     224    } 
     225    warn "unknown " . $request->uri; 
     226} 
     227 
     228 
     229sub poe_channels { 
     230    my ($self, $kernel, $heap) = @_[OBJECT, KERNEL, HEAP]; 
     231 
     232    $self->yield(_httpget => $heap->{args}->{NOWA_HOME}); 
     233} 
     234 
     235sub poe__scrape_channels { 
     236    my ($self, $kernel, $heap, $param) = @_[OBJECT, KERNEL, HEAP, ARG0]; 
     237 
     238    $param->{scraper} = scraper { 
     239        process 'ul.home-chlist > li', 'channels[]' => scraper { 
     240            process 'a', 
     241                name => 'TEXT', 
     242                link => '@href'; 
     243        }; 
     244    }; 
     245 
     246    my $res = $self->_scrape($param); 
     247    my $data; 
     248    for my $chan (@{ $res->{channels} }) { 
     249        my $id = '#' . ($chan->{link} =~ m!^http://nowa.jp/ch/(.*?)/!)[0]; 
     250        my $name = $chan->{name}; 
     251        $name =~ s/\(\d+\)$//; 
     252        $data->{$id} = $name; 
     253    } 
     254 
     255    $kernel->yield(notify => 'channels_success', $data); 
     256} 
     257 
    87258 
    88259sub poe_recent { 
    89     my ($self, $kernel, $heap, $target, $message) = @_[OBJECT, KERNEL, HEAP]; 
    90  
    91     my $data = $heap->{nowa}->recent; 
    92     $kernel->yield(notify => 'recent_success', $data); 
    93 } 
    94  
    95 sub poe_channels { 
    96     my ($self, $kernel, $heap, $target, $message) = @_[OBJECT, KERNEL, HEAP]; 
    97  
    98     my $data = $heap->{nowa}->channels; 
    99     $kernel->yield(notify => 'channels_success', $data); 
    100 } 
     260    my ($self, $kernel, $heap) = @_[OBJECT, KERNEL, HEAP]; 
     261 
     262    $self->yield(_api => $heap->{args}->{apis}->{recent}->{json}); 
     263} 
     264 
    101265 
    102266sub poe_channel_recent { 
    103     my ($self, $kernel, $heap, $target, $message) = @_[OBJECT, KERNEL, HEAP]; 
    104  
    105     my $data = $heap->{nowa}->channel_recent; 
    106     $kernel->yield(notify => 'channel_recent_success', $data); 
     267    my ($self, $kernel, $heap) = @_[OBJECT, KERNEL, HEAP]; 
     268 
     269    $self->yield(_httpget => $heap->{args}->{scrapers}->{scrape_channel_recent}); 
     270} 
     271 
     272sub poe__scrape_channel_recent { 
     273    my ($self, $kernel, $heap, $param) = @_[OBJECT, KERNEL, HEAP, ARG0]; 
     274 
     275    $param->{scraper} = scraper { 
     276        process 'ul#article-list > li', 'msgs[]' => scraper { 
     277            process_first 'a.blue-cms', 
     278                user => 'TEXT', 
     279                userlink => '@href'; 
     280            process 'span.body', 
     281                body => 'TEXT'; 
     282            process 'span.body > a', 
     283                channel => 'TEXT', 
     284                channellink => '@href'; 
     285            process 'span.time > a', 
     286                permalink => '@href'; 
     287        }; 
     288    }; 
     289 
     290    my $res = $self->_scrape($param); 
     291    my @data; 
     292    for my $msg (@{ $res->{msgs} }) { 
     293        next unless $msg->{permalink}; 
     294 
     295        my $user = ($msg->{userlink} =~ m!^http://([^\.]+)\.nowa\.jp/!)[0]; 
     296        my $body = $msg->{body}; 
     297        $body =~ s/\s+#\w+$//; 
     298 
     299        push(@data, +{ 
     300            body => $body, 
     301            user => $user, 
     302            permalink => $msg->{permalink}->as_string, 
     303            channel => $msg->{channel}, 
     304        }); 
     305    } 
     306 
     307    $kernel->yield(notify => 'channel_recent_success', \@data); 
    107308} 
    108309