[Jifty-commit] jifty branch, pubsub, updated. 1.10518-119-g70b4e0b

Jifty commits jifty-commit at lists.jifty.org
Sun Nov 4 23:31:13 EST 2012


The branch, pubsub has been updated
       via  70b4e0b87215303dc71f9e7cc98b6a6c3a2e7b2e (commit)
       via  5d37a0265615cd19beafa799418b64bffdf2d931 (commit)
       via  5e7e3f4c66a4be0c2759917365e7c409437a4436 (commit)
       via  334b68a8395e249cf667960dc4c87b6daabb2dc1 (commit)
       via  4ec0fba30b291bd77445c35b37031cca900f7e64 (commit)
       via  32ca123a51c368811c7cf30911b7931881cc55d5 (commit)
       via  dc1aa828e553750a7f4741979954f45bf59d5961 (commit)
       via  fdd5c220c340965d7a326b60cbfc264b92cb5f33 (commit)
       via  2029bac5bf148a122eda11caa94f790c5f19a51d (commit)
       via  2294fd07361583527a38f6466a032001ac0e6d80 (commit)
       via  0b284881140239899aad28ba507160a162d49ab2 (commit)
       via  d3057798d80ea490221871b0af6cd11bb3b6d57e (commit)
      from  e0fe716106b5dc0ac3f36bdefb139ab20a9f9902 (commit)

Summary of changes:
 Makefile.PL                                        |  11 ++
 lib/Jifty/Plugin/PubSub.pm                         | 163 +++++++++++++++++++-
 lib/Jifty/Plugin/PubSub/Bus.pm                     |  43 ++++++
 lib/Jifty/Plugin/PubSub/Connection.pm              | 168 +++++++++++++++++----
 lib/Jifty/Plugin/PubSub/Subscriptions.pm           | 120 +++++++++++----
 lib/Jifty/Plugin/RPC.pm                            |  39 ++++-
 .../Jifty/Plugin/PubSub/web/static/js/pubsub.js    |  19 +--
 7 files changed, 487 insertions(+), 76 deletions(-)
 create mode 100644 lib/Jifty/Plugin/PubSub/Bus.pm

- Log -----------------------------------------------------------------
commit d3057798d80ea490221871b0af6cd11bb3b6d57e
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 21:19:50 2012 -0500

    Rename hpipe to pubsub, to make its use more understandable

