Lingr APIで何か作る日記

Lingr APIを使って何か面白いものが作れないかと試行錯誤する日記です。
 | 

2007-02-12

セッションを使ってroom.enterでルームに入る (その3)  セッションを使ってroom.enterでルームに入る (その3) - Lingr APIで何か作る日記 を含むブックマーク はてなブックマーク -  セッションを使ってroom.enterでルームに入る (その3) - Lingr APIで何か作る日記  セッションを使ってroom.enterでルームに入る (その3) - Lingr APIで何か作る日記 のブックマークコメント

Railsモデル側がだいぶできたので、Webブラウザからroom.observeを呼び出してLingrチャットルームを見られるようにしましょう。

まず最初に、room.enterレスポンスのうち、counterとmax_observe_timeもDBに保存するように、Occupantモデルを修正します。

Index: app/models/occupant.rb
===================================================================
--- app/models/occupant.rb      (revision 72)
+++ app/models/occupant.rb      (working copy)
@@ -17,6 +17,8 @@
     end
     self.ticket = response[:response]['ticket']
     self.name = response[:response]['occupant_id']
+    self.counter = response[:response]["room"]["counter"].to_i
+    self.max_observe_time = response[:response]['max_observe_time'].to_i
     self.room.name = response[:response]['room']['name']
     self.room.save
   end

次に、Railsコントローラとビューを作ります。

$ script/generate Controller room show

Roomコントローラ (app/controllers/room_controller.rb) のshowアクションでは、セッションを生成して指定されたルームに入室します。

class RoomController < ApplicationController
  def show
    room = Room.find(params[:id])
    if @room
      @session = Session.create
      @occupant = Occupant.create(:session => @session, :room => room)
    end
  end
end

showアクションに対応するビュー (app/views/room/show.rhtml) では、room.enterで取得したsession, ticket, counterをテキストフィールドに埋め込んでいます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>JSONP Test</title>
    <script type="text/javascript" src="/javascripts/prototype.js"></script>
    <script type="text/javascript" src="/javascripts/prototype-jsonp.js"></script>
    <script type="text/javascript" src="/javascripts/lingr.js"></script>
  </head>
  <body>
    <input id="session" name="session" type="text" value="<%=h @session.name %>" />
    <input id="ticket" name="ticket" type="text" value="<%=h @occupant.ticket %>" />
    <input id="counter" name="counter" type="text" value="<%=h @occupant.counter %>" />
    <button onclick="observeLingr()">connect Lingr (observe)</button>
    <ul id="messages"></ul>
  </body>
</html>

これでRails側の準備はおしまいです。次はWebブラウザからJavaScriptを使って、チャットルームのメッセージを取得します。

JavaScriptでJSONPを使う  JavaScriptでJSONPを使う - Lingr APIで何か作る日記 を含むブックマーク はてなブックマーク -  JavaScriptでJSONPを使う - Lingr APIで何か作る日記  JavaScriptでJSONPを使う - Lingr APIで何か作る日記 のブックマークコメント

Webブラウザごにょごにょする前に、JavaScriptでJSONPを簡単に使えるようにします。RailsJavaScriptと言えばprototype.jsなので、prototype.jsでJSONPを扱う方法を調べます。MochiKit で JSONP の利用 - 2nd lifeによると、「prototype.js なら dojoの ScriptSrcIO ライクに拡張した404 Not Found」が使えるようです。

リンク先のJavaScriptファイルコピペして、「prototype-json.js」という名前で保存しました。オリジナルのままだと動かなかったので、下記のように修正しています。

$ diff -u aaa.js prototype-jsonp.js
--- aaa.js      2007-02-12 23:36:26.759944464 +0900
+++ prototype-jsonp.js  2007-02-10 10:49:33.145858968 +0900
@@ -40,7 +40,7 @@
     try {
       this.url = url;
       if (this.options.method == 'get' && parameters.length > 0)
-        this.url += (this.url.match(/?/) ? '&' : '?') + parameters;
+        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

       Ajax.Responders.dispatch('onCreate', this, this.transport);

@@ -72,9 +72,10 @@
   }
 });

-com.espn.io.ScriptSrcTransport = Class.create();

