The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Mojolicious::Plugin::PubSubHubbub - Publish and Subscribe with PubSubHubbub

SYNOPSIS

  # Mojolicious
  $app->plugin(PubSubHubbub => {
    hub => 'https://hub.example.org/',
    pubsub_verify => sub {
      return 1;
    }
  });

  my $r = $app->routes;
  $r->route('/:user/callback_url')->pubsub;

  # Mojolicious::Lite
  plugin 'PubSubHubbub' => {
    hub => 'https://hub.example.org'
  };

  any('/:user/callback_url')->pubsub;

  # In Controllers:
  # Publish feeds
  $c->pubsub_publish(
    'https://sojolicio.us/blog.atom',
    'https://sojolicio.us/activity.atom'
  );

  # Subscribe to a feed
  $c->pubsub_subscribe(
    topic => 'https://sojolicio.us/feed.atom',
    hub   => 'https://hub.sojolicio.us'
  );

  # Discover a resource
  my ($topic, $hub) = $c->pubsub_discover('http://sojolicio.us/');
  if ($topic && $hub) {
    $c->pubsub_subscribe( topic => $topic, hub   => $hub );
  };

  # Unsubscribe from a feed
  $c->pubsub_unsubscribe(
    topic => 'https://sojolicio.us/feed.atom',
    hub   => 'https://hub.sojolicio.us'
  );

DESCRIPTION

Mojolicious::Plugin::PubSubHubbub is a plugin to publish and subscribe to PubSubHubbub 0.3 Webhooks.

The plugin currently supports the publisher and subscriber part of the protocol, not the hub part.

This plugin is data store agnostic. Please use this plugin by applying hooks and callbacks.

This module is an early release! There may be significant changes in the future.

ATTRIBUTES

hub

  $ps->hub('http://pubsubhubbub.appspot.com/');
  my $hub = $ps->hub;

The preferred hub. Currently local hubs are not supported. Establishes an endpoint called pubsub-hub.

Defaults to pubsubhubbub.appspot.com, but this may change without notification.

lease_seconds

  my $seconds = $ps->lease_seconds;
  $ps->lease_seconds(100 * 24 * 60 * 60);

Seconds a subscription is valid by default before auto refresh is enabled. You can not rely on auto refresh by the hub - your subscriber should resubscribe automatically, if the hub does not ask for renewal.

Defaults to 9 days.

METHODS

register

  # Mojolicious
  $app->plugin(PubSubHubbub => {
    hub => 'https://hub.example.org/',
    lease_seconds => 100 * 24 * 60 * 60
  });

  # Mojolicious::Lite
  plugin 'PubSubHubbub' => {
    hub => 'https://hub.example.org/',
    lease_seconds => 100 * 24 * 60 * 60
  };

  # Or in your config file
  {
    PubSubHubbub => {
      hub => 'https://hub.example.org/',
      lease_seconds => 100 * 24 * 60 * 60
    }
  }

Called when registering the plugin. Accepts the attributes mentioned as parameters. All parameters can be set either on registration or as part of the configuration file with the key PubSubHubbub.

SHORTCUTS

pubsub

  # Mojolicious
  my $r = $app->routes;
  $r->route('/callback_url')->pubsub;

  # Mojolicious::Lite
  any('/callback_url')->pubsub;

Define the callback endpoint for your subscriptions. Establishes an endpoint called pubsub-callback.

HELPERS

pubsub_discover

  # In Controllers
  my ($topic, $hub) = $c->pubsub_discover('http://sojolicio.us/');

Discover a topic feed and a hub based on a URI. The discovery heuristics may change without notification.

pubsub_publish

  # In Controllers
  $c->pubsub_publish(
    'my_feed',                       # named route
    '/feed.atom',                    # relative paths
    'https://sojolicio.us/feed.atom' # absolute URIs
  );

Publish a list of feeds in terms of a notification to the hub. Supports endpoints, named routes, relative paths and absolute URIs.

pubsub_subscribe

  # In Controllers
  if ($c->pubsub_subscribe(
    topic => 'https://sojolicio.us/feed.atom',
    hub   => 'https://hub.sojolicio.us' );
    lease_seconds => 123456
  )) {
    print 'You successfully subscribed!';
  };

Subscribe to a topic.

Relevant parameters are hub, lease_seconds, secret, verify_token, and callback. Additional parameters are ignored but can be accessed in the hooks. If no verify_token is given, it is automatically generated. If no callback is given, the route callback is used. If no lease_seconds is given, the subscription won't automatically terminate. If a secret is given, it must be unique for every callback and hub combination to allow for bulk distribution.

The method returns a true value on success and a false value if an error occured. If called in an array context, the hub's response message body is returned additionally.

pubsub_unsubscribe

  # In Controllers
  if ($c->pubsub_unsubscribe(
    topic => 'https://sojolicio.us/feed.atom',
    hub   => 'https://hub.sojolicio.us'
  )) {
    print 'You successfully unsubscribed!';
  };

Unsubscribe from a topic.

