Block Rockin’ Codes

back with another one of those block rockin' codes

Socket.IOv0.8.4 のソースを読んでわかった次期新機能先取り

本文

Socket.IO のソースを眺めていると色々面白いことがわかります。
master がガンガン新機能を実装していて、現時点でもアンドキュメントな API もいくつかあるし、結構ソースは読みやすい方なので勉強になります。

で、最近また最新のを読んでたら色々面白そうな機能があって、「あるんならちゃんとドキュメントに書いてよ。。」などと思ってたら、ついさっきコミッタの 3rdEden がこのスライドを公開してました。

http://www.slideshare.net/3rdEden/going-real-time-with-socketio


まだ未発表の新機能だっただけのようです(でもそういう機能も master にばっちりあるんだな。develop ブランチ一応あるんだけどw)。
おそらく次のバージョンアップは、また割と大きくなると思います。折角なので手元のメモを公開して、今のうちに少し先取りしてみようかと思います。

注意

  • Socket.IO@0.8.4 を読んでます。
  • 0.9で正式にアナウンスされると思うので、そしたらこの記事は止めて改めてそっちを書くつもりです。
  • ソース見ながら見つけただけで未検証です。
  • master に入ってるし、 npm で入れても v0.8.4 が入るので、手元で試せるはずです。

Configure

機能が増えればその設定が増えます。
設定項目とデフォルト値は以下、色々増えてますね。

  • origins: '*:*'
  • log: true
  • store: new MemoryStore
  • logger: new Logger
  • static: new Static(this)
  • heartbeats: true
  • resource: '/socket.io'
  • transports: defaultTransports
  • authorization: false
  • 'log level': 3
  • 'close timeout': 25
  • 'heartbeat timeout': 15
  • 'heartbeat interval': 20
  • 'polling duration': 20
  • 'flash policy server': true
  • 'flash policy port': 10843
  • 'destroy upgrade': true
  • 'browser client': true
  • 'browser client cache': true
  • 'browser client minification': false
  • 'browser client etag': false
  • 'browser client gzip': false
  • 'browser client handler': false
  • 'client store expiration': 15

Store

まず、大きいのは Store だと思います。
設定では MemoryStore になってます。
この MemoryStore は Connect のものかと思ったら独自実装でした。

大きいのは、この Store のインスタンスは、 Publish(), Subscribe() のインターフェースを実装することになっていて、
Socket.IO はメッセージを内部で Publish/Subscribe してから broadcast 等を行うようになってます。

で、デフォルトでは MemoryStore と Redis が選べるようになっていて、
MemoryStore の場合は Publish も Subscribe も実装がつぶされていて実際にはただのメソッド呼び出しになっている、
なのに対して、 Redis を選べばちゃんと Redis の Pub/Sub のラッパーになっている。

まとめると

  • MemoryStore

-- デフォルト準備要らず
-- スタンドアローンのローカルでのみ動く、スケールしない。
-- 要するに開発用

  • RedisStore

-- 要 Redis サーバ
-- Redis サーバ共有すれば簡単にスケール


という今まで独自でやっていた事が簡単にできるようになりそう。
また、インタフェースを実装すれば、他のストレージを指す事もできるはず。


これはヤバい。ちなみに実装は「まだ半分くらいまで」らしいです。期待!


データの紐づけ

Socket.IO API 解説 - Block Rockin’ Codes のデータの紐付けで書いたデータは、上述の store に入るよう。だからただスクリプトレベルでグローバルとかに代入した変数とちがって、分散サーバ間でちゃんと共有できる。

そして、 get(), set() 以外に has(), del() の実装を確認。
スケールアウトに結構まじめに取り組んでますね。


Static

/socket.io/hoge のように Socket.IO のサーバから配信すべきクライアントの js やら flash まわりのやつやらがごっそり変わってる。
まず、キャッシュ周りの設定や、 gzip が増えてる。
gzip は実際は node ではなく child-process 経由でローカルサーバの gzip コマンド叩いてるだけだから入ってなかったらならない。

  • 'browser client cache': true
  • 'browser client minification': false
  • 'browser client etag': false
  • 'browser client gzip': false


また、

 Regexp for matching custom transport patterns. Users can configure their own
 socket.io bundle based on the url structure. Different transport names are
 concatinated using the `+` char. /socket.io/socket.io+websocket.js should
 create a bundle that only contains support for the websocket.

とあって、スライドには実例として

  • '/socket.io/socket.io+websocket.js'
  • '/socket.io/socket.io+websocket.js+htmlfile.js'

みたいにすると websocket のみサポートするクライアントなど、URLからクライアントを動的にカスタムビルドできるみたい。
このビルドは node で行われてるな。イニシャルリクエスとだけだろうけどオーバーヘッドとか気になるところ。

ちなみに通信方法が変わったらクライアントのキャッシュは削除されて新しくキャッシュされるっぽい。

HTTPS

今までできたっけ?スタンドアローンサーバに key を渡せば、
HTTPS サーバで立てる事ができる。

  listen(80, {key:***}, function() {
    /* snip */
  });


ところで Socket.IO サーバをスタンドアローンで立てられるようになってからなのかわからないけど、
もし Express みたいな HTTPServer のインスタンスを渡したら、内部では一旦そっちのサーバに実装されたルーティングハンドラを全部奪って Socket.IO サーバが関心のあるリクエスとじゃなかった場合だけもとのサーバに処理されるリクエスとを改めて投げる実装になっているようだ。
ちょっと無駄な気がするのは気のせいかな?

逆に Socket.IO がわから HTTP へのリクエスとを渡す前に色々挟む余裕も有るのかも。(誰得だけど)

ちなみにサーバは必ずデフォルトレスポンスで

  res.writeHead(200);
  res.end('Welcome to socket.io.');

があって。これはサーバが起動してるかのテストに使えたりするよう。

というかもはやクロスオリジンなんだし、 Socke.IO サーバと普通の HTTP サーバ共存させる必要もないかとは思う。

Join

これはスライドにもまだなくて、 ML に流れてたのを @meso さんに教えてもらってから未だにアップデートがないんだけど、ネームスペースに関する結構便利そうな新機能。

まず `join()` を使うとネームスペースに Join できるらしい。

socket.join('room1', function(){
  /* snip */
});


出るのが `leave()`

socket.leave('room1', function(){
  /* snip */
});

メモ

  • hybi07, hybi10 サポート
  • flashsocket のポートが 843 から 10843 に変わってる。これで sudo いらないってことか。
  • send() の下に emit() があるんだけど、実はもう一個ローレベル API として packet() ってのがあって、これが実際は送信している。
  • test/common.js を盗めば大抵のテストが可能っぽい。それもそのうち書こう。

まとめ

かなり精力的で頼もしい。特に最近は Chrome とかの WebSocket の仕様が変更されたり、その Chrome が知らぬまで勝手にアップデートしてたりで色々あったけど、 Socket.IO の対応も早いので最新はわりといける。逆にブラウザも Socket.IO も両方最新じゃないと面倒だったりする。

とにかくまだまだ進化は続くようです。今もう v0.8 だからそろそろ v1.0 とかも視野に入れた話になってくるのかな。

東京Node学園祭2011 ではその辺の話も聞けるといいですね。