Node.js
Socket.io
websocket

socket.io 1.0 のハンドシェイク(セッション共有)

More than 3 years have passed since last update.

socket.io 1.0 では connect っぽく middleware として書けるようになりました。

socket.io 1.0 のハンドシェイク!

socket.requestRequest オブジェクトが受け取れるのでそれを利用します。
(以下、Express 4.x の場合)

server.coffee
Session = require('express-session').session.Session

COOKIE_SECRET = 'himitsu-dayo'
COOKIE_KEY    = 'sid'

#
# 途中省略
#

# Socket.io
io = require('socket.io')(server)

# セッション共有
io.use (socket, next)->

    # クッキーからセッション ID を取得する
    cookie = require('cookie').parse socket.request.headers.cookie
    cookie = require('cookie-parser/lib/parse').signedCookies cookie, COOKIE_SECRET
    sessionID = cookie[COOKIE_KEY]

    # セッション情報を取得する
    sessionStore.get sessionID, (err, sessionData)->

        # セッション情報の取得成功!
        if !err and sessionData

            # 新しく Session を作成
            socket.session = new Session({sessionID: sessionID, sessionStore: sessionStore}, sessionData)
            next()

        # セッション情報の取得失敗 :(
        else
            next if err then err.message else 'ハンドシェイク失敗だよ!'

# 接続
io.on 'connection', (socket)->

    # セッション!
    session = socket.session 

    #
    # 以下いろいろ
    # 

※ 0.9 までの connect.utils.parseSignedCookies は使えなくなったようです。 cookie-parser モジュールを使いましょう。

ちなみに・・・ socket.io 0.9 までのハンドシェイクは

0.9 までは下のように、 io.set('authorization', fun); のように書いていました。

server.coffee
io.set 'authorization', (handshakeData, callback)->

    # クッキーからセッション ID を取得する
    cookie = require('cookie').parse decodeURIComponent handshakeData.headers.cookie
    cookie = connect.utils.parseSignedCookies cookie, COOKIE_SECRET
    sessionID = cookie[COOKIE_KEY]

    # セッション情報を取得する
    sessionStore.get sessionID, (err, sessionData)->

        # セッション情報の取得成功!
        if !err and sessionData

            # 新しく Session を作成
            handshakeData.session = new Session sessionID: sessionID, sessionStore: sessionStore, sessionData
            callback(null, true)

        # セッション情報の取得失敗 :(
        else
            callback (if err then err.message else 'ハンドシェイク失敗だよ!'), false 

#
# 以下省略
# 

並べてみるとあまり変わらないように見えるけど、 middleware として書けることでセッション共有以外にもいろいろやりやすくなったと思います。

私のプロジェクトではハンドシェイクの後に middleware でユーザ情報を取り出したりとか書いたりしてます。

Store

タイトルのハンドシェイクとはあまり関係ないけど Store についても軽く触れておきます。

別のプロセスやサーバ間で共有するための store は Adapter という仕組みで実現します。

0.9 までは socket.ioRedis 用のクラスが最初から用意されてたけど、1.0 (pre4) では用意されてないようです。

現状、 Redis を使う場合は別の開発者の socket.io-redis がよさそうです。

こんな感じで、

server.coffee
# Redis アダプタ
RedisAdapter = require('socket.io-redis')(host: 'localhost', port: 6379)

# Socket.io
io = require('socket.io')(server, { adapter: RedisAdapter })

ソースを軽く覗いたら Pub/Sub とか勝手にやってくれそうな感じ。

最後に

この記事はまだ正式リリース前の socket.io 1.0.0-pre5 をベースに書いています。
たぶん正式版でも動く...はず!

1.0.2 で動きました。

こちらからは以上です。