XMPP on Google App Engine

XMPPってなんだ?

よくわかっていないのだが,インスタントメッセージを標準化しようというプロトコルらしい.こちらに非常によくまとまっているのだが,プロトコルとしてはメイルにかなり近いようだ.アドレスもメイルと同じ表現で,XXX@domain.nameと書く.サーバをDNSで引いてそこに送りつける,という部分も同じ.

これをGAEで使うとなにができるようになるか,というと,Google Talkなどから情報を入れたり,Google Talkにノーティフィケーションを出したりすることができる.たとえば,予定管理アプリなら,時間になったらIMが飛んでくる,みたいなことができる.私のように常にGmailを開いているものには便利だろう.

以下はApp Engineのページを参考にまとめてみる.

アドレス

GAEアプリには アプリID@appspot.com というアドレスが自動的に与えられる.また,

XXXX@アプリID.appspotchat.com

というアドレスも利用できる.XXXXは,任意の文字列.appspotchat.com というドメインになっていることに注意.

ちなみにアプリに複数のバージョンがある場合,当然これらのアドレスはデフォルトのアプリで処理される.ただし,

XXXX@バージョン.latest.アプリID.appspotchat.com

というアドレスで,各バージョンにメッセージを送ることができる.

デフォルトでないアプリがメッセージを送信した場合には,

アプリID@バージョン.latest.アプリID.appspotchat.com

からの送信となる.

送信

送信は,メイルとかとほとんど同じ.アドレスとボディを設定して,送るだけ.簡単.
フォームから送信できるものを作ってみる.まずはフォーム.

  <form action="/send" method="post">
    <div>to: <input name="to"/></div>  
    <textarea name="body" rows="2" cols="40" ></textarea>
    <div><input type="submit" value="Submit" /></div>
  </form>

サーブレットはこんな感じ.

import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.xmpp.*;

@SuppressWarnings("serial")
public class XMPPSenderServlet extends HttpServlet {
  public void doPost(HttpServletRequest req, 
      HttpServletResponse res)
      throws IOException {
    res.setContentType("text/html");    
    String to =   req.getParameter("to");
    String body = req.getParameter("body");
   
    JID jid = new JID(to);
    String msgBody = body;
    Message msg = new MessageBuilder()
            .withRecipientJids(jid)
            .withBody(msgBody)
            .build();
    boolean messageSent = false;
    XMPPService xmpp = XMPPServiceFactory.getXMPPService();
    if (xmpp.getPresence(jid).isAvailable()) {
      SendResponse status = xmpp.sendMessage(msg);
      messageSent = (status.getStatusMap().get(jid) == 
        SendResponse.Status.SUCCESS);
      if (messageSent)
        res.getWriter().println("<h2>Message Sent!</h2>");
      else
        res.getWriter().println("<h2>Failed!</h2>");           
    } else {
      res.getWriter().println("<h2>the address " + to + 
                              " is not available</h2>");
    }
  }
}

このサーブレットを/sendにweb.xmlでマップする.

  <servlet>
    <servlet-name>xmppsender</servlet-name>
    <servlet-class>myTest.XMPPSenderServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>xmppsender</servlet-name>
    <url-pattern>/send</url-pattern>
  </servlet-mapping>

Gmailのアドレスに送るとチャットウィンドウにメッセージが現れる.

受信

GAEにおけるXMPPの受信は,特定のURLへのリクエストという形で行われる.これは,GAEで言うところの,Web Hookというパターンで,スケジュールド・タスクやタスクキューでもおなじパターンが使われている.

受信するためには,以下をおこなえばよい.

appengine-web.xmlに設定

下記をappengine-web-appタグの中に書くだけ.

  <inbound-services>
    <service>xmpp_message</service>
  </inbound-services>
ハンドルサーブレット

サーブレットはこんな感じ.

import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.xmpp.*;

@SuppressWarnings("serial")
public class XMPPReceiverServlet extends HttpServlet {
  public void doPost(HttpServletRequest req, 
                     HttpServletResponse res)
                    throws IOException {
    XMPPService xmpp = XMPPServiceFactory.getXMPPService();
    Message message = xmpp.parseMessage(req);
    System.err.println("from: "+ message.getFromJid());
    System.err.println("body: "+ message.getBody());
   }
}
web.xml でURLにマップ

下記をweb.xmlに追加する.

 <servlet>
    <servlet-name>xmppreceiver</servlet-name>
    <servlet-class>XMPPReceiverServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>xmppreceiver</servlet-name>
    <url-pattern>/_ah/xmpp/message/chat/</url-pattern>
  </servlet-mapping>
テスト

Gmailに付いているchat窓からメッセージを送ってみる.アドレスフィールドに アプリID@appspot.com と入力し,inviteすると,下のリストにアドレスが現れるはずだ,これをクリックするとチャットサブウィンドウが開く.そこに何か入力して送ってみよう.

上のサーブレットはメッセージと送信者のIDをstderrに書き出している.stderrはwarning扱いでログに残るので,管理コンソールのログページで確認することができる.

クォータ

メイル同様XMPPにもクォータが設定されている.無料の範囲でも,SPAMする気でもなければあまり問題にならないような上限値になっている.invitationが1日あたり1000件になっているのが,場合によっては引っかかるかも,というぐらいか.

また,XMPPの受信はリクエストに対するクォータ以外に,1通あたり50msCPUを消費する換算になっているのも要注意点.

所感

メイルの受信機能が無い現在,XMPPはHTTP以外で唯一GAEがメッセージを受け取ることのできるプロトコルだ.メイルと同じで認証が全然ないのがかなり気になるような気もするが,用途は非常に広いのではないだろうか.使うのもすごく簡単だし.