« JSONデータの圧縮について | トップページ | プログラマ35歳限界説と出口戦略について »

2013年12月19日 (木)

Socket.IO用フレームワーク socket.io-reqev

この記事はNode.js Advent Calendar 2013 19日目の記事となります。

前書き

Push通知のフレームワークとしてSocket.IOがよく使われています。
Socket.IOは、Websocketが使えない環境でもPUSH通信を可能とすることで有名ですが、それ以外にも、namespace機能やroom機能、イベントを自由に使えるなど、直接websocketを使うよりも便利な機能が多くあります。
機能は豊富ですが、書き方にルールを決めずに気軽にあちらこちらでpushを使うと、見通しが悪く保守が大変なアプリになってしまいます。
そこでSocket.ioがベースの、簡単で保守しやすいプログラムが書けるsocket.io-reqevというフレームワークを紹介します。

socket.io-reqevの概要

socket.io-reqevは、pubsub機能 + requstごとの応答(HTTPのGETに該当)を簡単に行うために作られています。
クライアント(ブラウザ)とサーバ(node.js)側にそれぞれにライブラリが用意されています。

クライアント側

URL(socket.ioホスト名 + path)とコールバックを指定してsocket.io-reqevオブジェクトを作成し, watchメソッドに購読したいイベント名とrequestオブジェクトを指定するだけです。
サーバから応答があると指定したコールバックが呼び出されます。

サーバー側

socket.io-reqevオブジェクトを作成します。
eventsフィールドとrequestメソッドを持つオブジェクト(サービスと呼ぶ)をPathを指定してsocket.io-reqevオブジェクトに登録します。

クライアントからの通信にeventsフィールドがあると、eventsフィールドのeventごとにイベント名のroomにクライアントを登録し、サービスがイベントを発行すると、サービスが発行したイベント名と同じroomに登録されているクライアントにイベントの通知がいきます。

クライアントからの通信にrequestsフィールドがあると、requestsフィールドのrequestごとにサービスのrequestメソッドにそのrequestが渡され、requestメソッドからのcallbackを通じた応答をクライアントに返します。

インストール

npm install socket.io-reqev

デモ

socket.io-reqevを使ったデモ

概要を体感するために上記のリンク先のデモを実行してみてください。
Demoではサーバ側にタイマーサービスとして、5秒、10秒,30秒ごとに時間を通知するイベント(five,ten,thirty)と現在の時間を返すcurrentというリクエストが用意されています。
クライアント側には、それらごとにチェックボックスを用意して、sendボタンを押すごとに、チェックに応じたwatchが実行され、サーバからの応答をすべて画面の下部に追記していきます。

requestのcurrentにチェックがついている場合は、sendボタンを押したら即座に一度だけ、現在の時間が書き込まれます。
eventsの5秒、10秒、30秒は、秒がそれぞれ5、10、30で割り切れる時間になった時はずっと応答が返ってくるため、5秒、10秒にチェックが入っている場合は、00:00:05の時は1つだけ書きこまれ、00:00:10の時は5秒と10秒のイベント2つが応答を返すため、2つ書きこまれます。
sendは何度でも押せます。つまりwatchメソッドは何度でも呼び出し可能です。
sendを押すごとに前回購読していたイベントはとりやめられ、新たなイベントで上書きされるので、ブラウザのnetworkを見ると、イベントを減らすと通信も減ることがわかります。
スマホのWebサイトの場合は、通信量とバッテリ消費の結びつきは大きいため、購読だけでなくとりやめも簡単なのはすごく使い勝手がいいです。

Demoのソース解説

node.js側

socket.io-reqvのオブジェクトをsocket.ioオブジェクトを渡して初期化しています。
timerサービスを/timerで登録しています。
本質的なところは以上です。
temporary web server以下のソースは、index.htmlやjs配下のJavaScriptを返すためのWebサーバ機能です。

Timerサービスの実装になります。
serviceとしての要件であるeventsフィールドとrequestメソッドがあります。
socket.ioに依存がないので、テストがしやすそうですね!

this.eventsに5秒、10秒、30秒ごとに通知を行うためのfive,ten,thirtyのイベント名がセットされています。
サービスの初期処理で1秒ごとのタイマーを実行していて、その中で現在秒が割り切れた場合にイベントを発生させています。
また、requestメソッドも用意して、クライアントからcurrentという文字列がきた場合は現在時刻の文字列を返しています。
requestに引数がほしい場合は、requestとして文字列ではなく、オブジェクトを渡すことで実現できます。

ブラウザ側

backbone.jsのcollectionとviewをindex.htmlに埋めこんでしまっているためちょっと見づらいです。
すみません。
socket.io-reqevが直接関わっているのは18行目から30行目までです。

viewの初期処理

  1. timerCollectionというcollectionを作成
  2. timerCollectionのaddイベントに対して、画面下部に応答を追記する処理を登録

viewのrender処理

  1. event(current)とreqest(five,ten,thirty)ごとのチェックボックスとsendボタンを作成

viewのイベント

  1. sendボタンを押下すると、events,requestそれぞれでチェックがついている値の配列を作ってtimerCollectionのwatchを呼び出し。

timerCollectionのwatchメソッド

  1. 初回呼び出しの場合は、socket.io-reqev-clientのオブジェクトをsocket.ioサーバのURL+PATHとサーバから応答があった時用のcallbackを渡して作成
  2. socket.io-reqev-clientオブジェクトのwatchメソッドにviewから渡されたeventsの配列とrequestsの配列を渡す。
  3. socket.io-reqev-clientがsocket.ioサーバにrequestsとeventsを送信
  4. socket.ioサーバから応答があると、 socket.io-reqev-clientがtimerCollectionから渡されたcallback実行
  5. callbackの中でtimerCollectionのaddメソッドに応答を渡すことで新たなTimeオブジェクトをcollectionに追加
  6. veiwのイベントリスナーが上記のaddに反応して、画面下部に応答を追記する処理を実行

viewのremoveメソッド

今回はどこにも呼び出し箇所がない。
ブラウザのjavascriptコンソール上でv.remove()と実行することで呼び出し可能。
Viewが破棄され画面が真っ白になる。
Backbone.jsの決まりとしてveiwの開放時にviewのremoveを呼び出すことでview内でlistenToで登録されたイベントハンドラが開放されるが、timerや今回のようなsocket.ioのリソースは自分で開放する必要がある。
viewの中でremoveをオーバーロードして、そこでsocket.ioのリソースを開放している。
それによりsocket.ioの通信がstopする。(socket.ioの死活監視の通信は残る)

まとめ

去年にNode.js + WebSocket + Backbone.jsのすすめ という記事を書いてその中で実装はちょっと大変だみたいなことを書きましたが、その後経験をつみ、このようなライブラリを使うことで、効率的にアプリを書けるようになりました。
よそよそしく紹介しましたが、socket.io-reqevは自作です。
server側のio-reqev.jsは57行、client側のio-reqev-client.jsは61行というソースの小ささのため、socket.ioを知っている人が見るとすぐ理解できると思います。
Backbone.jsもそうですが、ライブラリが小さくても、考え方の導入次第でプログラムの作りを大きく改善できます。
ライブラリが小さいと、ソースも読めて融通もきいていいですね。

|

« JSONデータの圧縮について | トップページ | プログラマ35歳限界説と出口戦略について »

Node.js」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/68673/58780383

この記事へのトラックバック一覧です: Socket.IO用フレームワーク socket.io-reqev:

« JSONデータの圧縮について | トップページ | プログラマ35歳限界説と出口戦略について »