Home > Enterprise >  Socket.io socket.rooms is returned empty
Socket.io socket.rooms is returned empty

Time:12-13

I have written a simple Socket.io backend and am trying to check now if the socket has joined the room already or not.

According to the documentation:

socket.rooms

should return a list of rooms the socket has joined. However, for me this seems to be always an empty array.

Below is a quick example code for my server side to demonstrate the issue:

const express = require('express');
const app = express();
const http = require('http');
const https = require('https');
const fs = require('fs');
require('dotenv').config();

function isJsonString(str) {
    try {
        JSON.parse(str);
    } catch (e) {
        return false;
    }
    return true;
}

function relayMessage(room_id,msg){
    io.to(room_id).emit('chat message', msg);   
    console.log('Relay msg to room: '   room_id);
}

function joinRoomAndMessage(room_id,socket,msg){
    //Join the room.
    socket.join(room_id);
    console.log('Joined Room: '   room_id);
    
    //Relay the first message.
    relayMessage(room_id,msg);
}

//Create the server.
var server = null;
if(process.env.SSL_KEY_FILE.length>0){
    //If the key file is defined in .env, try to start the server in https mode.
    
    const options = {
      key: fs.readFileSync(process.env.SSL_KEY_FILE),
      cert: fs.readFileSync(process.env.SSL_CERT_FILE)
    };
    
    server = https.createServer(options, app);
    console.log('Starting server in HTTPS mode');
}else{
    //If the key file is not defined in .env, start the server in http mode.
    server = http.createServer(app);
    console.log('Starting server in HTTP mode');
}
const { Server } = require("socket.io");
const io = new Server(server);

app.get('/', (req, res) => {
  res.sendFile(__dirname   '/index.html');
});

io.on('connection', (socket) => {

  console.log('a user connected');
  socket.on('disconnect', () => {
console.log('user disconnected');


 });



socket.on('chat message', (msg) => {
  
console.log('message: '   msg);
// Always expect JSON messages.
if(isJsonString(msg)){
    const msgJSON = JSON.parse(msg);
    // Always expect the JSON to have a room_id.
    if(msgJSON.room_id){
        
        console.log("LIST OF ROOMS:" JSON.stringify(socket.rooms));
        
        if(!Object.keys(socket.rooms).includes(msgJSON.room_id)){
            
            joinRoomAndMessage(msgJSON.room_id,socket,msg);
            
        }else {
            relayMessage(msgJSON.room_id,msg);
        }
    }else{
        console.log('No relay. The server is expecting a room_id.');
    }
}else{
    console.log('No relay. The server is expecting JSON message.');
}
  });
  
});

// use port 3000 unless there exists a preconfigured port
const port = process.env.PORT || 3000;

server.listen(port, () => {
    console.log('listening on *:' port);
});

Also, below is a console log, when I push three messages to the same socket using this the above code:

Starting server in HTTPS mode
listening on *:3000
a user connected
user disconnected
a user connected
message:  {"room_id":"12345","msg":"Test message"}
LIST OF ROOMS:{}
Joined Room: 12345
Relay msg to room: 12345
message:  {"room_id":"12345","msg":"Test message 2"}
LIST OF ROOMS:{}
Joined Room: 12345
Relay msg to room: 12345
message:  {"room_id":"12345","msg":"Test message 3"}
LIST OF ROOMS:{}
Joined Room: 12345
Relay msg to room: 12345 

Does anyone have any ideas why the array is empty or other ways to check which rooms the socket is currently in?

Best regards,

Olli

P.S. This post (socket.rooms returns empty array) mentioned that I might have to wait before the socket.rooms is populated, however I get still get an empty array when sending next message to the socket that is already open and joined the room, hence I am thinking my issue must be something else.

CodePudding user response:

socket.rooms on the server-side is a Set object. You need to use proper methods for accessing it and logging it.

For example:

console.log(JSON.stringify(socket.rooms))

will not show you anything in it because there are not enumerable properties on a Set which is all JSON.stringify() looks for.

Instead, do this:

console.log("LIST OF ROOMS:", socket.rooms);

to let console.log directly see it as a Set and output it's items.


Also, this:

 if(!Object.keys(socket.rooms).includes(msgJSON.room_id))

is kind of crazy to do on a Set object. You should be doing this instead:

 if (!socket.rooms.has(msgJSON.room_id))

and use the built-in capabilities of the Set object (that's what it's for).

In reality, you don't even have to check for that as you can just always .join() because it doesn't cause any problem to .join() something you're already in. So, just join and then send the message every time.

  • Related