チャットサポートを構築する (その2) サーバー ejabberd の準備

【2018年4月20日追記】この記事は内容が古くなっている部分があります。「あらためてチャットサポートを構築する」もご覧ください。【追記ここまで】

前回の「チャットサポートを構築する (その1)」は、Converse.js を設置し、(テストのページ)のように、普通の XMPP クライアントとして使えるというところまででした。

BOSH サーバー

ここからしばらく、サーバー側の設定の話になります。

クライアントが Converse.js などウェブベースのもので内部状態を保持できないような場合、BOSHという仕組みを介することで、接続を維持します。XMPP サーバーの ejabberd の場合、設定ファイル ejabberd.cfg次のように書くことで、BOSH サーバーにもなります[1]

ポート 5281 (HTTPSの場合)を listen するところに http-bind と書き足します。

{listen,
 [
  ...
{5281, ejabberd_http, [
       ...
       http_bind,
       ...
       ]}
  ...
]}

モジュールの設定のところで

{modules,
 [
  ...
  {mod_http_bind, []},
  ...
]}

を読み込むようにします。

匿名サーバー

XMPP サーバーには匿名サーバーという機能を持つものがあります。一般にクライアントがサーバーに接続する場合、事前に登録して作成しておいた user@example.net という形をした JID と、パスワードが必要になりますが、匿名サーバーは、そのサーバー名だけを指定して接続を試みると、@ より前のユーザー名を乱数のようにそのつど生成して接続します。

サーバーアプリケーション ejabberd の場合、ejabberd.cfg につぎのように設定して SASL 匿名サーバー (anonymous.example.net という名前だとします) を設置します。

{hosts, [ ..., "anonymous.example.net"]}.

{host_config, "anonymous.example.net", [
                               ...
                               {auth_method, anonymous},
                               {anonymous_protocol, sasl_anon},
                               {s2s_default_policy, deny},
                               {{s2s_host,"example.net"}, allow},
                               ...
]}.

s2s_... は、匿名サーバーに接続したユーザーは特定のサーバー以外への通信を禁止するという設定です。

クライアント側の事前接続

ここからクライアント側の話です。

「チャットサポート」として利用できるためには

  1. アプリケーションの事前インストールが不要
  2. アカウント(JID)の登録が不要
  3. 連絡先が登録済み

であることが必要です。前回はこの最初の項目、Converse.js をごくふつうに設置する(テストのページ)ところまで行いましたが、このままでは客側にアカウント (JID) を入力してもらわなければなりません。

Converse.js のマニュアルに Server-side authentication という章があります。別の何らかの方法で事前にサーバーに接続しておき、その情報を引き継げば、上述の2番めの項目をクリアできます。接続先を匿名サーバにすればパスワードも不要になります。しかし、マニュアルには具体的な方法はありません。

次のような方法を考えてみましたがこれで正しいのかよくわかっていません。とりあえず(ある場合には)うまくいっています。もし詳しい方がありましたら、ぜひ教えてください。

Converse.js の初期設定を書く <script> のところの先頭に書き足します。

<script TYPE="text/javascript">
var BOSH_SERVICE = 'https://anonymous.example.net:5281/http-bind';
conn = new Strophe.Connection(BOSH_SERVICE);
conn.connect('anonymous.example.net', '', onConnect);

function onConnect(status)
{
     wpCookies.set('jid', conn.jid);
     wpCookies.set('sid', conn.sid);
     wpCookies.set('rid', conn.rid);
}

Strophe.js は Converse.js に同梱されているので、Converse.js を利用できるようにしていれば、使えます。接続すると JID、SID、RID が確定するので、それをクッキーとして書き出します。ここでは WordPress の wp-include/js/utils.js を利用した記述 wpCookies.set になっていますが、もちろんそれでなくてもかまいません。

それに続く Converse.js の設定では

require(['converse'], function (converse) {
    converse.initialize({
        ...
        bosh_service_url: BOSH_SERVICE,
        prebind: true,
        jid: wpCookies.get('jid'),
        rid: wpCookies.get('rid'),
        sid: wpCookies.get('sid'),
        ...
    });
});
</script>

と、bosh_service_url を指定し、prebindtrue とし、jid, rid, sid をクッキーから読み込みます。

この項まだ続く

  1. BOSH サーバーには2種類あります。local BOSH サーバーは、入り口はどこからでも接続できますが、ローカルのアカウントにしか接続できません。それに対して open BOSH サーバーは、他所のサーバーのアカウントにも接続できます。ejabberd の BOSH は local タイプです。

