playframework1.2.4におけるwebsocket
DESCRIPTION
PlayBay - PlayFramework + WebSocket勉強会で行った資料です。 WebSocketをPlayFrameworkでハンドリングするためのもろもろを解説しました。WebSocketControllerと、F.javaの話、イベントモデルの話がメインです。TRANSCRIPT
PlayFramework + WebSocket 勉強会PlayFramework1.2.4におけるWebSocket
エンジニアカフェ
原 一浩 @kara_d
原 一浩 @kara_d $ play netbeansify
トレンド 、統計、デザイン、システムデザイントレンドリサーチをベースに、デザインされたアプリPlayFramework、R言語、CakePHP、Flexなど受託制作
何してる人?
Greative is Great Creative
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
4/4のJavaOneに参戦!!
JavaOneでスピーカーします➡ PlayFramework + WebSocketでつくる
リアルタイムWebアプリケーション
4
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
アジェンダ
5
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
本日のゴールと目次
本日のゴール➡ なんとなくWebSocketアプリケーションが作れるくらい➡ PlayFrameworkにおけるWebSocketControllerの全体理解
目次➡ フロントエンドから見た、リアルタイム通信サーバのこれまで➡ WebSocketについて➡ WebSocket未対応ブラウザへの対応➡ PlayFrameworkとWebSocket➡ Sample chatでみる、WebSocketアプリの構成➡ WebSocketController➡ F.javaの話➡ WebSocketアプリケーションの設計・構築手順
6
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
フロントエンドから見た、リアルタイム通信サーバのこれまで
7
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
昔々のリアルタイム通信コンテンツの定番
Flashでのリアルタイム通信➡ Adobe Flash Communication Server➡ Adobe Flash Media Server
Real Time Messaging Protocol(RTMP)➡ Red5• http://www.red5.org/
• Javaで作られている
• オープンソース
8
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketについて
9
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketの仕様について
WebSocketは、W3CとIETFが策定している➡ 元々はHTML5の仕様の一部➡ 双方向の通信技術➡ AjaxやCommetよりもプッシュ技術の仕組みとして自然➡ 一度コネクションを行った後は専用の通信プロトコルで通信• ハンドシェイク
• ws:もしくはwss:
➡ 最終仕様は、RFC6455。対応は下記(※は未調査)• IE 10 Platform Preview 5※
• Firefox 11
• Google Chrome 16
• Safari 最新※
10
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocket未対応ブラウザへ
11
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
クロスブラウザ対応の力強い味方
web-socket-js➡ https://github.com/gimite/web-socket-js• Google Chrome 4 or later, Firefox 6 or later (uses native
WebSocket or MozWebSocket implementation)
• Firefox 3 to 5, Internet Explorer 8, 9 + Flash Player 10 or later
12
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
web-socket-jsのインストール方法(1)
PlayFrameworkでの利用➡ ダウンロードしたら、• public/javascripts/ に「swfobject.js」「web_socket.js」を配置
• public/swfs/ に「WebSocketMain.swf」を配置
➡ main.html(レイアウト)に記述
13
<script src="@{'/public/javascripts/swfobject.js'}" type="text/javascript" charset="${_response_encoding}"></script><script src="@{'/public/javascripts/web_socket.js'}" type="text/javascript" charset="${_response_encoding}"></script>
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
web-socket-jsのインストール方法(2)
JavaScriptでのWebSocketの接続方法
➡ Flashを介している点がデフォルトの方法と異なる➡ こうすることでFirefoxなど未対応ブラウザでも動作可能
14
WEB_SOCKET_SWF_LOCATION = "@{'/public/swfs/WebSocketMain.swf'}";WEB_SOCKET_DEBUG = false;
var socket;socket = new WebSocket( '@@{WebSocket.ChatRoomSocket.join(user)}')
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
PlayFrameworkとWebSocket
15
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
PlayFrameworkとWebSocket戦いの歴史
Play1.2.3➡ hybi-07➡ version 7(だったような...)➡ Chrome 14までサポート
Play1.2.4➡ hybi-10➡ バージョン8➡ Chrome 16までサポート
パッチ(Lighthouse 1240 patch)➡ RFC6455➡ 最新版に対応
16
Play勉強会
Play合宿Play, WebSocket and CakePHP mini hack-a-thon 雪山合宿
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
パッチを当てれば動く!!
パッチ(Lighthouse 1240 patch)の当て方➡ https://github.com/playframework/play/pull/438 を参照➡ framework/src/play/server/PlayHandler.java を修正➡ 修正後、antタスクを実行
17
$ ~/play-‐1.2.4/framework$ ant Buildfile: /Users/harakazuhiro/play-‐1.2.4/framework/build.xml.....BUILD SUCCESSFULTotal time: 22 seconds
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
パッチがあたると、こうなる
パッチが当たったリビルド版➡ バージョン表記が「play! 1.2.x-localbuild」に
18
$ play run ~ _ _ ~ _ __ | | __ _ _ _| |~ | '_ \| |/ _' | || |_|~ | __/|_|\____|\__ (_)~ |_| |__/ ~~ play! 1.2.x-‐localbuild, http://www.playframework.org
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
パッチについてのご意見
パッチ(Lighthouse 1240 patch)に関する情報
➡
が正解?
19
@gtk2k さんより@kara_d versionにはクライアントのSec-WebSocketフィールドの値 は、 versionにはクライアントのSec-WebSocket-Versionフィールドの値 の間違いです。
res.setHeader("Sec-WebSocket-Version", "13");
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
PlayFramework以外の状況
Play以外は追いかけれていませんが、ご参考まで
•
20
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
MVCとポートの話
WebSocketをMVCフレームワークに載せる意味➡ Webアプリケーションとのシームレスな統合➡ MVCフレームワークでWebSocketもコントローラーとして
ラッピングすることで、設計が容易に➡ 認証系、データ管理系の実装が楽になる• 負荷を考えると結局は別サーバー?
WebSocketアプリケーションとポート➡ 基本的には、Playが動いているポートになる➡ Apacheをフロントに置いて、mod_proxyを経由させている
場合は注意
21
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
接続先は自動で生成可能
PlayFrameworkとJavaScriptとの連携➡ WebSocketのポート、アドレスの出力
とすると、
と出力される。• @@{}で絶対URLになる
22
socket = new WebSocket( '@@{WebSocket.ChatRoomSocket.join(user)}' )
socket = new WebSocket( 'ws://localhost:9000/websocket/room/socket?user=hara' )
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
Sample chatでみる、WebSocketアプリの構成
23
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
付属のサンプル話
PlayFrameworkでのWebSocketのサンプル➡ samples-and-tests/chat• Reflesh形式
• Commet形式
• WebSocket形式
24
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketアプリ:サーバーとクライアント
Inbound
WebSocketアプリケーションの基本モデル
25
WebSocketController
DB PlayFramework
Webサイト
WebSocketハンドシェイク
WebSocketソケット通信
WebSocketEvent
ModelEvent
TextFrame
SocketClose
BinaryFrame
Join
Message
Leave
アプリごとにイベントデザインが必要
Outbound
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
サンプルのチャットアプリケーションを読み解く(1)
全体構成➡ クライアント• コマンドを「:」でつないだシンプルなメッセージ方式
• コマンド : ユーザー : メッセージ
• message : name : text
➡ サーバー• WebSocketコントローラー内にChatRoomSocketという
WebSocketControllerクラスを継承したクラスがある
• ChatRoomSocketには、joinメソッドのみがある
• ChatRoomモデル内でチャットのイベントを設定
• roomMessagesStreamイベントストリームを作成
• inbound.isOpen()の限りループ- ただし、Either<WebSocketEvent,ChatRoom.Event> eに値が入らない限りは停止
26
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
サンプルのチャットアプリケーションを読み解く(2)
• 各種イベントにマッチするものがあれば、各処理を実行- WebSocket側のイベントで発生したオブジェクトが、TextFrameかつTextFrameがquit- WebSocket側のイベントで発生したオブジェクトが、TextFrame- roomMessagesStream側のイベントで発生したオブジェクトが、ChatRoom.Joinクラス- roomMessagesStream側のイベントで発生したオブジェクトが、ChatRoom.Messageクラ
ス- roomMessagesStream側のイベントで発生したオブジェクトが、ChatRoom.Leaveクラス- WebSocket側のイベントで発生したオブジェクトが、SocketClosed
27
public static void join(String user) { while(inbound.isOpen()) { Either<WebSocketEvent,ChatRoom.Event> e = await(Promise.waitEither( inbound.nextEvent(), roomMessagesStream.nextEvent()));
...各種処理...
}}
ここで停止
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
ChatModelとChatRoomSocketでイベント判定
ChatModelは、通常のモデルと違いイベントを管理➡ 内部にEventクラスというabstractなクラスを用意➡ Eventクラスを継承した各種イベントクラス• Joinクラス
• Leaveクラス
• Messageクラス
ChatRoomSocketでのイベント判定➡ ChatRoom.Eventクラスをスーパークラスとするクラスを
パターンマッチで分岐• ClassOf(ChatRoom.Join.class).match(e._2)
• ClassOf(ChatRoom.Message.class).match(e._2)
• ClassOf(ChatRoom.Leave.class).match(e._2)
28
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
イベントはクラスで判別というのがセオリー?
イベントの全体像まとめ➡ ChatRoomイベント• ChatRoom.Joinクラス
• ChatRoom.Messageクラス
• ChatRoom.Leaveクラス
➡ WebSocketイベント• WebSocketFrameクラス
- play.mvc.Http.WebSocketEvent.TextFrame- play.mvc.Http.WebSocketEvent.BinaryFrame
• WebSocketCloseクラス- play.mvc.Http.WebSocketEvent.SocketClosed
29
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
フロント側のイベントはどういう定義になっている?
フロント側のイベントスキーマ➡ JavaScript側で定義し、socket.onmessageで取得できる
dataプロパティの値によって振り分け
event.type➡ message➡ join➡ leave➡ quit
30
イベント名:ユーザー名:メッセージテキスト
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
JavaScriptのWebSocket APIを把握しよう
JavaScriptのWebSocketのAPI➡ socket = WebSocket(url, protocols)➡ socket.send()➡ socket.close()
イベントハンドラ➡ socket.onmessage➡ socket.onopen➡ socket.onerror➡ socket.onclose
31
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
SVGを使った応用例
32
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
某Developers Day応募作品
➡ 作成したアプリケーション
33
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
作品の解説
アプリケーションの設計➡ ベースはサンプルチャットとほぼ同じ➡ SVGをjQueryで操作➡ ユーザー名はアクセスするたびに生成されるユニークID➡ ロールオーバー時にWebSocketイベントを発生➡ ロールオーバーした描画オブジェクトのIDをメッセージとして
渡す➡ アニメーションはCSS3のアニメーション
34
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketController
35
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
Controllerとは少し違うWebSocketController
WebSocketController➡ 通常のControllerのようにStaticメソッドによるアクションが
定義可能➡ ルーティングにより、URLの割当が可能➡ InboundとOutboundという2種類のチャンネルが存在➡ request、params、validation、sessionは存在➡ disconnect()メソッドにより、通信の切断が可能➡ awaitメソッドによる処理の待機➡ ビューでは、@@{}タグによってwsプロトコルにすることが
可能• Routesでプロトコルの指定が必要
36
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
InboundとOutbound、2つのチャンネルがある
InboundとOutbound➡ Inbound• WebSocketの受信
• WebSocketのソケットがオープンしている間、isOpen()がtrueを返す
• inbound.nextEvent()にて、発生したイベントを取得
➡ Outbound• WebSocketの送信
• Outbound.send(String string)にて、WebSocketにて送信
• sendメソッドには、opcodeを指定した生データに近い送信も行える- outbound.send(byte opcode, byte[] data);
37
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketアプリ:サーバーとクライアント
Inbound
WebSocketアプリケーションの基本モデル
38
WebSocketController
DB PlayFramework
Webサイト
WebSocketハンドシェイク
WebSocketソケット通信
WebSocketEvent
ModelEvent
TextFrame
SocketClose
BinaryFrame
Join
Message
Leave
アプリごとにイベントデザインが必要
Outbound
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
テキストフレーム以外も扱えるOutbound
Outboundあれこれ➡ テキストフレームは、通常下記みたいな利用をするが、• outbound.send("quit:ok");
➡ JSONでも送信が可能。sendJsonを使用する• outbound.sendJson(Object);
➡ 生データ• send(byte opcode, byte[] data)
39
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
これさえ覚えればOK、WebSocketのテキストフレーム
テキストフレームのやりとり➡ 受信• play.mvc.Http.WebSocketEvent.TextFrameからMatcherを使って
textDataを取り出す
➡ 送信• outbound.send(String string)を使って送信
40
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
F.javaの話
41
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
奇々怪々なコードが満載なF.java
F.java➡ WebSocket周りを見ていくと、必ずぶち当たる壁➡ Javaで関数言語的な使い方をサポートするライブラリ• Either
- E2、E3、E4、E5まである- Haskel由来?
• ArchivedEventStream- イベントのキューとして扱う仕組み
• Matcher- パターンマッチ用
• Promise- 非同期処理
➡ F.javaを制するものはPlayを制す?!(まだ制してません
42
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
Haskel由来?なクラス
Eitherについて➡ どちらか1つの型が入っていた場合の返り値を受け取れる➡ eという値で受け取った場合、e._1もしくはe._2が入る
中身➡ Either<WebSocketEvent, ChatRoom.Event> eのトレース• E2(_1: Some(play.mvc.Http$WebSocketFrame@65202d8a), _2:
None)
• E2(_1: None, _2: Some(models.ChatRoom$Message@238df2e4))
➡ E2(_1: 値, _2: 値)という出力が出るtoString()が実装• これで学習用の暫定確認が行える
43
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketで見られる不思議なfor構文の正体
パターンマッチFor文の使い方
44
for(String a: TextFrame.match(e._1)) {
...処理...
}
for(String a: TextFrame.and(Equals("quit")).match(e._1)) {
...処理...
}
for(Message a: ClassOf(Message.class).match(e._2)) {
...処理...
}
明示的なキャストが存在しないので、すべてがタイプセーフであり、コンパイラによって型チェックが行われます。
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
Matcherは最重要
F.javaのMatcher周りについて➡ String• 文字列でマッチ
➡ ClassOf• クラスでマッチ
➡ StartsWith• プレフィックスでマッチ
➡ Re• 正規表現パターンでマッチ
➡ Equals• 等価な文字列でマッチ
45
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketEventは下記のMatcherを覚える
WebSocketEvent周りのMatcher➡ SocketClosed.match()• WebSocketCloseかどうかでマッチ
➡ TextFrame.match()• WebSocketフレームがバイナリでなく、なおかつtextDataでマッチ
➡ BinaryFrame.match()• WebSocketフレームがバイナリで、binaryDataでマッチ
46
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
WebSocketアプリケーションの設計・構築手順
47
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
こうやればスムーズ?WebSocketアプリケーションの設計
WebSocketアプリケーションの設計・構築手順➡ ベースとなるバックエンドのPlayアプリケーションの作成➡ フロント側のイベントスキーム(JavaScriptのイベント)を決定➡ フロント側で受け取るフォーマット形式の作成➡ バックエンド側のイベントスキーム(モデル)を決める➡ WebSocketコントローラーをつくり、バックエンド側の
イベントスキームをマッチするように組み込む➡ WebSocketのルーティングの設定➡ イベントマッチ時のメッセージの出力実装➡ フロント側でのAjaxの実装➡ テスト送信をし、テスト
48
クラスベースハンドラのイベント駆動プログラム関数型風味
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
通信の確認
WebSocket通信時の確認にはChromeが便利
49
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
まとめ
50
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
まとめ
WebSocketアプリケーション設計のコツ(エコー系)➡ テキストフレームのスキーマ設計➡ イベント設計➡ インバウンド後の処理設計➡ アウトバウンドのタイミング設計
51
Play!のWebSocketControllerはチャットを作るための機能ではない
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
このへん、議論したいです
WebSocketはどういうケースで役に立つのか?➡ ログインをした移行は、ユーザーによる細かな操作が続く場合➡ Ajaxで行ってきた部分の上位バージョンとして使われる?➡ ブラウザで閲覧しているどこかのタイミングでリアルタイム
通信が必要なとき.....
52
勉強会で議論していきましょう
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
今後勉強会でテーマにしていきたいこと
今後のお題➡ WebSocketの利用範囲を考える考察➡ 既存の通信手段とのパフォーマンス比較➡ outbound.sendJson()の実験➡ MessagePackの利用➡ 認証がからむケースのセキュアなWebSocket➡ WebSocketのデータを保存していくベストプラクティス➡ イベントの登録管理をもっとスマートに➡ PlayにおけるWebSocketアプリケーションの負荷の調査➡ サーバー構成の研究➡ ネームスペースの実装?(Socket.IO)
53
Copyright(C) 2012 Greative - Sustainable Automation, for Creative -(http://greative.jp/)
ありがとうございました
54
PlayFramework + WebSocket 勉強会今後も定期的に勉強会をします。#playbay にて情報を発信していきます。ハンズオン中心でやろうかと。わからないことを聞きやすいけど、ハックもがんがんする的な感じを目指してます。