Relevant parameters are hub, secret, verify_token, and callback. Additional parameters are ignored but can be accessed in the hooks. If no verify_token is given, it is automatically generated. If no callback is given, the route callback is used.

The method returns a true value on success and a false value if an error occured. If called in an array context, the hub's response message body is returned additionally.

CALLBACKS

pubsub_accept

  # Establish callback
  $app->callback(
    pubsub_accept => sub {
      my ($c, $type, $topics) = @_;

      # Filter topics
      my @new_topics = grep($_ !~ /catz/, @$topics);

      # Set secret
      my $secret     = 'z0idberg';

      # Set X-Hub-On-Behalf-Of value
      my $on_behalf  = 3;
      return (\@new_topics, $secret, $on_behalf);
    });

This callback is released, when content arrives at the pubsub endpoint. The parameters passed to the callback include the current controller object, the content type, and an array reference of topics.

Expects an array reference of maybe filtered topics, a secret if necessary, and the value of X-Hub-On-Behalf-Of. If the returned topic list is empty, the processing will stop. If the callback is not established, the complete content will be processed.

The callback can be established with the callback helper or on registration.

pubsub_verify

  # Establish callback
  $app->callback(
    pubsub_verify => sub {
      my ($c, $param) = @_;

      # Topic is valid
      if ($param->{topic} =~ /catz/ &&
          $param->{verify_token} eq 'zoidberg') {
        return 1;
      };

      # Not verified
      return;
    });

This callback is released, when a verification is requested. The parameters include the current controller object and the parameters of the verification request as a hash reference (without hub.-prefix). If verification is granted, this callback must return a true value.

The callback can be established with the callback helper or on registration.

HOOKS

on_pubsub_content

  $app->hook(
    on_pubsub_content => sub {
      my ($c, $type, $dom) = @_;

      if ($type eq 'atom') {
        $dom->find('entry')->each(
          print $_->at('title')->text, "\n";
        );
      };

      return;
    });

This hook is released, when desired (i.e., verified and optionally filtered) content arrives. The parameters include the current controller object, the content type (either atom or rss), and the - maybe topic filtered - content as a Mojo::DOM object.

The Mojo::DOM object is canonicalized in a way that each entry in the feed (either RSS or Atom) includes its topic in the href of source > link[rel="self"].

before_pubsub_subscribe

  $app->hook(
    before_pubsub_subscribe => sub {
      my ($c, $params, $post) = @_;

      my $topic = $params->{topic};
      print "Start following $topic\n";

      return;
    });

This hook is released, before a subscription request is sent to a hub. The parameters include the current controller object, the parameters prepared for subscription as a hash reference and the POST string as a string reference. This hook can be used to store subscription information and establish a secret.

after_pubsub_subscribe

  $app->hook(
    after_pubsub_subscribe => sub {
      my ($c, $hub, $params, $status, $body) = @_;
      if ($status !~ /^2/) {
        warn 'Error: ', $body;
      };

      return;
    });

This hook is released, after a subscription request is sent to a hub and the response is processed. The parameters include the current controller object, the hub location, the parameters sent for subscription as a hash reference, the response status, and the response body. This hook can be used to deal with errors.

before_pubsub_unsubscribe

  $app->hook(
    before_pubsub_unsubscribe => sub {
      my ($c, $params, $post) = @_;

      my $topic = $params->{topic};
      print "Stop following $topic\n";

      return;
    });

This hook is released, before an unsubscription request is sent to a hub. The parameters include the current controller object, the parameters prepared for unsubscription as a hash reference and the POST string as a string reference. This hook can be used to store unsubscription information.

after_pubsub_unsubscribe

  $app->hook(
    after_pubsub_unsubscribe => sub {
      my ($c, $hub, $params, $status, $body) = @_;
      if ($status !~ /^2/) {
        warn 'Error: ', $body;
      };

      return;
    });

This hook is released, after an unsubscription request is sent to a hub and the response is processed. The parameters include the current controller object, the hub location, the parameters sent for unsubscription as a hash reference, the response status, and the response body. This hook can be used to deal with errors.

EXAMPLE

The examples/ folder contains a full working example application with publishing, subscription and discovery logic. The example has additional dependencies of DBI, DBD::SQLite and XML::Loy (at least v0.13).

It can be started using the daemon, morbo or hypnotoad, and needs to be accessible from the web.

  $ perl examples/pubsubapp daemon

PubSubHubbub Example Application

This example may be a good starting point for your own implementation, especially, if you deal with the subscriber part.

TODO

Currently all methods are blocking. In an upcoming release all blocking methods will allow for non-blocking as well.

DEPENDENCIES

Mojolicious (best with SSL support), Mojolicious::Plugin::Util::Endpoint, Mojolicious::Plugin::Util::Callback, Mojolicious::Plugin::Util::RandomString.

AVAILABILITY

  https://github.com/Akron/Mojolicious-Plugin-PubSubHubbub

This plugin is part of the Sojolicious project.

COPYRIGHT AND LICENSE

Copyright (C) 2011-2014, Nils Diewald.

This program is free software, you can redistribute it and/or modify it under the terms of the Artistic License version 2.0.