socket.io で動的に名前空間(namespace)を追加する方法

導入

node.js で socket.io を使って、なんかゲーム作れないかな?と最近いろいろ試している。
そこで、例えばこういうケース

  • ユーザが「部屋の新規作成」を選ぶと、新しいチャットルーム的なものができる

に対応する場合、動的に名前空間を追加したくなる。

本題

socket.io で動的に名前空間を追加する際の情報って意外と少ないし、
なんか良さげな方法が見つかりにくいのでとりあえず自分が使っている方法を残す。

説明

クライアント側で、接続時に ID を送る

socket.io は「クライアントがサーバに接続した時」というフックを持っている


[サーバ側]

  io.configure(function () {
    io.set('authorization', function (handshake, callback) {
      // 処理
    });
  });


上記のようにかける。
また、クライアント側からはハンドシェイク向けのデータを送信することもでき、


[クライアント側]

  var con = io.connect('http://localhost:3000?debug=1');


上記のように、クエリストリングに書くことができる。
つまり、ID を debug=1 の部分に埋め込めば、ソケットサーバ側で ID をとれるということになる。

名前空間(namespace)は動的に追加できる

また、socket.io は動的に名前空間を定義でき、それは、authorization のタイミングでも可能。
上記を踏まえて、このように記述できる。


[クライアント側]

/**
  * 名前空間 /chat/1 を指定し、
  * id=1 をソケットサーバに送信
  */
var socket = io.connect('http://localhost:3000/chat/1?id=1');


[サーバ側]

io.configure(function () {
  io.set('authorization', function (handshake, callback) {

  /**
    * クライアントからきた id=1  の部分を取得
    * /chat/1 名前空間が存在しなければ、io.of('/chat/' + id) で作成する。
    */
    var id = handshake.query.id;
    if (!io.namespaces.hasOwnProperty('/chat/' + id)) {
      var room = io.of('/chat/' + id);
      room.on('connection', function (socket) {
        // 処理
      });
    }

    callback(null, true);
  });
});
上記を踏まえた全体の流れ

上記を踏まえてこのような動作が可能になる。

  1. ユーザは、「チャットルームの作成」リンクをクリックする
  2. サーバ側で、 MySQL などにチャットルームの 1 レコードを作成する
  3. クライアントを、チャットルームページに飛ばし、その際に2で作ったチャットルームの ID をページに埋め込む
  4. クライアント側からチャットルームの特定の名前空間に接続する
  5. この際、「名前空間がない && MySQL にチャットルームのレコードが存在する」場合、名前空間を作る
  6. クライアントは、元々指定していたチャットルームの ID の名前空間に接続する

終わりに

上記の流れで、動的に名前空間を作れるようになり、チャットルーム自体もサーバ側で管理できるようになる。

もっといい方法があれば教えてください。