-com.espn.io.ScriptSrcTransport.prototype = {
+EspnScriptSrcTransport = Class.create();
+
+EspnScriptSrcTransport.prototype = {
        initialize: function()
        {
                if(!document.scriptRequests){ document.scriptRequests = []; }
@@ -100,7 +101,7 @@

                if(jsonParamName)
                {
-                       sep = (/?/.test(url)) ? '&' : '?';
+                       sep = (/\?/.test(url)) ? '&' : '?';

使い方はリンク先に書いてあるとおりです。urlにはJSONPのURLを入れます。

new Ajax.Request(url,
{
	transport: com.espn.io.ScriptSrcTransport,
	jsonParamName: 'callback',
	method: 'get',
	onFailure: this.doClipFailure.bind(this),
	onSuccess: this.showClips.bind(this)
});

WebブラウザからJSONPで部屋を覗く (observe)  WebブラウザからJSONPで部屋を覗く (observe) - Lingr APIで何か作る日記 を含むブックマーク はてなブックマーク -  WebブラウザからJSONPで部屋を覗く (observe) - Lingr APIで何か作る日記  WebブラウザからJSONPで部屋を覗く (observe) - Lingr APIで何か作る日記 のブックマークコメント

Railsからもらったsession, ticket, counterを使って、Webブラウザからroom.observeを呼び出します。ソースは下に載せておきます。要点だけ箇条書きで書いておきます。

  • timeoutSecondsを必ず指定すること。値はroom.enter戻り値の一つ、max_observe_timeよりも大きくする。(さっき試したら80秒だったので、余裕を持って120秒にしている)
  • onFailureはサーバとの接続に失敗したか、timeoutSecondsで設定した時間が経っても応答が無かった場合。
  • onSuccessはサーバから応答が返ってきた場合。応答の種類によって処理が異なる。
    • statusがokの場合: 誰かが発言したか、max_observe_timeの時間が過ぎたかのどちらか。後者の場合はjson.messagesが空になる。counterも進まない。
    • statusがfailの場合: sessionやticketの有効期限切れなど。たぶんそのままリクエストを再送しても無駄
  • console.logはFireBug用のデバッグログ。
  • このままだとJSONPでroom.observeを呼ぶたびに、headのscriptタグがどんどん増えていく。本当は呼び終わったらscriptタグを消すべし(やり方分からない。req.abort()を呼べばいい?)。

と言うわけで、onSuccessかつstatusが'ok'の場合のみに、リクエストを再送 (再びobserveLingr関数を実行) しています。さらに、messages配列存在する場合は、showMessage関数を呼び出してWebブラウザの画面にチャットの発言を表示します。

一応、これでJSONPを使ってLingr API経由でチャットを見られるようになりました。

var lingr_base = 'http://www.lingr.com/api';

function observeLingr() {
  var url = lingr_base + '/room/observe/';
  url += '?session=' + $F('session');
  url += '&ticket=' + $F('ticket');
  url += '&counter=' + $F('counter');
  url += '&format=json';
  new Ajax.Request(url, {
    method: 'get',
    transport: EspnScriptSrcTransport,
    jsonParamName: 'callback',
    timeoutSeconds: 120,
    onFailure: function(req, json) {
      console.log(req);
      console.log('connection error');
    },
    onSuccess: function(req, json) {
      if (json && json.status == 'ok') {
        if (json.messages) {
          showMessage(json.messages);
          $('counter').value = json.counter;
        }
        observeLingr();
      } else {
        // Error was returned by Lingr API
        console.log('response error');
      }
    }
  });
}

function showMessage(messages) {
  messages.each(function(message, index) {
    nickname = message.nickname.escapeHTML();
    text = message.text.escapeHTML();
    new Insertion.Bottom('messages', '<li>' + nickname + ':' + text + '</li>');
  });
}

WebブラウザからJSONPで部屋を覗いて何が嬉しいのか  WebブラウザからJSONPで部屋を覗いて何が嬉しいのか - Lingr APIで何か作る日記 を含むブックマーク はてなブックマーク -  WebブラウザからJSONPで部屋を覗いて何が嬉しいのか - Lingr APIで何か作る日記  WebブラウザからJSONPで部屋を覗いて何が嬉しいのか - Lingr APIで何か作る日記 のブックマークコメント

さて、わざわざJSONPを使ってJavaScriptからLingr APIroom.observeを呼び出しました。こんなことしなくても、直接Lingrチャットルームを覗くのと何が違うのか、と思うかもしれません。

ですが、Lingr APIを使わないと実現できないこともあるのです。

部屋のパスワードを教えずに部屋に招待する

Lingrでは部屋に鍵(パスワード)をかけることができます。普通Lingrを使う場合は、パスワードを教えないと部屋の発言を見ることができません。

でも、Lingr APIを使えば、「部屋のパスワードを教えずに部屋の中を見せることができる」のです。さっきのJSONPの例でも、部屋のパスワードを知っているのはRails側で、Webブラウザには部屋に入るためのTicketとSessionしか渡していません。

Rails側でSessionを無効にすれば、その人はもう部屋の発言を見ることができなくなります(部屋のパスワードを知らないので)。

発言禁止状態で部屋に招待する

さらに発言禁止のAPIキーを使ってSessionを作るようにすれば、「パスワードを知らない人は閲覧だけができる部屋」が実現できます。例えば、誰かと誰かの対談を、ReadOnlyで広く公開することもできるでしょう。

と、ここまで書いておいて、本家に同じような機能ができたら意味が無いのですが…。

ゲスト



トラックバック - http://lingr.g.hatena.ne.jp/kmachu/20070212
 |