ぶれすとつーる

だいたいjavascript

socket.ioで特定ユーザーにemitしたい時

最近socket.ioがメジャーバージョンになって少しかわって

今まで

io.sockets.socket(id).json.emit('msg', send_msg);

みたいな感じでかけてたのですがsockets (namespace)がsocketメソッドを持たなくなってて、「 あれ特定ユーザ探す方法なくね」って思ってたんだけどドキュメントよんでたら

Each Socket in Socket.IO is identified by a random, unguessable, unique identifier Socket#id. > For your convenience, each socket automatically joins a room identified by this id.

This makes it easy to broadcast messages to other sockets:

Socket.IOの各ソケットはランダム、推測できない、ユニークな識別子のソケット#IDで識別されます。あなたの便宜のために、各ソケットは自動的にこのIDで識別される部屋に参加します。 これにより、簡単に他のソケットにメッセージを配信することができる

ってあるの見つけた。

各socketは自動的にIDで識別される部屋に参加するってあるっていってるのでそのルームに対してemitするのってどうしたらいいんだろっておもったらその辺うまくやってくれるsocket#to見つけた。

(メジャーバージョン以前からこのAPIはあったんだけど)

Socket.prototype.to =
Socket.prototype.in = function(name){
  this._rooms = this._rooms || [];
  if (!~this._rooms.indexOf(name)) this._rooms.push(name);
  return this;
};

渡されたname(sokecet#id)を見て次の通信のためのroomを指定できる感じになってる そして実際に送信するsocket#emitみると

Socket.prototype.emit = function(ev){
  if (~exports.events.indexOf(ev)) {
    emit.apply(this, arguments);
  } else {
    var args = Array.prototype.slice.call(arguments);
    var packet = {};
    packet.type = hasBin(args) ? parser.BINARY_EVENT : parser.EVENT;
    packet.data = args;

    // access last argument to see if it's an ACK callback
    if ('function' == typeof args[args.length - 1]) {
      if (this._rooms || (this.flags && this.flags.broadcast)) {
        throw new Error('Callbacks are not supported when broadcasting');
      }

      debug('emitting packet with ack id %d', this.nsp.ids);
      this.acks[this.nsp.ids] = args.pop();
      packet.id = this.nsp.ids++;
    }

    if (this._rooms || (this.flags && this.flags.broadcast)) {
      this.adapter.broadcast(packet, {
        except: [this.id],
        rooms: this._rooms,
        flags: this.flags
      });
    } else {
      // dispatch packet
      this.packet(packet);
    }

    // reset flags
    delete this._rooms;
    delete this.flags;
  }
  return this;
};

となってて基本的に対象となるroomに対してイベントを配信してるっぽい。

※送信後roomは都度消去される

ということなんで最初かいてたこれ

io.sockets.socket(id).json.emit('msg', send_msg);

これをroomを使ったイベント配信に書き換えると

socket.to(id).json.emit('msg', send_msg);

みたいにできてよしなに動いた。

Namespaceにも同様の実装の#toあったり、Serverもdefault namespace .of('/') のtoにaliasはってあるのでこんな感じにサーバーから直接呼ぶ事もできる

io.to(id).json.emit('msg', send_msg);