diff --git a/lib/Jifty/Plugin/PubSub.pm b/lib/Jifty/Plugin/PubSub.pm
index 24c1391..94f1aab 100644
--- a/lib/Jifty/Plugin/PubSub.pm
+++ b/lib/Jifty/Plugin/PubSub.pm
@@ -59,7 +59,7 @@ sub body_end {
     my $self = shift;
     my $client_id = Jifty->subs->client_id || "";
     $client_id = "'$client_id'" if $client_id;
-    Jifty->web->out( qq|<script type="text/javascript">hpipe_init($client_id)</script>|);
+    Jifty->web->out( qq|<script type="text/javascript">pubsub_init($client_id)</script>|);
 }
 
 sub psgi_app_static {
diff --git a/share/plugins/Jifty/Plugin/PubSub/web/static/js/pubsub.js b/share/plugins/Jifty/Plugin/PubSub/web/static/js/pubsub.js
index 173554a..c69934d 100644
--- a/share/plugins/Jifty/Plugin/PubSub/web/static/js/pubsub.js
+++ b/share/plugins/Jifty/Plugin/PubSub/web/static/js/pubsub.js
@@ -1,8 +1,10 @@
-var hpipe = new Hippie.Pipe();
-jQuery(hpipe).bind("message.jifty.fragment", function (e, d) {
-    hippie_fragment(d);
+var pubsub = new Hippie.Pipe();
+jQuery(pubsub).bind("message.jifty.fragment", function (event, d) {
+    d = prepare_element_for_update(d);
+    if (d == null) return;
+    fragment_updates(d, d['args'], d['content']);
 });
-jQuery(hpipe).bind("message.jifty.result", function (event, d) {
+jQuery(pubsub).bind("message.jifty.result", function (event, d) {
     if (d.error)
         jQuery.jGrowl( d.error, { theme: 'result-error' } );
     else if (d.failure)
@@ -13,14 +15,9 @@ jQuery(hpipe).bind("message.jifty.result", function (event, d) {
         jQuery.jGrowl( d.message, { theme: 'result-message' } );
 });
 
-var hpipe_init = function() {
+var pubsub_init = function() {
     var opt = {path: "/__jifty"};
     if (arguments.length)
         opt.client_id = arguments[0];
-    hpipe.init(opt);
-};
-var hippie_fragment = function(f) {
-    f = prepare_element_for_update(f);
-    if (f == null) return;
-    fragment_updates(f, f['args'], f['content']);
+    pubsub.init(opt);
 };

commit 0b284881140239899aad28ba507160a162d49ab2
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 21:21:26 2012 -0500

    Rename "render_with" key to Jifty->subs->add to the more canonical "path"

diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index 5953098..5f441c1 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -113,7 +113,7 @@ sub region_event {
 
             my $region = Jifty::Web::PageRegion->new(
                 name      => $sub->{region},
-                path      => $sub->{render_with},
+                path      => $sub->{path},
                 arguments => $sub->{arguments},
             );
             $region_name = $region->qualified_name;
@@ -133,7 +133,7 @@ sub region_event {
         $self->send( {
             type    => "jifty.fragment",
             region  => $region_name,
-            path    => $sub->{render_with},
+            path    => $sub->{path},
             args    => $sub->{arguments},
             content => $content,
             mode    => $sub->{mode},
diff --git a/lib/Jifty/Plugin/PubSub/Subscriptions.pm b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
index 1861b2e..5268f1e 100644
--- a/lib/Jifty/Plugin/PubSub/Subscriptions.pm
+++ b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
@@ -45,7 +45,7 @@ sub add {
     my %args = (
         topic              => undef,
         region             => undef,
-        render_with        => undef,
+        path               => undef,
         arguments          => undef,
         mode               => undef,
         element            => undef,
@@ -80,10 +80,10 @@ sub update_on {
     delete $args{region};
     delete $args{event};
     $self->add(
-        arguments   => \%args,
-        mode        => 'Replace',
-        region      => $region->qualified_name,
-        render_with => $region->path,
+        arguments => \%args,
+        mode      => 'Replace',
+        region    => $region->qualified_name,
+        path      => $region->path,
         @_,
     );
 }

commit 2294fd07361583527a38f6466a032001ac0e6d80
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 21:32:24 2012 -0500

    For future-proofing, change prepend "jifty." to internal types from the client

diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index 5f441c1..f00d1a5 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -66,10 +66,8 @@ sub receive {
 sub action_message {
     my $self = shift;
     my $msg = shift;
-    return unless exists $msg->{type}
-        and ($msg->{type} || '') eq "action"
-            and exists $msg->{class}
-                and defined $msg->{class};
+    return unless ($msg->{type} || '') eq "jifty.action"
+        and defined $msg->{class};
 
     my $class = Jifty->api->qualify($msg->{class});
     unless (Jifty->api->is_allowed($class)) {

commit 2029bac5bf148a122eda11caa94f790c5f19a51d
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 21:36:07 2012 -0500

    Add a Jifty AnyMQ subclass which pushes "type" explicitly
    
    If a client subscribes to multiple topics, they have no way of
    differentiating which topic a newly-arrived message came from; as a
    convention, Jifty uses the "type" key of the data to store the topic
    that the message was published on.  Provide an AnyMQ subclass to catch
    data which already uses that key, and to provide an interface which
    papers over the call to ->topic().

diff --git a/lib/Jifty/Plugin/PubSub.pm b/lib/Jifty/Plugin/PubSub.pm
index 94f1aab..e04e185 100644
--- a/lib/Jifty/Plugin/PubSub.pm
+++ b/lib/Jifty/Plugin/PubSub.pm
@@ -7,6 +7,7 @@ use base qw/Jifty::Plugin/;
 use AnyMQ;
 use Plack::Builder;
 use Web::Hippie::App::JSFiles;
+use Jifty::Plugin::PubSub::Bus;
 use Jifty::Plugin::PubSub::Connection;
 use Jifty::Plugin::PubSub::Subscriptions;
 
@@ -29,9 +30,9 @@ sub init {
     $opt{connection} ||= Jifty->app_class({require => 0}, 'PubSub');
     $opt{connection} = 'Jifty::Plugin::PubSub::Connection'
         unless Jifty::Util->try_to_require($opt{connection});
-    $self->{connection} = $opt{connection};
+    $self->{connection} = delete $opt{connection};
 
-    my $anymq = AnyMQ->new_with_traits(
+    my $anymq = Jifty::Plugin::PubSub::Bus->new_with_traits(
         traits => ['AMQP'],
         host   => 'localhost',
         port   => 5672,
diff --git a/lib/Jifty/Plugin/PubSub/Bus.pm b/lib/Jifty/Plugin/PubSub/Bus.pm
new file mode 100644
index 0000000..7ecc04d
--- /dev/null
+++ b/lib/Jifty/Plugin/PubSub/Bus.pm
@@ -0,0 +1,20 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::PubSub::Bus;
+use base qw/ AnyMQ /;
+
+sub publish {
+    my $self = shift;
+    my ($topic, $data) = @_;
+
+    $data ||= {};
+
+    warn "Publish passed data which uses the reserved 'type' key"
+        if exists $data->{type};
+
+    $data->{type} = $topic;
+    $self->topic( $topic )->publish( $data );
+}
+
+1;

commit fdd5c220c340965d7a326b60cbfc264b92cb5f33
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 23:08:55 2012 -0500

    For consistency, force messages sent via ->send to have a type

diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index f00d1a5..82fa1ee 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -51,8 +51,10 @@ sub subscribe {
 
 sub send {
     my $self = shift;
+    my ($type, $data) = @_;
+    $data->{type} = $type;
     Jifty->bus->topic("client." . $self->client_id )
-        ->publish( @_ );
+        ->publish( $data );
 }
 
 sub receive {
@@ -82,8 +84,7 @@ sub action_message {
     $action->run if $action->result->success;
 
     my $result = $action->result->as_hash;
-    $result->{type} = "jifty.result";
-    $self->send($result);
+    $self->send( "jifty.result" => $result);
 
     return 1;
 }
@@ -128,8 +129,7 @@ sub region_event {
             1;
         } or warn "$@";
 
-        $self->send( {
-            type    => "jifty.fragment",
+        $self->send( "jifty.fragment" => {
             region  => $region_name,
             path    => $sub->{path},
             args    => $sub->{arguments},

commit dc1aa828e553750a7f4741979954f45bf59d5961
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 21:38:03 2012 -0500

    Allow Jifty->subs->add( topic => "..." ) for direct-to-client subs
    
    Previously, the canonical way to subscribe the web browser's bus to
    messages on the message bus was to create a YourApp::Connection class:
    
        package YourApp::PubSub;
        use base qw/ Jifty::Plugin::PubSub::Connection /;
        sub connect {
            my $self = shift;
            $self->subscribe( qw/ some_event other_event / );
        }
    
    Also provide a simpler method, for when the subscriptions depend on
    which page is visited, by making use of the existing
    Jifty::Plugin::PubSub::Subscriptions->add method:
    
        Jifty->subs->add( topic => $_ )
            for qw/ some_event other_event /;

diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index 82fa1ee..ff7f947 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -21,8 +21,16 @@ sub new {
     $self->{api} = Jifty::API->new;
     $self->{listener}  = $env->{'hippie.listener'};
     $self->{client_id} = $env->{'hippie.client_id'};
+    $self->{region_subs} = [];
+
+    for my $sub ( @{ Jifty->subs->retrieve($self->client_id) }) {
+        if ( join(" ", keys %{$sub}) eq "topic" ) {
+            $self->subscribe( $sub->{topic} );
+        } else {
+            push @{ $self->{region_subs} }, $sub;
+        }
+    }
 
-    $self->{region_subs} = Jifty->subs->retrieve($self->client_id);
     if ( @{ $self->{region_subs} } ) {
         my @subs = map {$_->{topic}} @{ $self->{region_subs} };
         $self->{region_bus} = Jifty->bus->new_listener;
diff --git a/lib/Jifty/Plugin/PubSub/Subscriptions.pm b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
index 5268f1e..af7da08 100644
--- a/lib/Jifty/Plugin/PubSub/Subscriptions.pm
+++ b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
@@ -35,7 +35,7 @@ sub clear_for {
     my ($region) = @_;
     return unless $self->{client_id};
     $self->{store}{$self->{client_id}} = [
-        grep { $_->{region} ne $region }
+        grep { not exists $_->{region} or $_->{region} ne $region }
             @{$self->{store}{$self->{client_id}} }
         ];
 }

commit 32ca123a51c368811c7cf30911b7931881cc55d5
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 23:04:39 2012 -0500

    Rename some ->new methods to be private

diff --git a/lib/Jifty/Plugin/PubSub.pm b/lib/Jifty/Plugin/PubSub.pm
index e04e185..fb1a8b2 100644
--- a/lib/Jifty/Plugin/PubSub.pm
+++ b/lib/Jifty/Plugin/PubSub.pm
@@ -44,7 +44,7 @@ sub init {
     );
     *Jifty::bus = sub { $anymq };
 
-    my $subs = Jifty::Plugin::PubSub::Subscriptions->new;
+    my $subs = Jifty::Plugin::PubSub::Subscriptions->_new;
     *Jifty::subs = sub { $subs };
 
     Jifty::View->add_trigger(
@@ -86,7 +86,7 @@ sub wrap {
                   my $client_id = $env->{'hippie.client_id'}; # client id
 
                   $connections{$client_id}
-                      ||= $self->{connection}->new($env);
+                      ||= $self->{connection}->_new($env);
                   my $c = $connections{$client_id};
 
                   local $Jifty::WEB = $c->web;
diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index ff7f947..84b2748 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -3,7 +3,9 @@ use warnings;
 
 package Jifty::Plugin::PubSub::Connection;
 
-sub new {
+# This is _new rather than new because it should never be called by
+# external code
+sub _new {
     my $class = shift;
     my $env = shift;
 
diff --git a/lib/Jifty/Plugin/PubSub/Subscriptions.pm b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
index af7da08..acaa1b0 100644
--- a/lib/Jifty/Plugin/PubSub/Subscriptions.pm
+++ b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
@@ -3,7 +3,8 @@ use warnings;
 
 package Jifty::Plugin::PubSub::Subscriptions;
 
-sub new {
+# This is _new rather than new because it is a singleton
+sub _new {
     my $class = shift;
     my $env = shift;
 

commit 4ec0fba30b291bd77445c35b37031cca900f7e64
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 23:09:49 2012 -0500

    Intentionally ignore subscriptions during region push
    
    When regions were rendered in response to events, they had the
    opportunity to attempt to add new subscriptions via Jifty->subs->add.
    However, such calls added to the in-memory store for the client_id that
    had already been fetched -- and thus were lost.  Despite this, two
    different pieces of code attempted to manage the region subscriptions
    during event-triggered region rendering.
    
    Remove the misleading code, and replace it with an explicit mention of
    the missing functionality.

diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index 84b2748..e210247 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -117,8 +117,14 @@ sub region_event {
             # So we don't warn about "duplicate region"s
             local Jifty->web->{'regions'} = {};
             local Jifty->web->{'region_stack'} = [];
-            # So we don't pick up additional subs
-            local Jifty->subs->{region_subs} = [];
+
+            # XXX TODO: the "first page render" method of storing subs
+            # in Jifty->subs doesn't work when we're in the connection
+            # context; no-op all such attempts.  We _can_ nominally
+            # alter them immediately using $self->subscribe, however;
+            # shim in a Jifty->subs which wraps ->add and turns it into
+            # what we do in ->_new
+            local Jifty->subs->{store} = {};
 
             my $region = Jifty::Web::PageRegion->new(
                 name      => $sub->{region},
@@ -126,7 +132,6 @@ sub region_event {
                 arguments => $sub->{arguments},
             );
             $region_name = $region->qualified_name;
-            Jifty->subs->clear_for( $region_name );
 
             $region->enter;
             Jifty->handler->buffer->push( private => 1 );
diff --git a/lib/Jifty/Plugin/PubSub/Subscriptions.pm b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
index acaa1b0..f5daf97 100644
--- a/lib/Jifty/Plugin/PubSub/Subscriptions.pm
+++ b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
@@ -31,15 +31,6 @@ sub client_id {
     return $self->{client_id};
 }
 
-sub clear_for {
-    my $self = shift;
-    my ($region) = @_;
-    return unless $self->{client_id};
-    $self->{store}{$self->{client_id}} = [
-        grep { not exists $_->{region} or $_->{region} ne $region }
-            @{$self->{store}{$self->{client_id}} }
-        ];
-}
 
 sub add {
     my $self = shift;

commit 334b68a8395e249cf667960dc4c87b6daabb2dc1
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 23:19:38 2012 -0500

    Allow plugin configuration of the RPC serialization

diff --git a/lib/Jifty/Plugin/RPC.pm b/lib/Jifty/Plugin/RPC.pm
index 3efe2ba..c2440b8 100644
--- a/lib/Jifty/Plugin/RPC.pm
+++ b/lib/Jifty/Plugin/RPC.pm
@@ -13,10 +13,13 @@ our $VERSION = '0.5';
 our $RPC;
 sub init {
     my $self = shift;
-    my %opt  = @_;
+    my %opt  = (
+        serialize => "Storable",
+        @_,
+    );
 
     $RPC = AnyEvent::RabbitMQ::RPC->new(
-        serialize => "Storable",
+        serialize => $opt{serialize},
         connection => Jifty->bus->_rf,
     );
 

commit 5e7e3f4c66a4be0c2759917365e7c409437a4436
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 21:43:09 2012 -0500

    Add dependencies for the PubSub and RPC plugins

diff --git a/Makefile.PL b/Makefile.PL
index 025944f..c81bb2c 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -115,6 +115,17 @@ feature "Memcached support for serving compressed CSS and JS from Jifty's CAS" =
     recommends('Cache::Memcached' => 1.25),
     ;
 
+feature "Event-based publish/subscribe framework" =>
+    -default => 0,
+    recommends('Web::Hippie'), # Web::Hippie::App::JSFiles
+    ;
+
+feature "RPC support using AMQP" =>
+    -default => 0,
+    recommends('Web::Hippie'), # Web::Hippie::App::JSFiles
+    recommends('AnyEvent::RabbitMQ::RPC'),
+    ;
+
 feature 'Administrative Interface (web)' =>
     -default => 1,
     recommends('Pod::Simple' => 0), # Pod::Simple::Text Pod::Simple::HTML

commit 5d37a0265615cd19beafa799418b64bffdf2d931
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 23:19:52 2012 -0500

    Add documentation for all methods

diff --git a/lib/Jifty/Plugin/PubSub.pm b/lib/Jifty/Plugin/PubSub.pm
index fb1a8b2..a9cbf86 100644
--- a/lib/Jifty/Plugin/PubSub.pm
+++ b/lib/Jifty/Plugin/PubSub.pm
@@ -4,6 +4,120 @@ use warnings;
 package Jifty::Plugin::PubSub;
 use base qw/Jifty::Plugin/;
 
+=head1 NAME
+
+Jifty::Plugin::PubSub - Event-based publish/subscribe framework
+
+=head1 SYNOPSIS
+
+In F<etc/config.yml>:
+
+    Plugins:
+      - PubSub: {}
+
+In a region:
+
+    Jifty->subs->update_on( topic => "some_event" );
+
+In a model:
+
+    Jifty->bus->publish( "some_event" );
+
+=head1 DESCRIPTION
+
+=head2 Generating events
+
+The most basic aspect of event-based communication is the publishing of
+messages.  This is done via:
+
+    Jifty->bus->publish( "some_event" => {
+        some_key  => "data",
+    });
+
+This notifies all subscribers of the C<some_event> class with the
+arbitrary payload specified. See L<AnyMQ> for more details of the
+backend data bus.  The C<type> key of the data provided is reserved for
+internal routing.
+
+
+=head2 Consuming events outside the webserver
+
+C<<Jifty->bus>> is an L<AnyMQ> bus; as such, the standard ways of
+consuming apply here:
+
+    my $listen = Jifty->bus->new_listener;
+    $listen->subscribe( Jifty->bus->topic("some_event") );
+    $listen->poll( sub {
+        my ($data) = @_;
+        warn "Got some event with " . $data->{some_key};
+    }
+    # Loop forever
+    AE::cv->recv;
+
+
+=head2 Pushing updated regions to the client
+
+A region can request that it should be updated in the client when an
+event is received.  At the most basic, this is done via:
+
+    Jifty->subs->update_on( topic => "some_event" );
+
+Events may trigger arbitrary other region updates, using:
+
+    Jifty->subs->add(
+        topic  => "some_event",
+        region => "...",
+        path   => "...",
+        # Any other arguments from Jifty::Form::Element
+    );
+
+When a region is rendered because it was triggered by an event, it will
+be passed the triggering event in an C<event> variable.
+
+
+=head2 Running javascript in the client in response to events
+
+You may also subscribe the web browser directly to events.  This is done
+by calling C<Jifty->subs->add> with no region-relevant arguments, merely
+the C<topic>:
+
+    Jifty->subs->add( topic => $_ ) for qw/ some_event other_event /;
+
+Once the browser is subscribed, the events will be made available via
+the global C<pubsub> object in javascript, and can be consumed via
+C<bind>:
+
+    jQuery(pubsub).bind("message.some_event", function (event, data) {
+        alert(data.some_key);
+    }
+
+=head2 Sending messages from javascript
+
+From javascript in the client, you may also send information back to the
+server via the global C<pubsub> object:
+
+    pubsub.send({type: 'something', data: 'here'}});
+
+In order to act on these responses, create a C<YourApp::PubSub> which
+inherits from L<Jifty::Plugin::PubSub::Connection>, and override
+L<Jifty::Plugin::PubSub::Connection/receive>:
+
+    package YourApp::PubSub;
+    use base qw/ Jifty::Plugin::PubSub::Connection /;
+    sub receive {
+        my $self = shift;
+        my $msg = shift;
+        return 1 if $self->SUPER::receive( $msg );
+        warn "Got some message from the client: " . $msg->{data};
+        return 1;
+    }
+
+Note that, for security reasons, this communication from the web browser
+is B<not> published to the Jifty event bus (though you may opt to
+republish them there so manually).
+
+=cut
+
 use AnyMQ;
 use Plack::Builder;
 use Web::Hippie::App::JSFiles;
@@ -13,6 +127,15 @@ use Jifty::Plugin::PubSub::Subscriptions;
 
 our $VERSION = '0.5';
 
+=head1 METHODS
+
+=head2 init
+
+When initializing the plugin, it accepts any arguments that
+L<AnyMQ/new_with_traits> accepts.
+
+=cut
+
 sub init {
     my $self = shift;
     my %opt  = @_;
@@ -52,10 +175,24 @@ sub init {
     );
 }
 
+=head2 new_request
+
+Part of the L<Jifty::Plugin> interface; clears out the
+L<Jifty::Plugin::PubSub::Subscriptions> on every request.
+
+=cut
+
 sub new_request {
     Jifty->subs->reset;
 }
 
+=head2 body_end
+
+Part of the L<Jifty::Plugin> interface; appends a snippet of javascript
+to start the client-side websocket.
+
+=cut
+
 sub body_end {
     my $self = shift;
     my $client_id = Jifty->subs->client_id || "";
@@ -63,6 +200,13 @@ sub body_end {
     Jifty->web->out( qq|<script type="text/javascript">pubsub_init($client_id)</script>|);
 }
 
+=head2 psgi_app_static
+
+Part of the L<Jifty::Plugin> interface; provides the required static
+javascript.
+
+=cut
+
 sub psgi_app_static {
     my $self = shift;
     my $static_root = $self->static_root;
@@ -72,6 +216,14 @@ sub psgi_app_static {
     };
 }
 
+=head2 wrap
+
+Part of the L<Jifty::Plugin> interface; wraps the application to provide
+websocket support, via L<Web::Hippie>, and binds it to the L<AnyMQ> bus
+via L<Web::Hippie::Pipe>.
+
+=cut
+
 sub wrap {
     my $self = shift;
     my $app = shift;
diff --git a/lib/Jifty/Plugin/PubSub/Bus.pm b/lib/Jifty/Plugin/PubSub/Bus.pm
index 7ecc04d..8be8a62 100644
--- a/lib/Jifty/Plugin/PubSub/Bus.pm
+++ b/lib/Jifty/Plugin/PubSub/Bus.pm
@@ -4,6 +4,29 @@ use warnings;
 package Jifty::Plugin::PubSub::Bus;
 use base qw/ AnyMQ /;
 
+=head1 NAME
+
+Jifty::Plugin::PubSub::Bus - AnyMQ class for Jifty
+
+=head1 DESCRIPTION
+
+This class inherits from L<AnyMQ>, and exists to provide a simpler
+interface to that module.
+
+=head1 METHODS
+
+=head2 publish I<TOPIC> I<DATA>
+
+Jifty uses the C<type> key of data on the L<AnyMQ> bus to track what
+topic the data was originally published on; this method checks that the
+provided I<DATA> doesn't attempt to use that key, and warns if it does.
+It then publishes the given I<DATA> on the I<TOPIC>.
+
+Roughly equivalent to L<AnyMQ/topic> followed by
+L<AnyMQ::Topic/publish>.
+
+=cut
+
 sub publish {
     my $self = shift;
     my ($topic, $data) = @_;
diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index e210247..20fc548 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -3,6 +3,20 @@ use warnings;
 
 package Jifty::Plugin::PubSub::Connection;
 
+=head1 NAME
+
+Jifty::Plugin::PubSub::Connection - Connection to browser
+
+=head1 DESCRIPTION
+
+This class represents a bidirectional channel between the server and the
+web browser.  You may wish to subclass this class as C<YourApp::PubSub>
+to override the L</connect>, L</receive>, or L</disconnect> methods.
+
+=head1 METHODS
+
+=cut
+
 # This is _new rather than new because it should never be called by
 # external code
 sub _new {
@@ -46,19 +60,63 @@ sub _new {
     return $self;
 }
 
+=head2 web
+
+Returns the constructed L<Jifty::Web> object which is seen as
+C<Jifty->web> whenever in the context of this connection's L</connect>,
+L</receive>, L</disconnect>, or when page regions are rendered to be
+sent over this channel.  This ensures that C<Jifty->web->current_user>
+is set whenever it is relevant.
+
+=head2 api
+
+A new L<Jifty::API> object is instantiated for each
+L<Jifty::Plugin::PubSub::Connection> object.  You may wish to limit it
+to limit which actions can be performed by the web browser.
+
+=head2 listener
+
+The L<AnyMQ::Queue> object which listens to events for the client.
+
+=head2 client_id
+
+Returns a unique identifier associated with this connection.
+
+=cut
+
 sub web       { shift->{web} }
 sub api       { shift->{api} }
 sub listener  { shift->{listener} }
 sub client_id { shift->{client_id} }
 
+=head2 connect
+
+Called when a connection is established from the browser.  By default,
+does nothing.
+
+=cut
+
 sub connect {}
 
+=head2 subscribe I<TOPIC> [, I<TOPIC>, ...]
+
+Subscribes the browser to receive messages on the given topics.
+
+=cut
+
 sub subscribe {
     my $self = shift;
     $self->{listener}->subscribe( $_ )
         for map { Jifty->bus->topic( $_) } @_;
 }
 
+=head2 send I<TYPE> I<DATA>
+
+Sends an arbitrary message to the browser.  It is not published to the
+rest of the message bus.
+
+=cut
+
 sub send {
     my $self = shift;
     my ($type, $data) = @_;
@@ -67,6 +125,21 @@ sub send {
         ->publish( $data );
 }
 
+=head2 receive I<DATA>
+
+Called when a message is received from the web browser; returns true if
+the message was processed, false otherwise.  If you override this
+method, be sure you respect this class' return value:
+
+    sub receive {
+        my $self = shift;
+        my $msg = shift;
+        return 1 if $self->SUPER::receive( $msg );
+        # ...
+    }
+
+=cut
+
 sub receive {
     my $self = shift;
     my $msg = shift;
@@ -75,6 +148,13 @@ sub receive {
     return;
 }
 
+=head2 action_message I<DATA>
+
+Creates, validates, and runs an action if it was received by the client;
+called by L</receive>.
+
+=cut
+
 sub action_message {
     my $self = shift;
     my $msg = shift;
@@ -99,6 +179,15 @@ sub action_message {
     return 1;
 }
 
+=head2 region_event I<EVENT>
+
+Called when one or more regions on the page needs to be rendered and
+pushed to the client, as triggered by an event.  The rendered regions
+will be passed I<EVENT> as an C<event> variable.  Currently, rendered
+regions cannot alter the client's subscription set.
+
+=cut
+
 sub region_event {
     my $self = shift;
     my $event = shift;
@@ -162,6 +251,14 @@ sub region_event {
         for map {Jifty->bus->topic($_)} @subs;
 }
 
+=head2 disconnect
+
+Called when the connection to the browser is lost when the browser
+switches to a new page.  This is not immediate, but occurs after a
+15-second timeout.
+
+=cut
+
 sub disconnect {
     my $self = shift;
     if ($self->{region_bus}) {
diff --git a/lib/Jifty/Plugin/PubSub/Subscriptions.pm b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
index f5daf97..0145abe 100644
--- a/lib/Jifty/Plugin/PubSub/Subscriptions.pm
+++ b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
@@ -3,6 +3,42 @@ use warnings;
 
 package Jifty::Plugin::PubSub::Subscriptions;
 
+=head1 NAME
+
+Jifty::Plugin::PubSub::Subscriptions - Manage browser event subscriptions
+
+=head1 DESCRIPTION
+
+This class is a global cache of the outstanding subscriptions of
+requests.  When a page is rendered, it may choose to add subscriptions
+via L</update_on> or L</add>:
+
+    # Update the current region on an event
+    Jifty->subs->update_on( topic => "some_event" );
+
+or:
+
+    # Send this topic of events to the browser
+    Jifty->subs->add( topic => "some_event" );
+
+These subscriptions are not done in the I<rendering> request, but must
+be stored until the websocket connection occurs later; this class
+manages that storage.
+
+The storage is currently an I<in-memory> store which I<does not purge
+old subscriptions>.  This means that if a page with subscriptions is
+requested 1000 times, but the websocket for them is never established,
+those subscriptions will be stored until the server is restarted.  In
+the future, these subscriptions may be stored on the session, and
+expired in conjunction.
+
+The only expected interaction with this module is via L</update_on> and
+L</add>.
+
+=head1 METHODS
+
+=cut
+
 # This is _new rather than new because it is a singleton
 sub _new {
     my $class = shift;
@@ -15,22 +51,51 @@ sub _new {
     return $self;
 }
 
+=head2 reset
+
+Called internally once per request to reset for the next request.
+
+=cut
+
 sub reset {
     my $self = shift;
     $self->{client_id} = undef;
 }
 
+=head2 retrieve I<CLIENT_ID>
+
+Returns the data structure of subscriptions for the given I<CLIENT_ID>,
+and removes it such that it is not accessible to future requests.
+
+=cut
+
 sub retrieve {
     my $self = shift;
     my $client_id = shift;
     return delete $self->{store}{$client_id} || [];
 }
 
+
+=head2 client_id
+
+Returns the assigned I<CLIENT_ID> of the current connection.  This is
+C<undef> if the client has not been assigned any subscriptions yet.
+
+=cut
+
 sub client_id {
     my $self = shift;
     return $self->{client_id};
 }
 
+=head2 add topic => I<TOPIC> [, ...]
+
+Adds a subscription.  If only the I<TOPIC> is given, the event will be
+passed through to the web browser to interpret.  Otherwise, the
+arguments are used similarly to L<Jifty::Web::Element> to determine
+which region to update, and how.
+
+=cut
 
 sub add {
     my $self = shift;
@@ -60,6 +125,12 @@ sub add {
     push @{$self->{store}{$self->{client_id}}}, \%args;
 }
 
+=head2 update_on topic => I<TOPIC> [, ...]
+
+As L</add>, but defaults to refreshing the current region.
+
+=cut
+
 sub update_on {
     my $self = shift;
     my $region = Jifty->web->current_region;
diff --git a/lib/Jifty/Plugin/RPC.pm b/lib/Jifty/Plugin/RPC.pm
index c2440b8..0c2abe0 100644
--- a/lib/Jifty/Plugin/RPC.pm
+++ b/lib/Jifty/Plugin/RPC.pm
@@ -4,12 +4,44 @@ use warnings;
 package Jifty::Plugin::RPC;
 use base qw/Jifty::Plugin/;
 
+=head1 NAME
+
+Jifty::Plugin::RPC - Use AMQP for RPC
+
+=head1 SYNOPSIS
+
+    Jifty->rpc->call( name => "remote-method" );
+
+=head1 DESCRIPTION
+
+L<Jifty::Plugin::PubSub> interfaces with an L<AnyEvent::RabbitMQ>
+connection to provide a message bus.  This provides C<Jifty->rpc> which
+implements an L<AnyEvent::RabbitMQ::RPC> using that connection; see that
+module for complete documentation.
+
+=head1 METHODS
+
+=head2 prereq_plugins
+
+Use of this plugin requires (or implicitly loads, if missing) the
+L<Jifty::Plugin::PubSub> plugin.
+
+=cut
+
 use AnyEvent::RabbitMQ::RPC;
 
 sub prereq_plugins { 'PubSub' }
 
 our $VERSION = '0.5';
 
+=head2 init
+
+This plugin has one configuration option, C<serialize>, which defaults
+to C<Storable>.  See L<AnyEvent::RabbitMQ::RPC> for documentation on the
+possible alternatives.
+
+=cut
+
 our $RPC;
 sub init {
     my $self = shift;

commit 70b4e0b87215303dc71f9e7cc98b6a6c3a2e7b2e
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Sun Nov 4 23:22:16 2012 -0500

    Reorder methods to read more logically in POD

diff --git a/lib/Jifty/Plugin/PubSub/Connection.pm b/lib/Jifty/Plugin/PubSub/Connection.pm
index 20fc548..61895fc 100644
--- a/lib/Jifty/Plugin/PubSub/Connection.pm
+++ b/lib/Jifty/Plugin/PubSub/Connection.pm
@@ -60,35 +60,6 @@ sub _new {
     return $self;
 }
 
-=head2 web
-
-Returns the constructed L<Jifty::Web> object which is seen as
-C<Jifty->web> whenever in the context of this connection's L</connect>,
-L</receive>, L</disconnect>, or when page regions are rendered to be
-sent over this channel.  This ensures that C<Jifty->web->current_user>
-is set whenever it is relevant.
-
-=head2 api
-
-A new L<Jifty::API> object is instantiated for each
-L<Jifty::Plugin::PubSub::Connection> object.  You may wish to limit it
-to limit which actions can be performed by the web browser.
-
-=head2 listener
-
-The L<AnyMQ::Queue> object which listens to events for the client.
-
-=head2 client_id
-
-Returns a unique identifier associated with this connection.
-
-=cut
-
-sub web       { shift->{web} }
-sub api       { shift->{api} }
-sub listener  { shift->{listener} }
-sub client_id { shift->{client_id} }
-
 =head2 connect
 
 Called when a connection is established from the browser.  By default,
@@ -148,6 +119,52 @@ sub receive {
     return;
 }
 
+=head2 disconnect
+
+Called when the connection to the browser is lost when the browser
+switches to a new page.  This is not immediate, but occurs after a
+15-second timeout.
+
+=cut
+
+sub disconnect {
+    my $self = shift;
+    if ($self->{region_bus}) {
+        $self->{region_bus}->timeout(0);
+        $self->{region_bus}->unpoll;
+        undef $self->{region_bus};
+    };
+}
+
+=head2 web
+
+Returns the constructed L<Jifty::Web> object which is seen as
+C<Jifty->web> whenever in the context of this connection's L</connect>,
+L</receive>, L</disconnect>, or when page regions are rendered to be
+sent over this channel.  This ensures that C<Jifty->web->current_user>
+is set whenever it is relevant.
+
+=head2 api
+
+A new L<Jifty::API> object is instantiated for each
+L<Jifty::Plugin::PubSub::Connection> object.  You may wish to limit it
+to limit which actions can be performed by the web browser.
+
+=head2 listener
+
+The L<AnyMQ::Queue> object which listens to events for the client.
+
+=head2 client_id
+
+Returns a unique identifier associated with this connection.
+
+=cut
+
+sub web       { shift->{web} }
+sub api       { shift->{api} }
+sub listener  { shift->{listener} }
+sub client_id { shift->{client_id} }
+
 =head2 action_message I<DATA>
 
 Creates, validates, and runs an action if it was received by the client;
@@ -251,21 +268,4 @@ sub region_event {
         for map {Jifty->bus->topic($_)} @subs;
 }
 
-=head2 disconnect
-
-Called when the connection to the browser is lost when the browser
-switches to a new page.  This is not immediate, but occurs after a
-15-second timeout.
-
-=cut
-
-sub disconnect {
-    my $self = shift;
-    if ($self->{region_bus}) {
-        $self->{region_bus}->timeout(0);
-        $self->{region_bus}->unpoll;
-        undef $self->{region_bus};
-    };
-}
-
 1;
diff --git a/lib/Jifty/Plugin/PubSub/Subscriptions.pm b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
index 0145abe..ed43ca7 100644
--- a/lib/Jifty/Plugin/PubSub/Subscriptions.pm
+++ b/lib/Jifty/Plugin/PubSub/Subscriptions.pm
@@ -51,43 +51,6 @@ sub _new {
     return $self;
 }
 
-=head2 reset
-
-Called internally once per request to reset for the next request.
-
-=cut
-
-sub reset {
-    my $self = shift;
-    $self->{client_id} = undef;
-}
-
-=head2 retrieve I<CLIENT_ID>
-
-Returns the data structure of subscriptions for the given I<CLIENT_ID>,
-and removes it such that it is not accessible to future requests.
-
-=cut
-
-sub retrieve {
-    my $self = shift;
-    my $client_id = shift;
-    return delete $self->{store}{$client_id} || [];
-}
-
-
-=head2 client_id
-
-Returns the assigned I<CLIENT_ID> of the current connection.  This is
-C<undef> if the client has not been assigned any subscriptions yet.
-
-=cut
-
-sub client_id {
-    my $self = shift;
-    return $self->{client_id};
-}
-
 =head2 add topic => I<TOPIC> [, ...]
 
 Adds a subscription.  If only the I<TOPIC> is given, the event will be
@@ -151,4 +114,40 @@ sub update_on {
     );
 }
 
+=head2 client_id
+
+Returns the assigned I<CLIENT_ID> of the current connection.  This is
+C<undef> if the client has not been assigned any subscriptions yet.
+
+=cut
+
+sub client_id {
+    my $self = shift;
+    return $self->{client_id};
+}
+
+=head2 reset
+
+Called internally once per request to reset for the next request.
+
+=cut
+
+sub reset {
+    my $self = shift;
+    $self->{client_id} = undef;
+}
+
+=head2 retrieve I<CLIENT_ID>
+
+Returns the data structure of subscriptions for the given I<CLIENT_ID>,
+and removes it such that it is not accessible to future requests.
+
+=cut
+
+sub retrieve {
+    my $self = shift;
+    my $client_id = shift;
+    return delete $self->{store}{$client_id} || [];
+}
+
 1;

-----------------------------------------------------------------------


More information about the Jifty-commit mailing list