הלינקייה: מגזין חודשי למפתחים

רוצה לשמוע על כל האירועים, המדריכים, הקורסים והמאמרים שנכתבו החודש ?
הלינקייה הינו מגזין חופשי בעברית שמשאיר אותך בעניינים.
בלי ספאם. בלי שטויות. פעם בחודש אצלך בתיבה.

Facebook Like Contest

Below are two examples for using AnyEvent to write async netwrorking code in perl. We start with a simple echo server, and move on to some facebook integration. Note each time how $cv->recv is our entry point to the event look. This call will block until we finish our networking operations completely and exit the Event Loop by calling $cv->send.

The Echo Server simply listens on port 8190 for incoming clients, and echos back their message using the async socket operations push_read and push_write.

The Famous facebook like contest is a small program that goes over all your facebook friends and checks how many things each one of them likes. In the end, it'll provide a nice printout of the 3 friends who have liked the most pages.
Here, we're using AnyEvent to write async networking code. In async code, perl will send all the requests at once, and attach a callback to each network request. When the data is ready, the callback will be called with the data fetched from facebook, and we'll get a chance to order that into our data structures.
The good thing about using Async model is no thread synchronization is required. No two callbacks will ever get called concurrently. This saves us a great deal of trouble syncing our data structures and worrying what happens when.
I always prefer the Async networking model over the threaded one.

#################################
# A Simple AnyEvent Echo Server
#
# Using AnyEvent we build a TCP server that binds on port 8190 listening for clients,
# Note how all we need to do is define WHAT TO DO when a client sends a message in terms
# of a push_read callback.
# When the server gets a line from a client, our callback is called. It works because 
# echo is stateless.
#
# For protocols with states, we could use a %clients hash to store current
# state for every client.
#

use Modern::Perl;

use AnyEvent;
use AnyEvent::Socket qw/tcp_server/;
use AnyEvent::Handle;

my $gaurd = tcp_server undef, 8190, sub {
    my ($fh, $host, $port) = @_;
    my $hdl = AnyEvent::Handle->new( fh => $fh, on_error => sub {}  );

    my $reader; $reader = sub {
        my ($handle, $line) = @_;
        $hdl->push_write($line. "\n");
        $hdl->push_read( line => $reader );
    };

    $hdl->push_read(line => $reader);
};

AnyEvent->condvar->recv;


use strict;
use warnings;
 
use JSON;
 
use AnyEvent::HTTP;
use Data::Dumper;
 
my %likes;
 
my $fbtoken = '';
 
my $cv = AnyEvent->condvar;
my $active;
 
sub count_likes {
    my ($data, $headers) = @_;
    my $likes = from_json($data);
 
    $likes{$headers->{URL}}{LIKES} = scalar @ { $likes->{data} };
 
    --$active;
    warn "Active: [ $active ]";
 
    $cv->end;
}
 
http_get 'https://graph.facebook.com/me/friends?access_token='.$fbtoken, 
sub {
    my ($data, $headers) = @_;
 
    my $friends = from_json($data);
    foreach my $f (@{ $friends->{data} }) {
        my $url =   'https://graph.facebook.com/' . 
                    $f->{id} .
                    '/likes?access_token=' . $fbtoken;
 
        http_get $url, \&count_likes;
 
        $likes{$url}{name} = $f->{name};
        ++$active;
        $cv->begin;
    }
};
 
$cv->recv;
 
my @top = (reverse sort {
$a->{LIKES} <=> $b->{LIKES}
    } values %likes)[0..2];
 
warn Dumper(\@top);

course: