Socket.io - send different data to sender and clients? - javascript

I am learning NodeJS and Socket.IO and have been following the various tutorials dotted about, mainly focusing on making a basic chatroom.
My app works so far: being able to send messages with clients being able to move to different "rooms".
Now I am trying to tidy it up and make it look the part.
I am stumbling with the follow idea:
When user A moves form room A to B, an emit() method is sent to update an array with a user count, which in turn is sent back to the sender. A list of rooms in a side panel is then updated e.g. Room A (0), Room B (1).
Now, emitting the new data to the sender is easy and works, the room list gets updated, and the other rooms (that the sender is not in) have hyperlinks (this is how the user moves between rooms)
But I want to send data to the other clients, so their room lists also get updated. Sending the same data as before means the other clients's rooms list is incorrect, as the data is referencing the new room name the sender joined, not the room the other client is currently in.
Some code:
socket.on('switchRoom', function(data) {
var newroom = sanitize(data).escape().trim();
socket.leave(socket.room);
socket.join(newroom);
socket.room = newroom;
socket.emit('updaterooms', rooms, newroom);
// this is the problem area, socket.room should be the socket.room data for the non-sending client
//socket.broadcast.emit('updaterooms', rooms, socket.room);
});
How would I emit to all other clients (not the sender) with the data contained in their own socket "session" (i.e. socket.room)?

You will need to emit a generated message that's catered to each socket. What you will need to do is iterate through each socket, emitting the custom message based on each socket, for example:
io.sockets.on('connect', function(socket) {
socket.on('switchRoom', function(data) {
var newroom = sanitize(data).escape().trim();
socket.leave(socket.room);
socket.join(newroom);
socket.room = newroom;
socket.emit('updaterooms', rooms, newroom);
io.sockets.clients.forEach(function(client) {
if (socket != client) {
client.emit('updaterooms', rooms, client.room);
}
});
});
});

Related

Socket.io + express rooms

I am working on an online website with real-time chat and I've been trying to set up socket.io rooms for a few days now, but one of my custom events just doesn't emit.
My website has 2 paths, / and /play. When someone fills out a form in the / path, the website redirects them to the /play path.
const io = require('socket.io')(listener);
io.on('connection', socket => {
socket.on('add user', data => { // This event gets emitted when the user submits the form at `/`, in a client-side js file.
socket.username = data.username;
socket.room = data.room;
socket.score = 0;
socket.join(data.room);
io.sockets.in(data.room).emit('user joined', { // This event gets 'handled', in another (not the same one) client-size js file.
username: data.username,
room: data.room
});
});
socket.on('disconnect', function () {
io.sockets.in(socket.room).emit('user left', {
username: socket.username,
room: socket.room
});
socket.leave(socket.room)
});
});
In the other client-side js file:
var socket = io.connect();
let joined = 0;
socket.on('user joined', data => {
joined++;
console.log(joined, data)
const elemental = document.createElement("LI");
const info = document.createTextNode(data.username);
elemental.appendChild(info);
document.getElementById('people').appendChild(info)
});
The add user event code executes just fine, but the user joined one doesn't..
I'm almost certain that it has to do with the paths. I read on socket.io namespaces but it seems like they are just like a different type of rooms.
Can someone tell me what's wrong?
EDIT: I should mention that no errors come up.
Without seeing your whole code, I'm going to assume that the socket on client-side.js code, is not joined to the data.room room, and that's why you don't get anything on the 'user join' event listener and that happens because you probably have multiple socket.io connections on the client side code.
You have multiple ways to solve this, depending on what you're trying to achieve.
Instead of only emitting to people on the room, emit to all sockets that an user joined a specific room. io.emit('user joined') instead of io.sockets.in(data.room)...
There should only be one single var socket = io.connect(); on the front end, otherwise the socket that's emitting: add user and therefore joined to data.room is not the same socket that's listening on: user joined, and that's why you never get the event on that socket, because you have 2 different sockets, one that joined the room, and one that is doing absolutely nothing except waiting for an event that will never occur.

How to create dynamic socket rooms using socket.io

