Cometとは
Cometは、サーバで発生したイベントをリアルタイムでブラウザに通知するプッシュ型の技術です。通常はJavaScriptによってサーバーとコネクションを継続させることで実現します。
Cometを利用することで、通常のWebアプリケーションでは難しい、チャットのようにリアルタイムで通知が必要なアプリケーションを実現することが可能です。
LiftにおけるComet
Liftでは、ScalaのActorライブラリとjQueryを利用して、Cometアプリケーションの作成をサポートする機能が備わっています。
ScalaのActorライブラリは、オブジェクト間のメッセージのやりとりを非同期に行うことができるようになっています。
Actor同士は、相互にメッセージを送信しあって、非同期処理を協調して実行するのです。
Cometを利用する場合は、CometActorを継承したSnippetを用意します。このCometActorを継承したSnippet自体が、一つのActorになっており、CometActorにメッセージが送られると、あらかじめCometで接続されているブラウザにレスポンスを返す、というのがLiftにおけるCometの仕組みです。
Twitterのクローンのようなアプリケーションを改良する
では、前回まで作成していたTwitterのクローンのようなアプリケーションに、Cometを利用してメッセージが投稿されたらすぐにブラウザに反映されるような画面を追加してみましょう。
今回は、2つのActorを用意します。
一つは、CometActorを継承し、ブラウザとCometで接続し、メッセージを受け取ってブラウザにその内容を返すSnippetです。
もう一つは、データベースに登録されたメッセージを受け取って、もう一つのCometActorを継承したSnippetに、そのメッセージを配信するActorです。
構成は、以下の図のようになります。
今まで作成してきた投稿画面のSnippet(Twit.scala)では、データベースにメッセージを保存した後に、そのメッセージをTwitServerというActorに送るようにします。
TwitServerは、受け取ったメッセージをCometActorを継承したSnippetに一斉に配信することで、各Snippetは非同期にブラウザにメッセージを表示させることができるようになります。
メッセージを配信するTwitServer
では、まずはメッセージを配信するTwitServerを作成します。
プロジェクトディレクトリ以下の 「src/main/scala/demo/twitterclone/comet/」ディレクトリに、「TwitServer.scala」というファイル名で新しいファイルを作成します。内容は、以下のリスト5の通りです。
package demo.twitterclone.comet import _root_.scala.actors.Actor import Actor._ import _root_.net.liftweb._ import http._ import _root_.demo.twitterclone.model._ /** * メッセージを配信するTwitServer * ScalaのActorを継承し、Liftで用意されている * ListenerManagerトレイトを継承することで、 * 登録されている他のActorにメッセージを配信できる。 */ object TwitServer extends Actor with ListenerManager { // *1 // 投稿されたメッセージ(配信されるとクリアされる) private var msgs: List[Message] = Nil // 登録されている他のActorに配信するメッセージ protected def createUpdate = Messages(msgs) // メッセージを受信した際の処理 override def highPriority = { // *2 case m: Message => msgs ::= m // 他のActorにメッセージを配信する updateListeners() msgs = Nil } this.start // *3 } case class Messages(msgs: List[Message]) // *4
TwitServerクラスは、ScalaのActorを継承します。さらに、Liftで用意されているListenerManagerトレイトを継承することで、登録されている他のActorにメッセージを配信できます(*1)。
このActorがメッセージを受信した際の処理は、highPriority関数に実装されています(*2)。
highPriority関数は、継承元のListenerManagerトレイトが持つ関数をオーバーライドすることで、メッセージをActorが受信すると自動的に呼び出されます。
ここでは、前回作成したモデルであるMessageモデルを受信し、このクラスがもつmsgsフィールドに受信したMessageモデルオブジェクトを追加して、ListenerManagerトレイトが持つupdateListner関数で、受信したMessageモデルオブジェクトをそのまま他のActorに配信しています。
*3は、このTwitSeverがメッセージの受信を開始する処理です。
*4のcaseクラスは、他のActorに配信するためのメッセージオブジェクトになっています。内容は、MessageモデルオブジェクトのListを持っています。このListの内容が、Cometで非同期に表示させる内容になる形です。