Blog

リアルタイムWebのためのPubSubHubbub の Subscriber を構築する方法

PubSubHubbub(以下PuSH)は、フィードの更新をリアルタイムに通知するためのプロトコルである。
ウェブ上にころがっている"PuSH"の情報は、"Pub" の部分を実装する方法か、「PubSubHubbub の本家GAE実装を手元でうごかしてみたよ」という記事しかなくて、"Sub"を実装する方法について解説しているブログなどはみあたらなかったので、ここに記す(英語だといくつかあった)。

基本的に、ほとんどの人が興味あるのは "Pub" の部分である。自分のブログの更新情報等をリアルタイムにおくりつけたいと考えるからである。実際、ほとんどのブログソフトウェアではすでに PuSH 対応がすんでいる。see MT-PuSH, etc.

しかし、私は今まさに Subscriber をつくりたいとおもったのである。なぜならば、"friendfeed.com/cpan" の更新情報を PuSH でうけとり、リアルタイムに手元の情報を更新しようとおもったからである。

さて、"Sub" の部分については、いくつかのライブラリ実装もあるようだ。しかし、Perl のものはない。なんでだろう。
http://code.google.com/p/pubsubhubbub/wiki/SubscriberClients

というわけで、しょうがないのでプロトコル仕様を読む。
http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html

以下のようなフローで購読処理が完了するようだ。

処理の方法

サブスクライブ要求を hub にだす。
hub.callbackコールバックURL
hub.mode"subscribe" または "unsubscribe" という文字列
hub.topic購読したいフィードの URL
hub.verify自分がおくった文字列かどうかを確認するための秘密の文字列

(他にもoptionalな項目がいくつかある)

この部分は、URL を生成して HTTP Request をなげてつかう。

しかし、リファレンス実装の GAE hub には、これをおくるための web ui がついているので、これを利用するのが簡単だ。https://pubsubhubbub.appspot.com/subscribe

hub は、204 no content を返すので、submit ボタンをおしてもなにも変化しないことに注意。ボタンをおしたら、callback url にリクエストがとんでくるはずである。

確認リクエストがとんでくるので、これを処理する

hub は、スパム防止のために、sub にたいして「本当におまえがおくったんけ?」というリクエストをなげる。

そのリクエストには以下の項目がふくまれる(optionalな項目は省略)。

hub.mode"subscribe"という文字列
hub.topic購読対象のURL
hub.challengehubが生成したランダムな文字列

これにたいして、レスポンスは 200 OK で、content body に hub.challenge をそのままいれてやればよい。

定期的な確認

subscriber には有効期限が設定されており、期限がおわったら、再度確認リクエストがくるので、その時にもちゃんと応答してやらなくてはならない。

Perl による簡単な実装例

"*.psgi" 形式による簡単な疑似コードをここに紹介する。

use Plack::Request;
use XML::Feed;
sub {
  my $req = Plack::Request->new();
  if ($req->param('hub.mode') eq 'subscribe') {
    my $topic = $req->param('hub.topic');
    my $challenge = $req->param('hub.challenge');
    if ($topic eq 'ここに購読したいURLを書く') {
       return [200, [], [$challenge]];
    } else {
       return [500, [], ["unknown feed"]];
    }
  } else {
    # 実際のフィードにたいする処理はここにかく
    my $feed = XML::Feed->parse(\($req->content));
    ...
    return [200, [], ["OK"]]; # 2xx をかえして成功をつげる。
  }
}

ここにいたり、なぜ "Sub" のライブラリが Perl に無いのかを知る。そう。必要ないのだ。

まとめ

PubSubHubbub の "Sub" の実装について解説した。今回の場合、friendfeed からの情報取得だったので、realtime streaming API を利用してもよかったのだが、更新頻度がそれほどないフィードであること、より汎用的なプロトコルであうことから PubSubHubbub を利用することにした。
PubSubHubbub の場合、webhook で実装可能であるから、デーモンの数が増えないのが利点のひとつだとかんじた。

【追記】
フィードを処理した後のところのレスポンスを追加。