1
votes

I am writing a simple chat on socket.io with node.js server. So I need to know in which room socket is. For example, socket has connected and joined a room. So, when this socket sends a message I want to broadcast it only to the sockets that are in that room (sck.broadcast.to(it_room).emit).

io.on("connection", function(sck) {
  ...
  sck.join(availableRoom);
  sck.on("message", function(msg) {
    sck.broadcast.to(**its room**).emit(msg);
    sck.emit(msg);
  });
  ...
});

I do not need an array of sockets and information about them (in which room etc).

2

2 Answers

1
votes

You first enter your username and chat room that you join. Once you submit the form, username and room info will be appended URL as query string. in browser: location.search :this is how we reach to query strings. We have to parse it.

add this CDN to your main.html

<script src="https://cdnjs.cloudflare.com/ajax/libs/qs/6.6.0/qs.min.js"></script>

this cdn for npm querystringify package. since it will be headache to setup npm package in clients side, cdn is easier to handle it. make sure cdn script files should be loaded first before other js files in hour html. once this cdn is loaded we can use:

const { username, room } = Qs.parse(location.search, { ignoreQueryPrefix: true })

{ ignoreQueryPrefix: true } this option will omit the "?" from query string.

once you reached username and room name, we can emit our event from client side.

client.js

socket.emit('join', { username, room }, (error) => {
    if (error) {
        alert(error)
        location.href = '/' //will keep the client in the same url
    }
})

now we gotta listen to this event from server side. but we have to keep track of users.

index.js

io.on("connection", socket => {

  socket.on("join", ({ username, room }, callback) => {
    //we have to define addUser function


let users = [];

const addUser = ({ id, username, room }) => {
  // Clean the data
  username = username.trim().toLowerCase();
  room = room.trim().toLowerCase();

  // Validate the data
  if (!username || !room) {
    return {
      error: "Username and room are required!"
    };
  }

  // Check for existing user
  const existingUser = users.find(user => {
    return user.room === room && user.username === username;
  });

  // Validate username
  if (existingUser) {
    return {
      error: "Username is in use!"
    };
  }

  // Store user
  const user = { id, username, room };
  users.push(user);
  // users=users.push(user) this will cause error
  return { user };
};
//as you see this function will return either error or user object

//Socket generates an id upon connection.
//result is either error or user
    const { error, user } = addUser({ id: socket.id, username, room });

    if (error) {
      return callback(error);
    }

    socket.join(user.room);//socket joined to this room
    //now time to emit a new event
    socket.emit("message", ( "Welcome!"));
    socket.broadcast
      .to(user.room)
      .emit(
        "message",
        (`${user.username} has joined!`)
      );


//broadcast will send messages to everyone in the chat room except the connected socket

    callback(); //success scenario. let the client knows that it is allowed to connect
  })   
})
0
votes

Try with the following, but I am not sure if it works in every situation.

Object.keys(sck.manager.roomClients[sck.id])[1]

I found this by logging socket, then I looked up for rooms information and extract it the way you can see in my code.


I am using 0.9.6 socket.io version, maybe there is a different solution for latest version.