UserLand が運営する Weblogs.Com は MovableType などのウェブログツールから、Ping と呼ばれる更新通知を受信して、ウェブログの更新情報を XML で配信しているサイトです。Ping の送受信には SOAP や XML-RPC が使われます。大袈裟に言うと、ウェブサービスですね。
Weblogs.Com Ping は仕様が公開されており、Weblogs.Com 以外にも Ping を受け付けるプログラムを実装したサイトはたくさんあります。国内ですと、先日サービスインした Myblog Japan、dh's memoranda の hirata さんによる ping.bloggers.jp などがあります。
BlogShares や BlogRolling、BlogMatcher といったメタブログサービスは、Weblogs.Com を始めとする各 Ping サイトが公開するウェブログ更新情報を元にウェブログを巡回したり、ウェブログの更新通知を行うようになっています。
物は試しにと、Ping サーバを Perl で実装してみました。(公開目的ではなく、実験目的です。)
とりあえず今回は実装が簡単そうな XML-RPC インタフェースのみ考慮しました。XML-RPC インタフェースの仕様は Weblogs.Com XML-RPC interface で公開されています。かなりシンプルな仕様になっています。
Ping する側は、Ping サーバに対して HTTP POST、Content-Type: text/xml で以下の様なリクエストを送信します。
<?xml version="1.0"?>
<methodCall>
<methodName>weblogUpdates.ping</methodName>
<params>
<param>
<value>NDO::Weblog</value>
</param>
<param>
<value>http://naoya.dyndns.org/~naoya/mt/</value>
</param>
</params>
</methodCall>
これは XML-RPC によるメソッド呼び出しのフォーマットで、関数風に書くと、weblogUpdates.ping("NDO::Weblog", "http://naoya.dyndns.org/~naoya/mt/") に等しくなっています。第一引数にウェブログの名前、第二引数にウェブログのURLを渡すよう仕様で決められています。
このリクエストを受信したサーバーは、引数を使って任意の処理をした後、以下のリクエストを Ping 送信元に返却します。
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>flerror</name>
<value>
<boolean>0</boolean>
</value>
</member>
<member>
<name>message</name>
<value>Thanks for the ping</value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>
返却される値は構造体を XML-RPC 規則に則ってシリアライズしたものになります。名前が flerror で値が boolean 型、名前が message で値が string 型の二つのメンバで構成される構造体を返却します。flerror が Ping 処理の成否を判定するための返値で、false のときは処理が成功したとみなされます。もし何かしらのエラーを送信元に通知したい場合は、flerror を true (boolean 1)、messags にエラー内容を記述して返却します。
XML-RPC インタフェースの仕様はこの二点のみ。
Perl で XML-RPC インタフェースを実装する場合、色々方法は考えられますが、CPAN の XMLRPC::Transport::HTTP を使うのが簡単です。XMLRPC::Transport::HTTP は SOAP::Lite ディストリビューションに含まれるので、SOAP::Lite をインストールすれば一緒に入ってきます。
サンプルコードは以下のようになります。
#!/usr/local/bin/perl
use strict;
use warnings;
use XMLRPC::Transport::HTTP;
XMLRPC::Transport::HTTP::CGI->dispatch_to('weblogUpdates')->handle;
package weblogUpdates;
sub ping {
my $self = shift;
my ($name, $url) = @_;
# ここに何かしらの処理を書く
return { flerror => XMLRPC::Data->type('boolean', 0),
message => "Thanks for the ping" };
}
XML::RPC::Transport::HTTP を使うと XML-RPC サーバが作れますが、サーバを CGI プログラムとして実装することもできるし、スタンドアロンのデーモンとして実装することもできます。ここでは CGI プログラムとして実装しました。
パッケージ weblogUpdates を XML::RPC::Transport::HTTP::CGI->dispatch でディスパッチし、weblogUpdates パッケージに ping メソッドを用意します。この ping メソッドが、先ほどの weblogUpdates.ping("NDO::Weblog", "http://naoya.dyndns.org/~naoya/mt/") に相当します。引数としてウェブログの名前、ウェブログのURLを受け取っています。それぞれの値には、Ping リクエストに含まれている値がちゃんと代入されてきます。
返却する値としてハッシュのリファレンス返せば、XML::RPC::Transport が返却値のシリアライズや XML レスポンスの作成などをやってくれます。楽ちんです。boolean 型を明示的に指定するために XMLRPC::Data->type を使ってます。(明示的に指定しないと自動で判定してくれますが、整数は int 型になってしまうので。)
実験のための簡単な Ping クライアントも実装してみます。クライアントも同じく CPAN モジュールを使えば簡単にできます。SOAP::Lite に含まれる XMLRPC::Lite でもいいですが、ここでは敢えて Frontier::Client を使ってみます。
#!/usr/local/bin/perl
use strict;
use warnings;
use Frontier::Client;
my $server = Frontier::Client->new( url => 'http://localhost/some/where/ping.cgi',
debug => 1);
my $result = $server->call('weblogUpdates.ping',
'NDO::Weblog',
'http://naoya.dyndns.org/~naoya/mt/');
for my $key (keys %$result) {
print $key, ": ", $result->{$key}, "\n";
}
Frontier::Client のコンストラクタの引数に、先ほど書いた CGI プログラム (ここでは ping.cgi ) の URL を指定します。(CGI として正しく動作する場所に設置すること。) あとは、Frontier::Client の call メソッドを使って、XML-RPC 呼び出しを行うのみ。第一引数が XML-RPC メソッド名、以降がそれに与える引数となります。構造体の返却値はハッシュリファレンスで返ってくるので、デリファレンスしていじるのみ。クライアントを実行して "Thanks for the ping" が出力されたら成功です。
なお、Frontier::Client のコンストラクタの引数として debug => 1 としておくと、XML-RPC リクエスト、レスポンスが出力されるので便利です。
# CPAN って素晴らしい。:)
もちろん、この Ping サーバには MovableType などのウェブログツールから Ping (TrackBack Ping ではないです。) を打つことができます。まだ Ping サーバには何も処理を行わせていないので、これだと送信しても無意味ですけど。
Weblogs.Com では Ping 受信結果をアグリゲーションして changes.xml として公開してます。changes.xml の仕様も公開されているので、Ping を受信して、新しい更新情報をもとに changes.xml を更新する処理を書けば自前 Weblogs.Com の完成です。
changes.xml についてと、その処理方法については明日にでも記述します。