How to get Socket to send to the requesting client only? - javascript

I am having an issue practicing with socket.io. I have a function set up, where on connection, the users data is refreshed, only it seems to only be happening AFTER the initial connection.
When one user connects, nothing on new user refreshes. Aditional new user connects, Old connection refreshes, but new connection remains untouched.
Am I not able to send data during connection?
This is just some simple practice for me, trying to get better with websockets, and can't seem to get past the general broadcast.emit.
I have tried socket.to(socket.id).broadcast.emit, of course, however no luck there either. You will see in my code.
// Setup socket.io
socketIo.on('connection', socket => {
getDataByUser(user, socket)
socket.on('disconnect', function() {
delete CLIENTS[socket.id];
console.log(`${username} disconnected`)
});
function getDataByUser(user, socket) {
var items = [1,2,3];
items.forEach(element => {
socket.broadcast.emit('server:data', element)
socket.broadcast.to(socket.id).emit('data', 'for your eyes only');
});
}
As you can see in the getData function, I use both a general emit, and an emit to, in order to test it. I have proper listeners set up, however the socket itself is only refreshed apon a new connection. Perhaps this is only called when socket a makes a new connection?
I would like to have this function called imediately apon socket connection. for only the user who has connected. Any help would be greatly appreciated.

I think the way you can deal with this is to not broadcast it.
Try to emit only to the socket who got connected at that time.
I did not get what you are trying to achieve so if the code below does not resolve you problem please say what output do you expect.
socketIo.on('connection', socket => {
var items = [1,2,3];
items.forEach(element => {
socket.emit('server:data', element)
socket.emit('data', 'for your eyes only');
});
socket.on('disconnect', function() {
socket.disconnect();
console.log(`${username} disconnected`)
});
when you use the socket object you adress to that client only...the one who establised the connection.

Related

SignalR multi user live chat desynchronisation

I have a live chat in which multiple people would be connected simultaneously. All public messaging works fine, but sometimes private messaging to a specific id doesn't work. I believe i narrowed it down to when people disconnected and reconnected that they connected to a different instance (perhaps IIS had recycled and started a new hub).
I thought I had fixed it, but I haven't and now I'm here because I'm stuck. What I thought would fix it was changing the connection variable within the startChat() function to refresh it with the correct information.
This is a cut down version of the code, as I didnt thing the rest would be necesary.
Issue is that when connected to signalR recipients of a message directly to them doean't come through, even though the chat Id it's being sent to it correct. Possible hub/socket mismatch?
var chat = $.connection.chatHub;
$(document).ready(function () {
// Start the chat connection.
startChat();
//restart chat if disconnected
$.connection.hub.disconnected(function () {
setTimeout(startChat(), 5000);
});
$.connection.hub.error(function (error) {
$('#messagebar').html('Chat ' + error + '. If this message doesn\'t go away, refresh your page.');
});
chat.client.addToChat = function (response) {
$('#chat-' + response.Type).prepend(response.Message);
};
});
function startChat() {
chat = $.connection.chatHub;
$.connection.hub.start().done(function () {
//get recent chat from db and insert to page.
//also saves user's chat id to their user for lookup when private messaging
$.ajax({
method: 'POST',
url: '/api/Chat/SetupChat/'
});
$('#messagebar').html('Connected to chat.');
});
}
Any help appreciated, Thanks.
Not sure exactly how your message is going missing, but you should send messages to a User instead of by connection id. This way you be able to identify on the server that a User has at least one connection, and send messages to all connections for that User. if a given connection id is no longer valid, but another one is (because the client has refreshed the page for example) the message wont be lost.
From the docs https://learn.microsoft.com/en-us/aspnet/core/signalr/groups:
The user identifier for a connection can be accessed by the
Context.UserIdentifier property in the hub.
public Task SendPrivateMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", message);
}
Not sure how this relates exactly to your server code, but you could add it if you're unclear how to progress.

Socket.io kick specific user

I have an event from the client side that passes the socket id to be kicked to the server, socket.emit('kick', socketId);.
My intention is to find the socket using this socketId server side, and then call socketToBeKicked.disconnect(). How do I find the specific socket? I tried looking at other posts but most of the solutions do not work anymore. Or is there a better way that I can implement the kick function?
I figured out a solution. Instead of trying to find the socket obj on the server side, we can emit an event from the server to the client to that is going to get kicked and emit another event back to the server to get the client's socket obj.
client.js
socket.emit('kick', socketId); // sent by the host
socket.on('kick helper', () => { // sent by the user getting kicked
socket.emit('kick helper');
}
server.js
socket.on('kick', (socketId) => {
socket.to(socketId).emit('kick helper');
}
socket.on('kick helper', () => { // now this socket obj is the user getting kicked
socket.disconnect();
}
It still feels like quite a long way around to get the socket object of the user to be kicked. Please share if you have a better solution, I would love to know!

Socket.io reconnection causes new username

I am creating a chat in node.js and socket.io.
When a user opens my application, I ping the server and ask it to let the user join a specific room and set a random username (which can be edited at a later stage).
I use this
io.on('connection', (socket) => {
socket.on('join room', (roomId, callback) => {
// leave and join room
if (socket.roomId) {
socket.leave(socket.roomId);
}
socket.roomId = roomId;
socket.join(roomId);
// set username
if (!socket.username) {
socket.username = getRandomUsername();
}
});
});
It seems to work, but I have experienced situation where I have had the application running for a long time, and suddenly the user's username has changed.
I am suspecting this to occur because the user has lost connection, and socket.io have tried reconnecting. When the user has reconnected, the original socket is lost (and therefore it has no username), and a new username is assigned to the new socket, which overrides the original client socket.
Is there a problem with my code by assigning a random username to the user like this? It is somehow the same Google Docs does when the user is not signed in (they often give you an animal's name).
How can I solve the problem? I would very much like to avoid using cookies. An option could probably be to tell the client that it lost connection, and it has to reload the page, and then ask the server to get the same username.
I already save the assigned username on the client with this code:
const socket = io();
let username = null;
socket.on('connect', function() {
socket.emit('join room', roomId, function (newUsername) {
username = newUsername;
});
});
(...)

How can I connect a node.js server page to my sockets server as though it were a client?

I've seen many similar questions here, like this one about connecting servers to sockets, however, that doesn't seem to be working.
My goal is to have one of my server pages occasionally emit an "advance" event to all of the connected clients. My sockets server listener (sockets.js) looks like this
io.on('connection', function (socket) {
socket.on('advance', function () {
console.log('advancing clients');
io.emit('advance');
});
});
and my other server page (queue.js) has this code
var socket = require('socket.io-client');
socket.connect('localhost:5000');
socket.on('connect', function () {
socket.emit('advance');
});
I have also tried
var socket = require('socket.io-client');
socket.connect('localhost:5000');
socket.emit('advance');
Both of those were in the other question I linked, however both of those failed. In the case of the first example, I received the error
socket.on is not a function
and on the second
socket.emit is not a function
it would seem that socket.connect worked, however, socket.on and socket.emit both failed. The idea is that queue.js will emit an event to all the clients, so they know to request the next song from the server.
As bonus points, I happen to be using passport.socketio to authenticate my users (though I don't seem to be getting the "ioAuthFail" message that would normally occur when a user attempts to connect and is not authenticated).
for what it's worth, my socket authentication code looks like
io.use(passportSocketIo.authorize({
//cookieParser:
key:'user',
secret:'secret',
store:new MongoStore({mongooseConnection:mongoose.connection}),
success:onAuthorizeSuccess,
fail:function(){console.log('ioAuthFail')}
}));
If there's a better way to advance the clients than using socket.io, i would also accept that, but for now it seems like this is the best way for me, assuming I can get this working.
EDIT
as mentioned through comments, changing my code to
var io = require('socket.io-client');
socket = io.connect('localhost:5000');
socket.on('connect', function () {
socket.emit('advance');
});
socket.emit('advance');
doesn't break it, but it doesn't work, either.

Socket.IO socket.id changing for same client without reconnect

I'm making an application where I need to map sockets to some object. I thought I would be safe using the socket.id variable provided by Socket.IO. Unfortunately while debugging I found out that the socket.id changed without the client disconnecting/reconnecting or whatever.
Here's a small piece of code to show what I'm trying to do:
var io = require('socket.io').listen(8080),
var myVariable = new Array();
// Main event loop
io.sockets.on('connection', function (socket) {
socket.on('myEvent', function(data) {
myVariable[socket.id] = data;
}
// 'someOtherEvent' which uses the mapped data.
socket.on('someOtherEvent', function(data) {
// Doesn't always work because socket.id has changed and var is empty
doSomethingWith(myVariable[socket.id]);
}
});
I'm not sure but I don't think this is the desired effect. Why does this happen and how would I work around it?
I was using node-inspector to debug my application and because I was holding the code on some breakpoint it disconnected the client (probably some timeout client side). That's why I got a new socket.id when I continued the code execution.
Looks like 'someOtherEvent' emited before 'myEvent' or socket has been reconnected. I use socket.id as connection identifier on two different projects in production and it works without any problems.

Categories