9

I wanted to associate an object called player to different sockets. So I thought the easiest way to do that is to just socket.prototype.player = whatever;

But no matter what I try to prototype I keep getting undefined. Anyone have an idea on how to accomplish this ? Also IDK if this is bad practice. Let me know.

2
  • 1
    It's probably "just" an object, so try using socket.player = whatever. Commented Jun 6, 2016 at 7:35
  • I think we need to see if there's more to your code. Are you also using a client side socket.io? If so, what does your emit looks like in the server? Commented Jun 6, 2016 at 7:47

4 Answers 4

20

A socket.io socket is just a Javascript object. You can add any property to it directly, not through the prototype.

So, on the server, you could just add a new property to the socket object directly:

io.on('connection', function(socket) {
    // some code to get the name for this user
    var name = .....
    socket.player = name;
});

Properties like this are not shared with the other end of the connection - they are local to this particular object and are only available on this side of the connection.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks bro, you're like a freaking Ninja O_O, Or I'm really slow... Let's go with the former
How to do this in typescript? I tried redeclaring the Socket object but it didn't work
@MohammadKazemzadeh - I'd suggest you ask your own question about how to do this in TypeScript. Just mention you want to add your own property to an already existing socket.io socket object.
2

Since you did ask about best practices, it's not advised to modify the prototype of the type that's not in your control or use custom variables on top of it. While JavaScript is rather loose and lets you make these changes, you should guard yourself against any further changes to the prototype that Socket.IO may make in the future.

The reason is that there's always a chance, however small, of there being a collision with whatever property name you're using.

To get around this, we can either use a Map related to the socket ID, or use a WeakMap on the socket itself. If you use a Map, you have to remove the entry manually when the socket is disconnected, but with a WeakMap, it's garbage collected automatically (assuming SocketIO releases all references to it on disconnect).

  /** @type {WeakMap<SocketIO.Socket, Object>} */
  const socketIOLocals = new WeakMap();
  io.use((socket, next) => {
      const locals = { player: null }; // Create new instance
      socketIOLocals.set(socket, locals);
      next();
  });

You can then get the variable object with socketIOLocals.get(socket);


On a side note, Express does have the .locals property to let you pass data between Response objects. It's a shame SocketIO doesn't have something like this.

1 Comment

this is actually best :)
1

You can also handle online users pairing them with their socket id like this

io.on('connection', function(socket){
  socket.on('disconnect', function() {
    console.log("disconnect")
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].socket === socket.id){
        console.log(onlineplayers[i].code + " just disconnected")
        onlineplayers.splice(i, 1)
      }
    }
    io.emit('players', onlineplayers)
  })

  socket.on('lobby_join', function(player) {
    if(player.available === false) return
    var exists = false
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].code === player.code){
        exists = true
      }
    }
    if(exists === false){
      onlineplayers.push({
        code: player.code,
        socket:socket.id
      })
    }
    io.emit('players', onlineplayers)
  })

  socket.on('lobby_leave', function(player) {
    var exists = false
    for(var i = 0; i < onlineplayers.length; i++ ){
      if(onlineplayers[i].code === player.code){
        onlineplayers.splice(i, 1)
      }
    }
    io.emit('players', onlineplayers)
  })
})

Comments

0

Solution as of Dec 2017 (socket.io innards changes more often than one might assume). In this version I've created a join_exclusive function which will leave all rooms, except the default room and the new room you want to join

io.sockets.on('connection', function(socket) {
    socket.join_exclusive = function (newroom) {
        for (var room in this.manager.roomClients[this.id]) {
            if (room == '') continue; // default room required for socket.emit(...
            this.leave(room.slice(1)); // remove '/' char
        }
        this.join(newroom);
    };
});

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.