Ignore:
Timestamp:
Sep 20, 2011, 11:15:32 PM (13 years ago)
Author:
Edward Z. Yang <ezyang@mit.edu>
Branches:
master, release-1.10, release-1.9
Children:
b7fa912
Parents:
2a42248
git-author:
Edward Z. Yang <ezyang@mit.edu> (07/12/11 09:17:04)
git-committer:
Edward Z. Yang <ezyang@mit.edu> (09/20/11 23:15:32)
Message:
Convert to async (both Facebook::Graph and us.)

Work items:
    - Documentation is all out of date
    - Think more carefully about error handling
      (right now it's delayed into the response object)
    - Really bad HTTP POST hack in Publish.pm.

Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
Location:
perl/modules/Facebook/lib
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • perl/modules/Facebook/lib/BarnOwl/Module/Facebook/Handle.pm

    rd9c6631 r7777ac2  
    165165sub check_result {
    166166    my $self = shift;
    167     if (kiss 400) {
    168         # Ugh, no easy way of accessing the JSON error type
    169         # which is OAuthException.
     167    if (kiss "OAuthException") {
    170168        $self->{logged_in} = 0;
    171169        $self->facebook_do_auth;
     
    185183    return unless $self->{logged_in};
    186184
    187     my $friends = eval { $self->{facebook}->fetch('me/friends'); };
    188     return unless $self->check_result;
    189 
    190     $self->{friends} = {};
    191 
    192     for my $friend (@{$friends->{data}}) {
    193         if (defined $self->{friends}{$friend->{name}}) {
    194             # XXX We should try a little harder here, rather than just
    195             # tacking on a number.  Ideally, we should be able to
    196             # calculate some extra piece of information that the user
    197             # needs to disambiguate between the two users.  An old
    198             # version of Facebook used to disambiguate with your primary
    199             # network (so you might have Edward Yang (MIT) and Edward
    200             # Yang (Cambridge), the idea being that users in the same
    201             # network would probably have already disambiguated
    202             # themselves with middle names or nicknames.  We no longer
    203             # get network information, since Facebook axed that
    204             # information, but the Education/Work fields may still be
    205             # a reasonable approximation (but which one do you pick?!
    206             # The most recent one.)  Since getting this information
    207             # involves extra queries, there are also caching and
    208             # efficiency concerns (though hopefully you don't have too
    209             # many friends with the same name).  Furthermore, accessing
    210             # this information requires a pretty hefty extra set of
    211             # permissions requests, which we don't currently ask for.
    212             #   It may just be better to let users specify custom
    213             # aliases for Facebook users, which are added into this
    214             # hash.  See also username support.
    215             warn "Duplicate friend name " . $friend->{name};
    216             my $name = $friend->{name};
    217             my $i = 2;
    218             while (defined $self->{friends}{$friend->{name} . ' ' . $i}) { $i++; }
    219             $self->{friends}{$friend->{name} . ' ' . $i} = $friend->{id};
    220         } else {
    221             $self->{friends}{$friend->{name}} = $friend->{id};
     185    $self->{facebook}->query->find('me/friends')->request(sub {
     186        my $response = shift;
     187        my $friends = eval { $response->as_hashref };
     188        return unless $self->check_result;
     189
     190        $self->{friends} = {};
     191
     192        for my $friend (@{$friends->{data}}) {
     193            if (defined $self->{friends}{$friend->{name}}) {
     194                # XXX We should try a little harder here, rather than just
     195                # tacking on a number.  Ideally, we should be able to
     196                # calculate some extra piece of information that the user
     197                # needs to disambiguate between the two users.  An old
     198                # version of Facebook used to disambiguate with your primary
     199                # network (so you might have Edward Yang (MIT) and Edward
     200                # Yang (Cambridge), the idea being that users in the same
     201                # network would probably have already disambiguated
     202                # themselves with middle names or nicknames.  We no longer
     203                # get network information, since Facebook axed that
     204                # information, but the Education/Work fields may still be
     205                # a reasonable approximation (but which one do you pick?!
     206                # The most recent one.)  Since getting this information
     207                # involves extra queries, there are also caching and
     208                # efficiency concerns (though hopefully you don't have too
     209                # many friends with the same name).  Furthermore, accessing
     210                # this information requires a pretty hefty extra set of
     211                # permissions requests, which we don't currently ask for.
     212                #   It may just be better to let users specify custom
     213                # aliases for Facebook users, which are added into this
     214                # hash.  See also username support.
     215                warn "Duplicate friend name " . $friend->{name};
     216                my $name = $friend->{name};
     217                my $i = 2;
     218                while (defined $self->{friends}{$friend->{name} . ' ' . $i}) { $i++; }
     219                $self->{friends}{$friend->{name} . ' ' . $i} = $friend->{id};
     220            } else {
     221                $self->{friends}{$friend->{name}} = $friend->{id};
     222            }
    222223        }
    223     }
    224 
    225     # XXX We should also have support for usernames, and not just real
    226     # names. However, since this data is not returned by the friends
    227     # query, it would require a rather expensive set of queries. We
    228     # might try to preserve old data, but all-in-all it's a bit
    229     # complicated.  One possible way of fixing this is to construct a
    230     # custom FQL query that joins the friends table and the users table.
     224
     225        # XXX We should also have support for usernames, and not just real
     226        # names. However, since this data is not returned by the friends
     227        # query, it would require a rather expensive set of queries. We
     228        # might try to preserve old data, but all-in-all it's a bit
     229        # complicated.  One possible way of fixing this is to construct a
     230        # custom FQL query that joins the friends table and the users table.
     231    });
    231232}
    232233
     
    244245    $self->{topics} = {};
    245246
    246     my $updates = eval {
    247         $self->{facebook}
    248              ->query
    249              ->from("my_news")
    250              # Not using this, because we want to pick up comment
    251              # updates. We need to manually de-duplicate, though.
    252              # ->where_since("@" . $self->{last_poll})
    253              # Facebook doesn't actually give us that many results.
    254              # But it can't hurt to ask!
    255              ->limit_results(200)
    256              ->request
    257              ->as_hashref
    258     };
    259     return unless $self->check_result;
    260 
    261     my $new_last_poll = $self->{last_poll};
    262     for my $post (reverse @{$updates->{data}}) {
    263         # No app invites, thanks! (XXX make configurable)
    264         if ($post->{type} eq 'link' && $post->{application}) {
    265             next;
    266         }
    267 
    268         # XXX Filtering out interest groups for now
    269         # A more reasonable strategy may be to show their
    270         # posts, but not the comments.
    271         if (defined $post->{from}{category}) {
    272             next;
    273         }
    274 
    275         # There can be multiple recipients! Strange! Pick the first one.
    276         my $name    = $post->{to}{data}[0]{name} || $post->{from}{name};
    277         my $name_id = $post->{to}{data}[0]{id} || $post->{from}{id};
    278         my $post_id  = $post->{id};
    279 
    280         my $topic;
    281         if (defined $old_topics->{$post_id}) {
    282             $topic = $old_topics->{$post_id};
    283             $self->{topics}->{$post_id} = $topic;
    284         } else {
    285             my @keywords = keywords($post->{name} || $post->{message});
    286             $topic = $keywords[0] || 'personal';
    287             $topic =~ s/ /-/g;
    288             $self->{topics}->{$post_id} = $topic;
    289         }
    290 
    291         # Only handle post if it's new
    292         my $created_time = str2time($post->{created_time});
    293         if ($created_time >= $self->{last_poll}) {
    294             # XXX indexing is fragile
    295             my $msg = BarnOwl::Message->new(
    296                 type      => 'Facebook',
    297                 sender    => $post->{from}{name},
    298                 sender_id => $post->{from}{id},
    299                 name      => $name,
    300                 name_id   => $name_id,
    301                 direction => 'in',
    302                 body      => $self->format_body($post),
    303                 post_id   => $post_id,
    304                 topic     => $topic,
    305                 time      => asctime(localtime $created_time),
    306                 # XXX The intent is to get the 'Comment' link, which also
    307                 # serves as a canonical link to the post.  The {name}
    308                 # field should equal 'Comment'.
    309                 permalink => $post->{actions}[0]{link},
    310                );
    311             BarnOwl::queue_message($msg);
    312         }
    313 
    314         # This will interleave times (they'll all be organized by parent
    315         # post), but since we don't expect too many updates between
    316         # polls this is pretty acceptable.
    317         my $updated_time = str2time($post->{updated_time});
    318         if ($updated_time >= $self->{last_poll} && defined $post->{comments}{data}) {
    319             for my $comment (@{$post->{comments}{data}}) {
    320                 my $comment_time = str2time($comment->{created_time});
    321                 if ($comment_time < $self->{last_poll}) {
    322                     next;
    323                 }
     247    $self->{facebook}
     248         ->query
     249         ->from("my_news")
     250         # Not using this, because we want to pick up comment
     251         # updates. We need to manually de-duplicate, though.
     252         # ->where_since("@" . $self->{last_poll})
     253         # Facebook doesn't actually give us that many results.
     254         # But it can't hurt to ask!
     255         ->limit_results(200)
     256         ->request(sub {
     257
     258        my $updates = eval { shift->as_hashref };
     259        return unless $self->check_result;
     260
     261        my $new_last_poll = $self->{last_poll};
     262        for my $post (reverse @{$updates->{data}}) {
     263            # No app invites, thanks! (XXX make configurable)
     264            if ($post->{type} eq 'link' && $post->{application}) {
     265                next;
     266            }
     267
     268            # XXX Filtering out interest groups for now
     269            # A more reasonable strategy may be to show their
     270            # posts, but not the comments.
     271            if (defined $post->{from}{category}) {
     272                next;
     273            }
     274
     275            # There can be multiple recipients! Strange! Pick the first one.
     276            my $name    = $post->{to}{data}[0]{name} || $post->{from}{name};
     277            my $name_id = $post->{to}{data}[0]{id} || $post->{from}{id};
     278            my $post_id  = $post->{id};
     279
     280            my $topic;
     281            if (defined $old_topics->{$post_id}) {
     282                $topic = $old_topics->{$post_id};
     283                $self->{topics}->{$post_id} = $topic;
     284            } else {
     285                my @keywords = keywords($post->{name} || $post->{message});
     286                $topic = $keywords[0] || 'personal';
     287                $topic =~ s/ /-/g;
     288                $self->{topics}->{$post_id} = $topic;
     289            }
     290
     291            # Only handle post if it's new
     292            my $created_time = str2time($post->{created_time});
     293            if ($created_time >= $self->{last_poll}) {
     294                # XXX indexing is fragile
    324295                my $msg = BarnOwl::Message->new(
    325296                    type      => 'Facebook',
    326                     sender    => $comment->{from}{name},
    327                     sender_id => $comment->{from}{id},
     297                    sender    => $post->{from}{name},
     298                    sender_id => $post->{from}{id},
    328299                    name      => $name,
    329300                    name_id   => $name_id,
    330301                    direction => 'in',
    331                     body      => $comment->{message},
     302                    body      => $self->format_body($post),
    332303                    post_id   => $post_id,
    333304                    topic     => $topic,
    334                     time      => asctime(localtime $comment_time),
     305                    time      => asctime(localtime $created_time),
     306                    # XXX The intent is to get the 'Comment' link, which also
     307                    # serves as a canonical link to the post.  The {name}
     308                    # field should equal 'Comment'.
     309                    permalink => $post->{actions}[0]{link},
    335310                   );
    336311                BarnOwl::queue_message($msg);
    337312            }
     313
     314            # This will interleave times (they'll all be organized by parent
     315            # post), but since we don't expect too many updates between
     316            # polls this is pretty acceptable.
     317            my $updated_time = str2time($post->{updated_time});
     318            if ($updated_time >= $self->{last_poll} && defined $post->{comments}{data}) {
     319                for my $comment (@{$post->{comments}{data}}) {
     320                    my $comment_time = str2time($comment->{created_time});
     321                    if ($comment_time < $self->{last_poll}) {
     322                        next;
     323                    }
     324                    my $msg = BarnOwl::Message->new(
     325                        type      => 'Facebook',
     326                        sender    => $comment->{from}{name},
     327                        sender_id => $comment->{from}{id},
     328                        name      => $name,
     329                        name_id   => $name_id,
     330                        direction => 'in',
     331                        body      => $comment->{message},
     332                        post_id   => $post_id,
     333                        topic     => $topic,
     334                        time      => asctime(localtime $comment_time),
     335                        permalink => "",
     336                       );
     337                    BarnOwl::queue_message($msg);
     338                }
     339            }
     340            if ($updated_time + 1 > $new_last_poll) {
     341                $new_last_poll = $updated_time + 1;
     342            }
    338343        }
    339         if ($updated_time + 1 > $new_last_poll) {
    340             $new_last_poll = $updated_time + 1;
    341         }
    342     }
    343     # old_topics gets GC'd
    344 
    345     $self->{last_poll} = $new_last_poll;
     344        # old_topics gets GC'd
     345
     346        $self->{last_poll} = $new_last_poll;
     347    });
    346348}
    347349
     
    375377    my $msg = shift;
    376378
     379    my $cont = sub { $self->sleep(0); };
     380
    377381    if (defined $user) {
    378382        $user = $self->{friends}{$user} || $user;
    379         eval { $self->{facebook}->add_post($user)->set_message($msg)->publish; };
    380         return unless $self->check_result;
     383        $self->{facebook}->add_post($user)->set_message($msg)->publish($cont);
    381384    } else {
    382         eval { $self->{facebook}->add_post->set_message($msg)->publish; };
    383         return unless $self->check_result;
    384     }
    385     $self->sleep(0);
     385        $self->{facebook}->add_post->set_message($msg)->publish($cont);
     386    }
    386387}
    387388
     
    392393    my $msg = shift;
    393394
    394     eval { $self->{facebook}->add_comment($post_id)->set_message($msg)->publish; };
    395     return unless $self->check_result;
    396     $self->sleep(0);
     395    $self->{facebook}->add_comment($post_id)->set_message($msg)->publish(sub { $self->sleep(0); });
    397396}
    398397
     
    416415
    417416    $self->{cfg}->{token} = $1;
    418     if ($self->facebook_do_auth) {
     417    $self->facebook_do_auth(sub {
    419418        my $raw_cfg = to_json($self->{cfg});
    420419        BarnOwl::admin_message('Facebook', "Add this as the contents of your ~/.owl/facebook file:\n$raw_cfg");
    421     }
     420    });
     421    return;
    422422}
    423423
    424424sub facebook_do_auth {
    425425    my $self = shift;
     426    my $success = shift || sub {};
    426427    if (!defined $self->{cfg}->{token}) {
    427428        BarnOwl::admin_message('Facebook', "Login to Facebook at ".$self->{login_url}
     
    437438    $self->{facebook}->access_token($self->{cfg}->{token});
    438439    # Do a quick check to see if things are working
    439     my $result = eval { $self->{facebook}->query()->find('me')->select_fields('name')->request->as_hashref; };
    440     if ($@) {
    441         BarnOwl::admin_message('Facebook', "Failed to authenticate with '$@'!"
    442             . "\nLogin to Facebook at ".$self->{login_url}
    443             . "\nand run command ':facebook-auth URL' with the URL you are redirected to.");
    444         return 0;
    445     } else {
    446         my $name = $result->{'name'};
    447         BarnOwl::admin_message('Facebook', "Successfully logged in to Facebook as $name!");
    448         $self->{logged_in} = 1;
    449         $self->sleep(0); # start polling
    450         return 1;
    451     }
     440    $self->{facebook}->query()->find('me')->select_fields('name')->request(sub {
     441        my $result = eval { shift->as_hashref };
     442        if ($@) {
     443            BarnOwl::admin_message('Facebook', "Failed to authenticate with '$@'!"
     444                . "\nLogin to Facebook at ".$self->{login_url}
     445                . "\nand run command ':facebook-auth URL' with the URL you are redirected to.");
     446        } else {
     447            my $name = $result->{'name'};
     448            BarnOwl::admin_message('Facebook', "Successfully logged in to Facebook as $name!");
     449            $self->{logged_in} = 1;
     450            $self->sleep(0); # start polling
     451            $success->();
     452        }
     453    });
    452454}
    453455
  • perl/modules/Facebook/lib/Facebook/Graph.pm

    r2a42248 r7777ac2  
    6262
    6363sub request_access_token {
    64     my ($self, $code) = @_;
    65     my $token = Facebook::Graph::AccessToken->new(
     64    my ($self, $code, $cb) = @_;
     65    Facebook::Graph::AccessToken->new(
    6666        code            => $code,
    6767        postback        => $self->postback,
    6868        secret          => $self->secret,
    6969        app_id          => $self->app_id,
    70     )->request;
    71     $self->access_token($token->token);
    72     return $token;
     70    )->request(sub {
     71        my ($response) = @_;
     72        $self->access_token($response->token);
     73        $cb->($response);
     74    });
    7375}
    7476
    7577sub convert_sessions {
    76     my ($self, $sessions) = @_;
    77     return Facebook::Graph::Session->new(
     78    my ($self, $sessions, $cb) = @_;
     79    Facebook::Graph::Session->new(
    7880        secret          => $self->secret,
    7981        app_id          => $self->app_id,
    8082        sessions        => $sessions,
    81         )
    82         ->request
    83         ->as_hashref;
     83    )->request($cb); # API change
    8484}
    8585
     
    9292}
    9393
    94 sub fetch {
    95     my ($self, $object_name) = @_;
    96     return $self->query->find($object_name)->request->as_hashref;
    97 }
     94# XXX error handling
     95#sub fetch {
     96#    my ($self, $object_name, $cb) = @_;
     97#    $self->query->find($object_name)->request(sub {
     98#        my ($result) = @_;
     99#        $cb->($result->as_hashref);
     100#    });
     101#}
    98102
    99103sub query {
     
    540544L<Any::Moose>
    541545L<JSON>
    542 L<LWP>
    543 L<LWP::Protocol::https>
     546L<AnyEvent::HTTP>
    544547L<Mozilla::CA>
    545548L<URI>
  • perl/modules/Facebook/lib/Facebook/Graph/AccessToken.pm

    r2a42248 r7777ac2  
    77use Facebook::Graph::AccessToken::Response;
    88with 'Facebook::Graph::Role::Uri';
    9 use LWP::UserAgent;
     9use AnyEvent::HTTP;
    1010
    1111has app_id => (
     
    4343
    4444sub request {
    45     my ($self) = @_;
    46     my $response = LWP::UserAgent->new->get($self->uri_as_string);
    47     return Facebook::Graph::AccessToken::Response->new(response => $response);
     45    my ($self, $cb) = @_;
     46    http_get $self->uri_as_string, sub {
     47        my ($response, $headers) = @_;
     48        $cb->(Facebook::Graph::AccessToken::Response->new(
     49            response => $response,
     50            headers => $headers,
     51            uri => $self->uri_as_string
     52        ));
     53    };
    4854}
    4955
  • perl/modules/Facebook/lib/Facebook/Graph/AccessToken/Response.pm

    r2a42248 r7777ac2  
    1818    lazy    => 1,
    1919    default => sub {
     20        # LOL error handling
    2021        my $self = shift;
    21         my $response = $self->response;
    22         if ($response->is_success) {
    23             return URI->new('?'.$response->content)->query_param('access_token');
    24         }
    25         else {
    26             ouch $response->code, 'Could not fetch access token: '.$response->message, $response->request->uri->as_string;
    27         }
     22        return URI->new('?'.$self->response)->query_param('access_token');
     23        #else {
     24        #    ouch $response->code, 'Could not fetch access token: '.$response->message, $response->request->uri->as_string;
     25        #}
    2826    }
    2927);
     
    3331    lazy    => 1,
    3432    default => sub {
     33        # LOL error handling
    3534        my $self = shift;
    36         my $response = $self->response;
    37         if ($response->is_success) {
    38             return URI->new('?'.$response->content)->query_param('expires');
    39         }
    40         else {
    41             ouch $response->code, 'Could not fetch access token: '.$response->message, $response->request->uri->as_string;
    42         }
     35        return URI->new('?'.$self->response)->query_param('expires');
     36        #else {
     37        #    ouch $response->code, 'Could not fetch access token: '.$response->message, $response->request->uri->as_string;
     38        #}
    4339    }
    4440);
  • perl/modules/Facebook/lib/Facebook/Graph/Publish.pm

    r2a42248 r7777ac2  
    77use Facebook::Graph::Response;
    88with 'Facebook::Graph::Role::Uri';
    9 use LWP::UserAgent;
     9use AnyEvent::HTTP;
     10use LWP::UserAgent; # XXX blegh
     11use HTTP::Request::Common;
    1012use URI::Encode qw(uri_decode);
    1113
     
    4244
    4345sub publish {
    44     my ($self) = @_;
     46    my ($self, $cb) = @_;
    4547    my $uri = $self->uri;
    4648    $uri->path($self->object_name.$self->object_path);
    47     my $response = LWP::UserAgent->new->post($uri, $self->get_post_params);
    48     my %params = (response => $response);
    49     if ($self->has_secret) {
    50         $params{secret} = $self->secret;
     49    # XXX blegh
     50    my $request = LWP::UserAgent->new->request(POST $uri->as_string, $self->get_post_params);
     51    http_post $uri->as_string, $request->content, sub {
     52        warn "whooo";
     53        my ($response, $headers) = @_;
     54        my %params = (
     55            response => $response,
     56            headers  => $headers,
     57            uri      => $uri->as_string
     58        );
     59        if ($self->has_secret) {
     60            $params{secret} = $self->secret;
     61        }
     62        $cb->(Facebook::Graph::Response->new(%params));
    5163    }
    52     return Facebook::Graph::Response->new(%params);
    5364}
    5465
  • perl/modules/Facebook/lib/Facebook/Graph/Query.pm

    r2a42248 r7777ac2  
    77use Facebook::Graph::Response;
    88with 'Facebook::Graph::Role::Uri';
    9 use LWP::UserAgent;
     9use AnyEvent::HTTP;
    1010use URI::Encode qw(uri_decode);
    1111
     
    183183
    184184sub request {
    185     my ($self, $uri) = @_;
    186     $uri ||= $self->uri_as_string;
    187     my $response = LWP::UserAgent->new->get($uri);
    188     my %params = (response => $response);
    189     if ($self->has_secret) {
    190         $params{secret} = $self->secret;
    191     }
    192     return Facebook::Graph::Response->new(%params);
     185    my ($self, $cb) = @_;
     186    my $uri = $self->uri_as_string;
     187    http_get $uri, sub {
     188        my ($response, $headers) = @_;
     189        my %params = (
     190            response => $response,
     191            headers => $headers,
     192            uri => $uri
     193        );
     194        if ($self->has_secret) {
     195            $params{secret} = $self->secret;
     196        }
     197        $cb->(Facebook::Graph::Response->new(%params));
     198    };
    193199}
    194200
  • perl/modules/Facebook/lib/Facebook/Graph/Response.pm

    r2a42248 r7777ac2  
    1313);
    1414
     15has headers => (
     16    is      => 'ro',
     17    required=> 1,
     18);
     19
     20has uri => (
     21    is      => 'ro',
     22    required=> 1,
     23);
     24
    1525has as_string => (
    1626    is      => 'ro',
     
    1828    default => sub {
    1929        my $self = shift;
    20         return $self->response->content;
     30        if (!defined $self->response) {
     31            ouch $self->headers->{Status}, $self->headers->{Reason}, $self->uri;
     32        }
     33        if ($self->headers->{Status} < 200 || $self->headers->{Status} >= 300) {
     34            my $type = $self->headers->{Status};
     35            my $message = $self->response;
     36            my $error = eval { JSON->new->decode($self->response) };
     37            unless ($@) {
     38                $type = $error->{error}{type};
     39                $message = $error->{error}{message};
     40            }
     41            ouch $type, 'Could not execute request ('.$self->uri.'): '.$message, $self->uri;
     42        }
     43        return $self->response;
    2144    },
    2245);
     
    2750    default => sub {
    2851        my $self = shift;
    29         my $response = $self->response;
    30         if ($response->is_success) {
    31             return $response->content;
    32         }
    33         else {
    34             my $message = $response->message;
    35             my $error = eval { JSON->new->decode($response->content) };
    36             unless ($@) {
    37                 $message = $error->{error}{type} . ' - ' . $error->{error}{message};
    38             }
    39             ouch $response->code, 'Could not execute request ('.$response->request->uri->as_string.'): '.$message, $response->request->uri->as_string;
    40         }
     52        return $self->as_string;
    4153    },
    4254);
  • perl/modules/Facebook/lib/Facebook/Graph/Session.pm

    r2a42248 r7777ac2  
    77use Facebook::Graph::Response;
    88with 'Facebook::Graph::Role::Uri';
    9 use LWP::UserAgent;
     9use AnyEvent::HTTP;
    1010
    1111has app_id => (
     
    3838
    3939sub request {
    40     my ($self) = @_;
    41     my $response = LWP::UserAgent->new->get($self->uri_as_string);
    42     return Facebook::Graph::Response->new(response => $response);
     40    my ($self, $cb) = @_;
     41    http_get $self->uri_as_string, sub {
     42        my ($response, $headers) = @_;
     43        $cb->(Facebook::Graph::Response->new(
     44            response => $response,
     45            headers  => $headers,
     46            uri      => $self->uri_as_string
     47        ));
     48    };
    4349}
    4450
Note: See TracChangeset for help on using the changeset viewer.