Wassr というすばらしいサイトがあるのですが、そのサイトでは XMPP でユーザーの更新情報を得ることができたり、発言情報をえたりできます。
このサイトで、それを実現させているのは、bradfitz の DJabberd というソフトウェアみたいです。これを使うと、容易に XMPP Server を構築することができます。Perl でできているので、割と簡単につくれます。もちろん bradware なので、bradware っぽい感じではあります。わからないことがあったら Livejournal のコードを読む必要があるので要注意です。
DJabberd は Danga::Socket を使った IO 多重化の1スレッドで動いています。Danga::Socket で構築されていますので、Gearman::Client::Async を使うことができます。というか、基本的に重い処理はすべて Gearman にやらせるようにしないと、サーバーがふんづまりますので、基本的にはすべての処理は Gearman にやらせるようにします。
さて、そんな DJabberd ですが、Wassr では
- Wassr::DJabberd::RosterStorageAlwaysBoth
- Wassr::DJabberd::Bot
- Wassr::DJabberd::AdminExtension
という3つのモジュールを定義しているようです。
RosterStorageAlwaysBoth というのは、とりあえず話しかけてきた人を全員友達扱いにします。
Bot は、その名のとおりボットのコアです。DJabberd::Bot を継承しています。DJabberd::Bot はソース読まないと使い方わからないので、がんばって解読します。基本的には process_text というメソッドを上書きすればいい。それだけです。
# $text is flagged utf8.
# $from is DJabberd::JID
# $from->as_bare_string; : jid string
# $ctx is DJabberd::BotContext
# $ctx->reply required 'flagged utf8 string'
というような引数の状況でよばれます。jid というのは、Jabber ID の略で、ユーザーの識別符号ですね。DJabberd の中では DJabberd::JID というオブジェクトで表現されています。
さて、これで済めば、なにも問題はないのですが、DJabberd::Bot はエラーの処理がちゃんとできてなくて、エラーパケットもそのまま process_text メソッドにわたってきます。しかしながら、エラーパケットであるという情報を得る手段が process_text の引数にはありません。なので、send_stanza メソッドを ad-hoc に拡張しています。
sub send_stanza { my ($self, $stanza) = @_; if ($stanza->isa('DJabberd::Message')) { ######### XXX START TOKUHIROM PATCH if ($stanza->attr('{}type') ne 'chat') { warn "unknown packet type " . $stanza->attr('{}type'); return; } ######### XXX END TOKUHIROM PATCH 以下略
AdminExtesion というのは、DJabberd の admin port(perlbal の admin port みたいなもの) のコマンドを拡張しているだけの存在です。DJabberd::Connection::Admin::CMD_* を定義して、admin port から情報を流し込めるようにしています。