I want to implement multiple chat using socket.io can, iwas able to implement one to one chat using one socket.room but i want to create multiple socket rooms to chat with multiple people parallel
below is the example i got in git but i was not able to understand that how it will work for multiple chat can any one explain
Server side
io = socketio.listen(server);
// handle incoming connections from clients
io.sockets.on('connection', function(socket) {
// once a client has connected, we expect to get a ping from them
saying what room they want to join
socket.on('room', function(room) {
socket.join(room);
});
});
// now, it's easy to send a message to just the clients in a given
room
room = "abc123";
io.sockets.in(room).emit('message', 'what is going on, party
people?');
// this message will NOT go to the client defined above
io.sockets.in('foobar').emit('message', 'anyone in this room yet?');
Client side
// set-up a connection between the client and the server
var socket = io.connect();
// let's assume that the client page, once rendered, knows what room
it wants to join
var room = "abc123";
socket.on('connect', function() {
// Connected, let's sign-up for to receive messages for this room
socket.emit('room', room);
});
socket.on('message', function(data) {
console.log('Incoming message:', data);
});
Imagine a user with multiple Chat Room to choose. When he click on a specific room he will get the information of it : in this example ChatRoom1.
The client socket (belonging to the user who has click on this room) has first to join this room
→ so that's why we have :
socket.emit(room, ChatRoom1)
// on the other part the server side will add the socket id of this client to this room :
socket.on('room', function(room) {
socket.join(room);
});
Now if you want to emit a message to all socket belonging to a specific room you use this command on the server part:
io.sockets.in(ChatRoom1).emit('message', 'what is going on, party
people?');
→ in fact this command just send a message to all socket who is belonging to ChatRoom1
→ Basically a Room is just an array of socketId
SO now on the client side you have this :
socket.on('message', function(data) {
console.log('Incoming message:', data);
});
this is just a listener, and you will get in console log :
Incoming message: what is going on, party people?
As you soon you enter in a chatRoom your socket join a room and will listen for each event until you ask the socket to leave the room
So now you can imagine that in your message you have your Id , Your Room ID and your content, when you send it the server will know where to send it.
Example:
message: {
content: 'blabla',
user: me,
date: now,
RoomId: ChatRoom1
}
On the client side each time a user send a message:
socket.emit('sendMessage', message)
On the server side:
socket.on('sendMessage', function(message){
io.sockets.in(message.RoomId).emit('message', message);
})

is it possible to send data using socket.io-node just to chosen group of users?

how could I implement chat with different rooms? I don't want .broadcast() to send data to all logged in users.i just want to send the data to specific user
I've just completed doing something very similar with a game.
I maintain a list of all socket objects with the socket ID as the key. This allows me to emit a message at any time to one particular user.
On registering:
var sockets = [];
sockets[socket.id] = socket;
To emit:
// pass in needed socket ID from client
sockets[socketID].emit('message-name', message);
If you have specific questions share your code and I'll help as much as I can.
If you want to send a message to a group of users, you need to create a room for them & then emit a message. doc: https://socket.io/docs/rooms-and-namespaces/#joining-and-leaving. Following code snippet might be helpful
The user class used
User = {
constructor(socketID, socket) {
this.socketID = socketID;
this.socket = socket;
}
}
subscribe user's socket to the room
var users = [user1.socketID, user2.socketID, user3.socketID];
var room = 'room';
users.forEach(function (user) {
user.socket.join(room);
});
Then emit the message in the room
io.to(room).emit('messageInRoom', message);

Socket.io add two clients to room

I'm trying to implement private messaging in an app im creating using express 3 and socket.io
When a client connects a room with the clients userid is automatically created and joined. This is mainly for notifications and that sort of stuff. Now im trying to make this work for private chat too.When a user clicks the send button, the message gets sent along with the userid of the sender (from session userid) and the userid of the owner thats grabbed from a hidden field or attribute of element. And the sender joins the room with the owners userid namespace. The problem with this is that when the sender goes to another page or refresh the browser he is diconnected from the room, and doesnt recieve any further messages from the owner. He has to send a new message to rejoin the owners room. Now how do i percist the connection to the owners room? Or am i doing this all wrong? Is there a better or standard way to achieve this?
SERVER:
io.on('connection', function (socket) {
var sh = socket.handshake;
socket.join(sh.session.userid);
socket.on('chat', function (data) {
if (data.user) {
socket.join(data.owner);
}
io.sockets.in(data.owner).emit('chat',
{user: sh.session.user, message: data.message});
});
});
CLIENT:
var socket = io.connect('https://localhost/');
$('#send_message').click(function (e) {
socket.emit('chat',{message: $('.message').val(),
user:$('#user'), owner:$('#owner')} //Get this from hidden fields in chat form );
e.preventDefault();
});
socket.on('chat', function (data) {
$('ol').prepend('<li>' + data.user + '<br />' + data.message + '</li>');
});
Right. Because when you reload the page, the server gets a "client disconnected" message and unsubscribes the socket. The client will need to re-emit a 'chat' message (with same owner id) in order to get back onto the private feed.
One way is to have the client save the owner id in a cookie and recall it on every page load. Alternatively, you could have the server store and recall this info using a session cookie (http://www.senchalabs.org/connect/session.html), which, in essence, is much like the first option.

Sending to Subset of Users in Room/Channel with Socket.IO

I'm building a web application with Node (Express) and Socket.IO that has chat functionality. Because opening a new tab on a page establishes a new socket connection, I need to group all instances of a single user into their own room based on the Express session ID to enable all messages aimed at said user to appear in all duplicate tabs. This is in addition to any other room/channel they might already be logged into. At a minimum, users are subscribed to two chatrooms: the actual "real" room, and their own channel using the sessionID.
The problem is that all of the sockets for my sessionID are also in the more general room (and need to be to get messages from other users). When I send out the general chat message I'd like to omit any sockets corresponding to the sending user, as they have already received the message through their own channel. I've gone ahead and made a hash of arrays containing lists of socketIDs for that session, keyed on the sessionID. I've seen a few different syntaxes for specifying exception lists, but none seem to work for me.
The relevant code, with certain parts omitted for brevity:
var sessionSockets = {};
io.sockets.on('connection', function(socket){
if(!io.sockets.manager.rooms["/" + sessionID]) {
sessionSockets[sessionID] = [];
//send message indicating log on to all sockets except for my session
}
socket.join(sessionID); //create private channel for all sockets of the same sessionID
sessionSockets[sessionID].push(socket.id);
socket.on('chat', function(data){
var payload = {
message: data.msg,
from: data.user
};
//send back as personal message to all sockets for this session
io.sockets.in(sessionID).emit('me',payload);
//send to everyone else as regular message; WHAT SYNTAX?
io.sockets.in('').except(sessionSockets[sessionID]).emit('chat', payload);
}
}
tl;dr: How can I send a message to a subset of users in a channel/room without manually doing a comparison of arrays?
use socket.join('room') and then emit to the room by using socket.in(socket.room).broadcast.emit.
This is how you can group clients in a room and emit a perticular example to room

Categories

Resources