チャットサポートを構築する (その1)

【2018年4月20日追記】この記事は内容が古くなっている部分があります。「あらためてチャットサポートを構築する」もご覧ください。【追記ここまで】

ずっと頭の片隅にあっていつかはと思っていた話題ですが、あたためすぎて腐ってしまった感なきにしもあらずです。何しろ自分でプログラムを書くほどの能力がないので、道具が出揃うのを待っているうちに随分時間が経ってしまいました。

「チャットサポート」というものについて考えてみます。Wikipedia の記述をそのまま引用しますが、

文字通り、チャットによるサポートであり、閲覧中のWebページ内のチャットボタンをクリックするだけでリアルタイムに Web サイト運営者のサポートをリアルタイムに受けることが出来るシステム。……英語ではLive Chat Supportと呼ばれることが多い。

というものです。アメリカのネット通販サイトなどではよく目にしますが、日本ではあまり見かけません。それでも「チャットサポート」で検索すると、日本(語)でもそのようなサービスを提供するところが増えてきているようです。

しかし大手の販売サイトならともかく、月に数回程度の利用しかないと想定される規模では、月額数千–数万円のサービス料金がメリットに見合うとは、あまり思えません。

そこですべてオープンソースの個々の汎用アプリケーションを組み合わせて、無料でこの仕組みを構築することを考えてみました。プログラムを書く能力があれば自分で作れるのでしょうが、それができないために、あちこちのソフトを組み合わせることになりました。

基本はチャットですから、XMPP を使います。このプロトコル自体がオープンであり、Skype や LINE や twitter などとは異なります。

すべてオープンソースの組み合わせで構築すると

  • 費用が発生しない
  • 独占企業の都合によるサービスの変更や停止ということがない
  • 個々のアプリケーションを取り替えられる
  • カスタマイズできる
  • サーバーも自分で管理すれば他者を経由しないので情報の流出の不安がない

などのメリットがあります。

もちろん逆に、一定の労力が必要だったり、汎用アプリのため洗練されていないなどのデメリットもあります。

通常のチャットでは、話者のそれぞれが XMPP のアカウント(JIDといいます)を持ち、互いに相手先を名簿に登録しており、それぞれ手元の端末にインストールするなりした XMPP のアプリケーションを使って、サーバーを介して会話します。「チャットサポート」の場合、サポートする側(問い合わせを受ける側。以下、便宜的に「窓口側」と呼びます)は別として、一度きりかもしれない問い合わせを行う側(以下、「客側」と呼びます)に、そのためにアカウントやアプリケーションを用意してもらうことは非常に難しいでしょう。

Converse.js

まず XMPP クライアントアプリケーションですが、JavaScript で書かれたものをウェブページに設置することで、そのページにアクセスするだけで利用できるようにします。これで、客側が事前にアプリケーションをインストールしなければならないということがなくなります。

Converse.js というものを見つけました。2014年初頭現在、活発に開発されているようです。多言語化されているようですが、日本語はまだ対応していなかったので、翻訳して作者に送ってみました。この時点で日本語での情報はほとんどなく、見つけたのは「Ejabberd+Apache mod_proxy+converse.jsでXMPP(BOSH)なチャット環境を作ってみた」でした。

さて、マニュアルに従って設置してみます。<head>内に CSS と本体の js を読み込むように書き、またページ後半に初期設定を記した <script> を書きます。ここまでは簡単で、そのまま Converse.js が使えるようになりました。

テストのページで実際に見てみるとわかるように、素のままでは普通の XMPP クライアントとかわりません。すなわち、自分のアカウント情報を入力し、相手先のアカウントを指定して会話を開始する、というものです。

長くなりそうなので、この項続く

WordPress からのほぼすべての通知を XMPP で送信するプラグイン wp_mail to XMPP

先日、WordPress のフォーラムの話題に触発されて、「コメントが来たことをメール以外で知らせる方法」という記事を書きました。

そのあともう少し一般的に考えてみました。WordPress から多くのメールが届きますが、そのほとんどは単なる「通知」で返信を要しないものです。つまりメールである必要はないのです。ということは、コメントがついた時だけでなく、WordPress からのすべてのメールを XMPP にしてもいいのではないか、と思いました。メールと XMPP は形式がとてもよく似ており、そのまま宛先を変えるだけでいいのではないか、と。

