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.callback |
hub.mode |
hub.topic |
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 |
hub.topic |
hub.challenge |
これにたいして、レスポンスは 200 OK で、content body に hub.challenge をそのままいれてやればよい。
subscriber には有効期限が設定されており、期限がおわったら、再度確認リクエストがくるので、その時にもちゃんと応答してやらなくてはならない。
"*.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 で実装可能であるから、デーモンの数が増えないのが利点のひとつだとかんじた。
【追記】
フィードを処理した後のところのレスポンスを追加。