Ignore:
Timestamp:
Sep 19, 2011, 1:31:34 PM (13 years ago)
Author:
Edward Z. Yang <ezyang@mit.edu>
Children:
b594537
Parents:
ee98987
git-author:
Edward Z. Yang <ezyang@mit.edu> (06/19/11 22:39:49)
git-committer:
Edward Z. Yang <ezyang@mit.edu> (09/19/11 13:31:34)
Message:
Comment reading support and back-timing.

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

Legend:

Unmodified
Added
Removed
  • perl/modules/Facebook/README

    ree98987 r718c23f  
    2929
    3030TODO
    31   * We support commenting on wall posts, but not /displaying/ comments
    32     to a wall post.
     31  * Polling Facebook is pretty slow (on order of a second or more),
     32    and blocks the entire BarnOwl interface.  We need to confront
     33    Perl's threading demon.
    3334  * We currently expose the underlying post ID for disambiguating
    3435    instances.  Use something more user-friendly.
  • perl/modules/Facebook/lib/BarnOwl/Module/Facebook/Handle.pm

    ree98987 r718c23f  
    1717use Data::Dumper;
    1818use JSON;
     19use Date::Parse;
     20use POSIX;
    1921
    2022use Scalar::Util qw(weaken);
     
    2426
    2527our $app_id = 235537266461636; # for application 'barnowl'
     28
     29# Unfortunately, Facebook does not offer a comment stream, in the same
     30# way we can get a post stream using the news feed.  This makes it a bit
     31# difficult to de-duplicate comments we have already seen.  We use a
     32# simple heuristic to fix this: we check if the comment's time is dated
     33# from before our last update, and don't re-post if it's dated before.
     34# Be somewhat forgiving, since it's better to duplicate a post than to
     35# drop one.  Furthermore, we must use Facebook's idea of time, since the
     36# server BarnOwl is running on may be desynchronized.  So we need to
     37# utilize Facebook's idea of time, not ours.  We do this by looking at
     38# all of the timestamps we see while processing an update, and take the
     39# latest one and increment it by one second.
     40#
     41# What properties do we get with this setup?
     42#
     43#   - We get comment updates only for the latest N posts on a news feed.
     44#   Any later ones, you have to use Facebook's usual mechanisms (e.g.
     45#   email notifications).
     46#
     47#   - Processing a poll is relatively expensive, since we have to
     48#   iterate over N new posts.  It might be worthwhile polling for new
     49#   comments less frequently than polling for new posts.
    2650
    2751sub fail {
     
    3963        'cfg'  => $cfg,
    4064        'facebook' => undef,
    41         'last_poll' => time - 60 * 60 * 24,
    42         'last_message_poll' => time,
     65
     66        # Initialized with our 'time', but will be synced to Facebook
     67        # soon enough.
     68        'last_poll' => time - 60 * 60 * 24 * 2,
    4369        'timer' => undef,
    44         'message_timer' => undef,
     70
     71        # Message polling not implemented yet
     72        #'last_message_poll' => time,
     73        #'message_timer' => undef,
     74
    4575        # yeah yeah, inelegant, I know.  You can try using
    4676        # $fb->authorize, but at time of writing (1.0300) they didn't support
     
    4979        # minified to fit in most terminal windows.
    5080        'login_url' => 'http://goo.gl/yA42G',
     81
    5182        'logged_in' => 0
    5283    };
     
    110141    #BarnOwl::message("Polling Facebook...");
    111142
    112     # blah blah blah
     143    # XXX Oh no! This blocks the user interface.  Not good.
     144    # Ideally, we should have some worker thread for polling facebook.
     145    # But BarnOwl is probably not thread-safe >_<
    113146
    114147    my $updates = eval {
     
    116149             ->query
    117150             ->from("my_news")
    118              # ->include_metadata()
    119              # ->select_fields( ??? )
    120              ->where_since( "@" . $self->{last_poll} )
     151             # Not using this, because we want to pick up comment
     152             # updates. We need to manually de-dup, though.
     153             # ->where_since( "@" . $self->{last_poll} )
     154             ->limit_results( 200 )
    121155             ->request()
    122156             ->as_hashref()
    123157    };
    124 
    125     $self->{last_poll} = time;
    126158    $self->die_on_error($@);
    127159
    128160    #warn Dumper($updates);
    129161
     162    my $new_last_poll = $self->{last_poll};
    130163    for my $post ( reverse @{$updates->{data}} ) {
    131         # no app invites, thanks! (XXX make configurable)
     164        # No app invites, thanks! (XXX make configurable)
    132165        if ($post->{type} eq 'link' && $post->{application}) {
    133166            next;
    134167        }
    135         # XXX need to somehow access Facebook's user hiding mechanism...
    136         # indexing is fragile
    137         my $msg = BarnOwl::Message->new(
    138             type      => 'Facebook',
    139             sender    => $post->{from}{name},
    140             sender_id => $post->{from}{id},
    141             name      => $post->{to}{data}[0]{name} || $post->{from}{name},
    142             name_id   => $post->{to}{data}[0]{id} || $post->{from}{id},
    143             direction => 'in',
    144             body      => $self->format_body($post),
    145             postid    => $post->{id},
    146             zsig      => $post->{actions}[0]{link},
    147            );
    148         BarnOwl::queue_message($msg);
    149     }
     168
     169        # XXX Need to somehow access Facebook's user hiding
     170        # mechanism
     171
     172        # There can be multiple recipients! Strange! Pick the first one.
     173        my $name    = $post->{to}{data}[0]{name} || $post->{from}{name};
     174        my $name_id = $post->{to}{data}[0]{id} || $post->{from}{id};
     175
     176        # Only handle post if it's new
     177        my $created_time = str2time($post->{created_time});
     178        if ($created_time >= $self->{last_poll}) {
     179            # XXX indexing is fragile
     180            my $msg = BarnOwl::Message->new(
     181                type      => 'Facebook',
     182                sender    => $post->{from}{name},
     183                sender_id => $post->{from}{id},
     184                name      => $name,
     185                name_id   => $name_id,
     186                direction => 'in',
     187                body      => $self->format_body($post),
     188                postid    => $post->{id},
     189                time      => asctime(localtime $created_time),
     190                # XXX The intent is to get the 'Comment' link, which also
     191                # serves as a canonical link to the post.  The {name}
     192                # field should equal 'Comment'.
     193                zsig      => $post->{actions}[0]{link},
     194               );
     195            BarnOwl::queue_message($msg);
     196        }
     197
     198        # This will have funky interleaving of times (they'll all be
     199        # sorted linearly), but since we don't expect too many updates between
     200        # polls this is pretty acceptable.
     201        my $updated_time = str2time($post->{updated_time});
     202        if ($updated_time >= $self->{last_poll} && defined $post->{comments}{data}) {
     203            for my $comment ( @{$post->{comments}{data}} ) {
     204                my $comment_time = str2time($comment->{created_time});
     205                if ($comment_time < $self->{last_poll}) {
     206                    next;
     207                }
     208                my $msg = BarnOwl::Message->new(
     209                    type      => 'Facebook',
     210                    sender    => $comment->{from}{name},
     211                    sender_id => $comment->{from}{id},
     212                    name      => $name,
     213                    name_id   => $name_id,
     214                    direction => 'in',
     215                    body      => $comment->{message},
     216                    postid    => $post->{id},
     217                    time      => asctime(localtime $comment_time),
     218                   );
     219                BarnOwl::queue_message($msg);
     220            }
     221        }
     222        if ($updated_time + 1 > $new_last_poll) {
     223            $new_last_poll = $updated_time + 1;
     224        }
     225    }
     226
     227    $self->{last_poll} = $new_last_poll;
    150228}
    151229
Note: See TracChangeset for help on using the changeset viewer.