探してみたら、同じ目的の XMPP sender というものが既にありました。しかし中を見てみると古くて、メンテナンスもされていないようです。また、完全に wp_mail() を置き換えているので、条件によっては XMPP ではなくメールで送りたいと思っても応用が効きません。

WordPress からの通知は、更新・ユーザー追加・コメントなど発生源は種々あっても最終的には wp-includes/pluggable.php の中の wp_mail() によってメール発信が行われています。[1] wp_mail() を見てみますと、

function wp_mail( $to, $subject, $message, ...) {
	extract( apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ) );
		...
		$phpmailer->Send();
}

という構造になっています。冒頭のフック ‘wp_mail’ は、たぶん送信先の追加や、subject(件名)や message(内容)に一律に何か加工するなどを想定されていると思いますが、その中で XMPP 送信を行ってしまえばいいと考えて、次のようなプラグインを作りました。

wp_mail to XMPP
Send almost all notifications via XMPP instead of email

https://github.com/mako09/wp-mail2xmpp にも置いてあります。

前の記事「コメントが来たことをメール以外で知らせる方法」でざざっと書いて示したプラグインは、その機能が今回のプラグインに完全に含まれますので、忘れてください。

なおこのプラグインは、別のプラグイン XMPP Enabled を利用していますので、それを先にインストールしてください。

きっかけとなったフォーラムの話題のように、複数の投稿作成者がいて誰かが投稿したことを他の作成者たちが知りたい、という場合には、投稿を通知するプラグイン(公式ディレクトリで “post notification” で検索すれば、いろいろ見つかります)、たとえば New Post Notification などをインストールしておけばいいでしょう。そのメール通知も今回のプラグインで XMPP に振り替えます。

wp_mail to XMPP の中身

このプラグインは2つのフックを備えています。

abort_xmpp_sender は、XMPP送信処理を中止するためのものです。たとえば「コンタクトフォームからの送信は、JID の有無に関わらず、メールで送信する」としたい場合、件名やヘッダなどで判定するフィルターを追加すれば、実現できます。

email_to_jid は、メールアドレスから JID に変換するフィルターを呼び出します。デフォルトでは、そのサイトに登録されているユーザーかつそのユーザーがJIDを設定している場合のみ、JID を返すフィルターを設定しています。たとえばコメントをつけた人が入力したメールアドレスのように、JID を見つけることができなければ、その人には XMPP 通知を出しません。このフックにさらにフィルターを追加して、たとえば JID があっても XMPP 通知を出さない人を設定する、あるいは逆に、JID が見つからない場合は管理者の JID に XMPP 通知を出す、などを実現できます。

これらの後に、JID があれば XMPP 通知を、JID がなければメール通知を行います。XMPP に送られる通知では、subject(件名)と message(内容)をそのまま用い、headers(ヘッダー)と attachments(添付)は送信せず無視しています。

オプションで、XMPP 通知を行ったユーザーにもメール通知を行うように設定することもできます。

おわりに

はじめてプラグインを公式に公開しようとしたら、実際に動作するコードの部分を書く時間の10倍くらいを、その周辺のことに費やしました。名前を決めること、コメントや readme を英語で書くこと、依存する別のプラグイン XMPP Enabled を国際化・日本語化して作者に連絡して取り込んでもらうこと……。いやはや、いい経験になりました。それでもコード自体にも英語にも自信がありません。おかしなところを見つけて知らせてもらえたらうれしいです。

  1. ただし Jetpack購読(subscription)は、実際には WordPress.com がメールを送信しているため、これに該当しません。

コメントが来たことをメール以外で知らせる方法

WordPress のフォーラムに次のような話題がありました。

「コメントが来たことを知らせる方法をメール以外でなにかほしい」

現在、ワードプレスを数人で管理し、記事を書いています。

私たちの環境では、ディスカッション設定の自分宛のメール通知のところにある「コメントが投稿された時」にチェックを入れています。

(中略)

メールに気づく派も気づかない派も、各ユーザーがメールの通知以外でコメントに気づくことが出来るようにしたいと思っています。

そこで私は、以前に書いた「Jabber と WordPress」を示しながら、ただし XMPP サーバーを確保できないと難しいので一般的ではないと回答しました。

さて質問文をよく読むと、

  • 投稿にコメントがついたことの通知を受け取るのは、その投稿の作者のみでよい

