Permalink
Browse files

Initial version

  • Loading branch information...
0 parents commit c738edb178b6cf716a31d25681db684b4ba6c5bf @yannk committed Jul 25, 2009
Showing with 328 additions and 0 deletions.
  1. +5 −0 .gitignore
  2. +3 −0 .shipit
  3. +4 −0 Changes
  4. +14 −0 MANIFEST.SKIP
  5. +10 −0 Makefile.PL
  6. +31 −0 README
  7. +32 −0 eg/print_feed_titles.pl
  8. +200 −0 lib/AnyEvent/Superfeedr.pm
  9. +4 −0 t/00_compile.t
  10. +3 −0 x.pl
  11. +5 −0 xt/perlcritic.t
  12. +4 −0 xt/pod.t
  13. +9 −0 xt/podspell.t
  14. +4 −0 xt/synopsis.t
@@ -0,0 +1,5 @@
+META.yml
+Makefile
+inc/
+pm_to_blib
+*~
@@ -0,0 +1,3 @@
+steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN
+git.push_to = origin
+CheckChangeLog.files = Changes
@@ -0,0 +1,4 @@
+Revision history for Perl extension AnyEvent::Superfeedr
+
+0.01 Fri Jul 24 21:58:34 2009
+ - Initial version that doesn't do much
@@ -0,0 +1,14 @@
+\bRCS\b
+\bCVS\b
+\.svn/
+\.git/
+^MANIFEST\.
+^Makefile$
+~$
+\.old$
+^blib/
+^pm_to_blib
+^MakeMaker-\d
+\.gz$
+\.cvsignore
+\.shipit
@@ -0,0 +1,10 @@
+use inc::Module::Install;
+name 'AnyEvent-Superfeedr';
+all_from 'lib/AnyEvent/Superfeedr.pm';
+
+build_requires 'Test::More';
+use_test_base;
+auto_include_deps;
+author_tests('xt');
+auto_set_repository;
+WriteAll;
@@ -0,0 +1,31 @@
+This is Perl module AnyEvent::Superfeedr.
+
+NOTES
+
+see installation notes below.
+
+INSTALLATION
+
+AnyEvent::Superfeedr installation is straightforward. If your CPAN shell is set up,
+you should just be able to do (well, when this will be on CPAN ;)
+
+ % cpan AnyEvent::Superfeedr
+
+Download it, unpack it, then build it as per the usual:
+
+ % perl Makefile.PL
+ % make && make test
+
+Then install it:
+
+ % make install
+
+DOCUMENTATION
+
+AnyEvent::Superfeedr documentation is available as in POD. So you can do:
+
+ % perldoc AnyEvent::Superfeedr
+
+to read the documentation online with your favorite pager.
+
+Yann Kerherve
@@ -0,0 +1,32 @@
+use strict;
+use warnings;
+use Find::Lib '../lib';
+use AnyEvent::Superfeedr;
+use Encode;
+
+die "$0 <jid> <pass>" unless @ARGV >= 2;
+
+binmode STDOUT, ":utf8";
+
+my $end = AnyEvent->condvar;
+my $sf = AnyEvent::Superfeedr->new(
+ jid => shift,
+ password => shift,
+ #subscription => {
+ # interval => 5,
+ # cb => sub { [ "http://blog.cyberion.net/atom.xml"] },
+ #},
+ on_notification => sub {
+ my $entry = shift;
+ my $title = Encode::decode_utf8($entry->title);
+ $title =~ s/\s+/ /gs;
+
+ my $l = length $title;
+ my $max = 50;
+ if ($l > $max) {
+ substr $title, $max - 3, $l - $max + 3, '...';
+ }
+ printf "~ %-50s\n", $title;
+ },
+);
+$end->recv;
@@ -0,0 +1,200 @@
+package AnyEvent::Superfeedr;
+
+use strict;
+use warnings;
+use 5.008_001;
+
+our $VERSION = '0.01';
+use Carp;
+
+use AnyEvent;
+#use AnyEvent::Superfeedr::Notification;
+use AnyEvent::XMPP::Client;
+use AnyEvent::XMPP::Ext::Pubsub;
+use XML::Atom::Entry;
+
+use constant DEFAULT_SUB_IV => 60;
+
+our $SERVICE = 'firehoser.superfeedr.com';
+
+# TODO:
+# debug
+# tests
+# on_error
+# better error handling
+# (maybe) pubsub
+
+sub new {
+ my $class = shift;
+ my %param = @_;
+
+ my %filtered;
+ for ( qw{jid password debug subscription on_notification on_error} ) {
+ $filtered{$_} = delete $param{$_};
+ }
+ croak "Unknown option(s): " . join ", ", keys %param if keys %param;
+
+ my $superfeedr = bless {
+ debug => $filtered{debug} || 0,
+ jid => $filtered{jid},
+ password => $filtered{password},
+ }, ref $class || $class;
+
+ if (my $s = $filtered{subscription}) {
+ my $cb = $s->{cb}
+ or croak "subscription needs to pass a 'cb' callback";
+ my $iv = $s->{interval} || DEFAULT_SUB_IV;
+
+ my $timer_cb = sub {
+ my $list = $cb->($superfeedr);
+ return unless $list && @$list;
+ my $pubsub = $superfeedr->xmpp_pubsub;
+ my $con = $superfeedr->xmpp_connection;
+ unless ($pubsub && $con) {
+ warn "Not connected yet?";
+ return;
+ }
+ my $res_cb = sub {}; # XXX
+ # XXX also could do a huge list in eone slump
+ for my $feed (@$list) {
+ my $enc_feed = $feed; # XXX
+ my $xmpp_uri = "xmpp:$SERVICE?;node=$enc_feed";
+ $pubsub->subscribe_node($con, $xmpp_uri, $res_cb);
+ }
+ };
+ $superfeedr->{sub_timer} = AnyEvent->timer(
+ after => $iv, interval => $iv, cb => $timer_cb,
+ );
+ }
+ my $cl = AnyEvent::XMPP::Client->new(
+ debug => $superfeedr->{debug},
+ );
+ my $pass = $superfeedr->{password};
+ my $jid = $superfeedr->{jid}
+ or croak "You need to specify your jid";
+
+ $cl->add_account($jid, $pass, undef, undef, {
+ dont_retrieve_roster => 1,
+ });
+ $cl->add_extension(my $ps = AnyEvent::XMPP::Ext::Pubsub->new);
+ $superfeedr->{xmpp_pubsub} = $ps;
+
+ my $on_error = $filtered{on_error} || sub {
+ croak "Error: ". $_[2]->string;
+ };
+
+ $cl->reg_cb(
+ error => $on_error,
+ connected => sub {
+ $superfeedr->{xmpp_client} = $cl;
+ },
+ disconnect => sub {
+ my ($account, $host, $port) = @_;
+ warn "Got Disconnected from $host:$port\n";
+ },
+ connect_error => sub {
+ my ($account, $reason) = @_;
+ my $jid = $account->bare_jid;
+ croak "connection error for $jid: $reason";
+ },
+ );
+ if (my $on_notification = $filtered{on_notification} ) {
+ $ps->reg_cb(
+ pubsub_recv => sub {
+ my $ps = shift;
+ my @items = @_;
+ for my $item (@items) {
+ ## each item as one entry
+ my ($entry) = $item->nodes;
+ ## there must be more efficient ways? XXX
+ my $str = $entry->as_string;
+ my $ae = XML::Atom::Entry->new(Stream => \$str);
+ $on_notification->($ae);
+ }
+ },
+ );
+ }
+ $cl->start;
+
+ return $superfeedr;
+}
+
+sub xmpp_pubsub {
+ my $superfeedr = shift;
+ return $superfeedr->{xmpp_pubsub};
+}
+
+sub xmpp_connection {
+ my $superfeedr = shift;
+ my $con = $superfeedr->{xmpp_connection};
+ return $con if $con;
+
+ my $client = $superfeedr->{xmpp_client} or return;
+ my $jid = $superfeedr->{jid};
+ my $account = $client->get_account($jid) or return;
+ $con = $account->connection;
+ $superfeedr->{xmpp_connection} = $con;
+ return $con;
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=for stopwords
+
+=head1 NAME
+
+AnyEvent::Superfeedr - XMPP interface to Superfeedr service.
+
+=head1 SYNOPSIS
+
+ use AnyEvent::Superfeedr;
+
+ $end = AnyEvent->condvar;
+
+ ## receive 20 notifications and stop
+ $n = 0;
+ $callback = sub {
+ my Net::Superfeedr::Notification $notification = shift;
+ for my XML::Atom::Entry $entry ($notification->entries) {
+ printf "Got: %s\n" $entry->title;
+ }
+ $end->send if ++$n == 20;
+ };
+
+ $superfeedr = AnyEvent::Superfeedr->new(
+ jid => $jid,
+ password => $password
+ subscription => {
+ interval => 5,
+ cb => \%get_new_feeds,
+ },
+ on_notification => $callback,
+ );
+
+ $end->recv;
+
+=head1 DESCRIPTION
+
+Allows you to subscribe to feeds and get notified real-time about new
+content.
+
+This is a first version of the api, and probably only covers specific
+architectural needs.
+
+=head1 AUTHOR
+
+Yann Kerherve E<lt>yannk@cpan.orgE<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::XMPP> L<AnyEvent> L<http://superfeedr.com>
+
+=cut
@@ -0,0 +1,4 @@
+use strict;
+use Test::More tests => 1;
+
+BEGIN { use_ok 'AnyEvent::Superfeedr' }
@@ -0,0 +1,3 @@
+my $x = "xxxxxxxx";
+substr $x, 2, (length $x) - 2, '...';
+warn $x;
@@ -0,0 +1,5 @@
+use strict;
+use Test::More;
+eval q{ use Test::Perl::Critic };
+plan skip_all => "Test::Perl::Critic is not installed." if $@;
+all_critic_ok("lib");
@@ -0,0 +1,4 @@
+use Test::More;
+eval "use Test::Pod 1.00";
+plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
+all_pod_files_ok();
@@ -0,0 +1,9 @@
+use Test::More;
+eval q{ use Test::Spelling };
+plan skip_all => "Test::Spelling is not installed." if $@;
+add_stopwords(<DATA>);
+set_spell_cmd("aspell -l en list");
+all_pod_files_spelling_ok('lib');
+__DATA__
+Tatsuhiko
+Miyagawa
@@ -0,0 +1,4 @@
+use Test::More;
+eval "use Test::Synopsis";
+plan skip_all => "Test::Synopsis required" if $@;
+all_synopsis_ok();

0 comments on commit c738edb

Please sign in to comment.