kagamihogeの日記

kagamihogeの日記です。

Play FrameworkのWebSocketさわる

Play Frameworkはサンプルでチャットの例が一緒に入っているのだがActorを絡めたコードになっており、ビミョーによくわからなかった。ので、他のWebSocketのサンプルでしばしば見られる、送信したメッセージをただ送りなおす、いわゆる「エコー」をやってみることにした。

やったこと

Play Frameworkさわる - kagamihogeのblogで環境作って、初期状態のプロジェクトをそのまんま流用する。

まずクライアント側のapp/views/websocketindex.scala.htmlはこんな感じ。

<!DOCTYPE html>

<html>
<head>
<script src="@routes.Assets.at("javascripts/jquery-2.0.2.min.js")" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
    $(function() {
        var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket;
        var socket = new WS("@routes.Application.echowebsocketmessage().webSocketURL(request)");
        socket.onmessage = function(event) {
            var data = JSON.parse(event.data);
            $("#onReceive").text(data.text)
        }
        
        $("#onSend").click(function () {
            socket.send(JSON.stringify({text: $("#sendMessage").val()}));
        });
    })
</script>
</head>
<body>
<textarea id="sendMessage"></textarea>
<div id="onSend">click send message.</div>
<div id="onReceive">dummy</div>
</body>
</html>

@routes.Application.echowebsocketmessage〜てな感じでURLを書くことができ、実際にページにアクセスすると該当部分は下記のようになる。

var socket = new WS("ws://localhost:9000/echowebsocketmessage");

他はWebSocketのコードで、playとは直接の関係が無いので特に無し。

conf/routes に新しいURLマッピング書き加える。

# Home page
GET     /                           controllers.Application.index()
GET     /echowebsocketindex         controllers.Application.echowebsocketindex()
GET     /echowebsocketmessage       controllers.Application.echowebsocketmessage()

/echowebsocketindex でページ表示して、/echowebsocketmessage に対してWebSocketの送受信する。

package controllers;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ObjectNode;

import play.libs.F.Callback;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.WebSocket;
import views.html.index;
import views.html.websocketindex;

public class Application extends Controller {
  
    public static Result index() {
        System.out.println("root");
        return ok(index.render("Your new application is ready."));
    }
    
    public static Result echowebsocketindex() {
        return ok(websocketindex.render());
    }
    
    public static WebSocket<JsonNode> echowebsocketmessage() {
        return new WebSocket<JsonNode>() {
            public void onReady(WebSocket.In<JsonNode> in, WebSocket.Out<JsonNode> out){
                try { 
                    in.onMessage(new EchoCallback(out));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        };
    }
    
    public static class EchoCallback implements Callback<JsonNode> {
        private WebSocket.Out<JsonNode> out;
        public EchoCallback(WebSocket.Out<JsonNode> out) {
            this.out = out;
        }
        @Override
        public void invoke(JsonNode event) throws Throwable {
            ObjectNode echo = Json.newObject();
            echo.put("text", "[echo]" + event.get("text").asText());
            out.write(echo);
        }
    }
}

こんくらい最小限度のコードにしてしまえば、そんなにややこしいもんでなかった。