で済みそうです。一度の通知の送り先は1人でよい、ということであれば、先に示したややこしい仕組みは必要ありません。

やはりインスタントメッセンジャー(IM) の XMPP を利用した通知を行うことにします。

管理者の作業

公式プラグインのサイトから XMPP Enabled というプラグインをインストールします。

さらに次のプラグインをインストールします。これは XMPP Enabled と同じ作者による、投稿のあった際に XMPP で通知する Juick Crossposter というプラグインを、コメントの場合に置き換えて作り直してみたものです。

また管理者は次の節の脚注の作業も必要に応じて行ってください。

【追記】 これを元に、一般化して、プラグインを公開しました。「WordPress からのほぼすべての通知を XMPP で送信するプラグイン wp_mail to XMPP」を参照してください。

各投稿者の作業

先の質問では複数の投稿作成者がいるようです。そこでそれぞれが通知を受け取るためには、各人の PC やスマートフォンなどに XMPP クライアントを用意してもらいます。また、各人に XMPP のアカウント(JID)を取得してもらいます。WordPress.comのアカウントを取得すれば自動的に (アカウント)@im.wordpress.com が JID になるのでそれを利用できます。

さて投稿しているブログサイトで、各人は自分のプロフィールのページにある「Jabber/Google Talk」の欄に取得した JID を入力しておきます [1][2]

これで設定は完了です。コメントがつくと、そのコメントがつけられた元の投稿の作者に XMPP で通知が行きます。

  1. 「Google Talk」とありますが、2013年末現在、Google Talk はサービスがなくなり(Google+ ハングアウトに吸収され)、他の XMPP ネットワークと連絡できなくなりました。そのため Gmail アカウントはここでは利用できません。
  2. なお、つい最近の WordPress を新たにインストールして始めた場合には、この「Jabber/Google Talk」欄がないかもしれません。管理者は、たとえばこのページなどを参考に(そこでは悲しいことにJabber項目の削除として紹介されていますが、ちょうどその逆の操作です)、jabber というフィールド名の項目を追加してください。

ejabberd 2.1.11

Jabber/XMPP のサーバー ejabberd 2.1.11 がリリースされたようです。 今回は事前に「翻訳を送って」と連絡があったので、以前の版にずいぶん手を入れた日本語訳を同梱してもらいました。どれほどの人が日本語版を利用しているのかさっぱり不明ですけれども。

Gajim 0.15

XMPPクライアント Gajim の0.15 が公開されました。日本語化ファイルは大幅に見直したので、以前より隨分よくなったと思っています。お気づきの点がありましたら、メール mako(あっと)pasero.net または XMPP でも同じ形の mako(あっと)pasero.net までお知らせください。

Firefox に新しいプロトコルを教える

前の記事のようにして、WordPress の記事に xmpp: のリンクを書けるようになりました。しかし、それを読む側のブラウザが「そんなの知らん」と言っては役に立ちません。

手元の環境は Linux (Debian) 上の Firefox (Debian では Iceweasel という名前) ですので、それについて書きます。その他の環境については、wiki.xmpp.org に情報があります (ただし Firefox の例を見てもやや古い情報のようです)。

ブラウザ

Firefox について、mozillaZine の Register protocol を参考にしました。

  1. ロケーションバーに about:config と入力します。
  2. 右クリック→新規作成→真偽値 とします。
  3. 「設定名」を network.protocol-handler.expose.xmpp とし、値を false とします。
  4. 次にこの xmpp: のリンクをクリックしたときに、どのアプリケーションでこのリンクを開くか、聞いてきます。これはあとで 編集→設定→プログラム のところで変更できます。

Chromium (Chrome) については、常用していないので詳しくありません。ヘルプを見ると、設定→高度な設定→コンテンツの設定 の「ハンドラ」あたりでどうにかするのでしょうか。

XMPPクライアント

ところで、この方法ではアプリケーションに URL が渡されるのですが、それを受け取って開きながら起動できる XMPP アプリケーションを2つ紹介します。

ひとつは Gajim です。ただし gajim-remote handle_uri %s という形で呼び出すのですが、Firefox から URL 以外の引数を渡せないようなので、ラッパーを介することにしました。

もうひとつは、ウェブアプリの Jappix です。Jappix の オプション→一般→XMPPリンク の「JappixでXMPPリンクを開く」をクリックすると、Firefox の、どのアプリケーションでこのリンクを開くかという選択肢に Jappix が入ります。