rubyではなくNodeのSocket.io上にlindaを実装しようと思っていて、そのために

  • socketio clientをグループに分けるroom機能について知りたい
  • socketioを拡張するnpmをどうやって実装するのがいいのか調べる
必要があったので、chatを作った。


このようにshebangごとに部屋が別れる。

最近websocketがherokuで使えるようになったのでherokuに置いた。

ソースコード https://github.com/shokai/socketio-chat-study


実装

サーバーもクライアントも40行ぐらいでできた。express等WAFは使っていなくて、HTMLやJSをサーブする部分はhttpモジュールで書いた。
httpのインスタンス作る時にsocketioのインスタンスを食わせると、socketio.jsなどが生えるという仕様は面白い。nodeにはWSGI/Rack/PSGIのような物が必要ないように見える。


roomにクライアントを追加するには、サーバー側でsocket.join(‘部屋名’)で追加する。
クライアントが切断されてもroomから自動的に抜けてくれるわけではなく、その部屋に新しいクライアントをjoinした時にようやく切断済みクライアントがリストから取り除かれる。
なのでクライアントのdisconnectイベントでleaveさせた。

client.coffee
接続できたら、shebangから部屋名を決めてサーバーに”join_to_room”イベントを送る
socket.on 'connect', ->
room =
if (shebang = location.href.match(/#([^#]+)$/))
shebang[1]
else
'room1'
socket.emit 'join_to_room', room ## 部屋に入れてもらう

server.coffee
新規クライアントが接続してきて、”join_to_room”が来たら部屋に入れる。onceなので複数の部屋に1つのクライアントが入ることはない。
io.sockets.on 'connection', (socket) ->
socket.emit 'chat', {msg: 'hello new client!'}

## クライアントを部屋に追加する
socket.once 'join_to_room', (room) ->
console.log "<#{socket.id}> join_room to \"#{room}\""
socket.join room

## echo to room
socket.on 'chat', (data) ->
console.log "<#{socket.id}> #{data.msg}"
io.sockets.to(room).emit 'chat', data ## 部屋の全員にecho

socket.once 'disconnect', ->
socket.leave room ## 切断したら部屋から退去
notify_rooms()

notify_rooms()

## 現在存在する部屋名と人数を全クライアントに通知
notify_rooms = ->
rooms = {}
for name, ids of io.sockets.manager.rooms
## 全てのクライアントはデフォルトで "" という部屋に入っている
## "/" から始まる部屋名はshebangで指定された部屋
if name.match /^\/.+$/
name = name.replace /^\//, ''
rooms[name] = ids.length
io.sockets.emit 'rooms', rooms


Herokuでwebsocket

Using WebSockets on Heroku with Node.js | Heroku Dev Center

コマンド1発でherokuでwebsocketが使えるようになる。
heroku labs:enable websockets


Herokuへのデプロイは簡単で、

  • websocket proxyが通るように、httpとwebsocketは同じportにする
  • 環境変数PORTを読んでwebサーバーを起動する
  • 起動コマンドをProcfileに書く
  • npmの依存パッケージはpackage.json
さえ守っていればすぐHerokuに置けるというのは便利