The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package AnyEvent::FriendFeed::Realtime;

use strict;
use 5.008_001;
our $VERSION = '0.05';

use AnyEvent;
use AnyEvent::HTTP;
use Encode;
use JSON;
use MIME::Base64;
use Scalar::Util;
use URI;
use URI::QueryParam;

sub new {
    my($class, %args) = @_;

    my $headers = {};
    if ($args{username}) {
        my $auth = MIME::Base64::encode( join(":", $args{username}, $args{remote_key}) );
        $headers->{Authorization} = "Basic $auth";
    }

    my $uri = URI->new("http://friendfeed-api.com/v2/updates$args{request}");
    $uri->query_param(updates => 1);

    my $self = bless {}, $class;

    my $long_poll; $long_poll = sub {
        http_get $uri, headers => $headers, on_header => sub {
            my $hdrs = shift;
            if ($hdrs->{Status} ne '200') {
                ($args{on_error} || sub { die @_ })->("$uri: $hdrs->{Status} $hdrs->{Reason}");
                return;
            }
            return 1;
        }, sub {
            my($body, $headers) = @_;
            return $long_poll->() unless $body;
            my $res = eval { JSON::decode_json($body) } || do {
                ($args{on_error} || sub { die @_ })->("JSON parsing error: $@");
                return;
            };

            if ($res->{errorCode}) {
                ($args{on_error} || sub { die @_ })->($res->{errorCode});
                return;
            }

            for my $entry (@{$res->{entries}}) {
                ($args{on_entry} || sub {})->($entry);
            }

            if ($res->{realtime}) {
                $uri = $uri->clone;
                $uri->query_param(cursor => $res->{realtime}{cursor});
                $long_poll->();
            }
        }
    };

    $self->{guard} = AnyEvent::Util::guard { undef $long_poll };

    $long_poll->();

    return $self;
}

1;
__END__

=encoding utf-8

=for stopwords

=head1 NAME

AnyEvent::FriendFeed::Realtime - Subscribe to FriendFeed Real-time API

=head1 SYNOPSIS

  use AnyEvent::FriendFeed::Realtime;

  my $client = AnyEvent::FriendFeed::Realtime->new(
      username   => $user,        # optional
      remote_key => $remote_key,  # optional: https://friendfeed.com/account/api
      request    => "/feed/home", # or "/feed/NICKNAME/friends", "/search?q=friendfeed"
      on_entry   => sub {
          my $entry = shift;
          # See http://friendfeed.com/api/documentation for the data structure
      },
  );

=head1 DESCRIPTION

AnyEvent::FriendFeed::Realtime is an AnyEvent consumer that subscribes
to FriendFeed Real-time API via JSON long-poll.

=head1 AUTHOR

Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt>

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=head1 SEE ALSO

L<AnyEvent::HTTP>, L<AnyEvent::Twitter::Stream>, L<http://friendfeed.com/api/documentation>

=cut