get contents of the request object in socket.io - node.js

I am new to socket.io and I try to tell apart every client that connects to my node server.
I want to send data to just one client, not broadcast the same data to all of them. So, I have to find a unique piece of each client.
If I got it, I have to do something like
io.on('connection', function (socket) {
var origin = socket.request;
console.log("hey, so , new ws connection is > "+origin);
});
but I get [object, Object].
What are the contents of this object, so I can get something unique like an id. Also what other data this object contains that may come handy in the future?
Thanks
UPDATE
I saw the socket.id. But, everytime I refresh, the id changes. I want something to be stable, otherwise if the client refreshes for some reason, will no longer be related with the first id. Any tips?

every connect have socket.id is unique, if you use socket-io adapter you can use socket handshake info. on Browser for geting socket.id try
$(function () {
setTimeout(function () {
$("#socketId").val(socket.id);
},100);
});
if console.log you will see socket.id in future

You'd use the socket.id property to get hold of the unique identifier for the socket (client socket).
As for other data this object contains, there are plenty that are useful, but the usefulness is dependant on the application. Have a look at the following link for available properties/methods on the socket object. http://socket.io/docs/server-api/
Some very useful methods are emit, join, leave, to, in and properties include id and rooms.

Related

Storing custom objects in WebSocket in Node.js

I'm using a WebSocketServer. When a new client connects I need to store data about that client as a custom object for each client and I want to be able to store it in the WebSocket so when the server receives a new message from that client I can quickly access my custom object from the WebSocket itself. Is there any way to do this or do I just have to create a map for all my objects and lookup the object from the WebSocket each time based on it's ID? Thanks
The Map idea will work to lookup each connection's data, but there's also no reason why you can't just add your own custom property to the webSocket object.
wss.on('connection', socket => {
socket.userInfo = {someProperty: 'someValue'};
socket.on('message', data => {
console.log(socket.userInfo);
});
});
Then, the .userInfo property will be available any time you get a message on that socket object.
Keep in mind that this info is temporal and only good for the lifetime of the socket object. So, if the client disconnects and reconnects (such as when changing web pages), that will generate a new socket object that will not have the previous .userInfo property on it. So, if that information needs to persist longer than the lifetime of one connection, you will have to store it elsewhere and index it by some persistent user property, not just the socket object.

How to set id of a socket in WebSocket?

I'm using: https://github.com/websockets/ws as websockets.
In socket.io you could give an id to your sockets like:
io.emit('id','myText');
io.on('id',function(data){
//read data
});
In websocket on the server you can read sockets by id.
ws.on('id', function (data) {
};
You can read sockets by id on the client too.
ws.addEventListener('id', function (data) {
};
But I couldn't find how to send a socket with a specific id, I've also checked the code base. Am I missing something or is this impossible? Or are there some hacks that could achieve this?
//I want this:
ws.send('id','myText');
I'll format my comments into an answer since it appears to have explained things for you:
There is no handler for your own message names like this in webSocket:
ws.on('id', function(data) { ... });
Instead, you listen for data with this:
ws.on('message', function(data) { ... });
If you want to send a particular message name, you send that inside the data that is sent. For example, data could be an object that you had data.messageName set to whatever you want for each message.
It appears like you're trying to use a socket.io API with a webSocket. That simply doesn't work. socket.io adds a layer on top of webSocket to add things like message names. If you want to use that type of layer with a plain webSocket, you have to implement it yourself on top of a webSocket (or just use socket.io at both ends).

Sending sockets to client side, Error: Converting circular structure to JSON

I'm working in node JS and I'm trying to send an array, with my clients, from the server to every client with a normal emit, but it keeps giving me this error:
data = JSON.stringify(ev);
TypeError: Converting circular structure to JSON
Shortly, this is what I do.
var clients = new Array();
io.sockets.on('connection', function(socket) {
clients.push(socket);
socket.on('loginUser', function(data){
io.sockets.emit("getUsers", clients);
});
I've seen a couple of other people having this problem, but all those answers didn't work out for me.
Looking at the bigger problem, you can't just send an array of sockets to the client side. Sockets are objects which only make sense in their current context/process. If you want to control the sockets from client side, I just instead add some sort of RPC functionality.

Adding data to a socket.io socket object

I am trying to add some custom information to my socket object on connect, so that when I disconnect the socket, I can read that custom information.
IE:
// (Client)
socket.on('connect', function(data){
socket.customInfo = 'customdata';
});
// (server)
socket.on('disconnect', function () {
console.log(socket.customInfo);
});
Since it is JavaScript you can freely add attributes to any object (just as you did). However socket.io does give you a built-in way to do that (so you won't have to worry about naming conflicts):
socket.set('nickname', name, function () {
socket.emit('ready');
});
socket.get('nickname', function (err, name) {
console.log('Chat message by ', name);
});
Note that this is only on one side (either client or server). Obviously you can't share data between client and server without communication (that's what your example suggests).
The socket in your browser and the socket in the server won't share the same properties if you set them.
Basically you have set the data only at the client side (which is in your browsers memory NOT on the server).
For anyone still looking for an answer, there are a couple of things you can do to share data from the client to the server without actually sending a message.
Add a custom property to the auth property in the client socketIo options. This will be available to the server event handlers in socket.handshake.auth.xxxx.
Add a custom header to the transportOptions.polling.extraHeaders property in the client socketIo options. This will ONLY be presented when the socket.io client is connected via polling and not when "upgraded" to websockets (as you can't have custom headers then).
Add a custom query property to the client socketIo options. I don't recommend this since it potentially exposes the data to intermediate proxies.

How to avoid race conditions from client disconnections?

So, what I am doing right now is creating a new client object as new connections are received, and storing them within a self managed object; on user disconnect, I am removing the object. This is the basis of what it looks like:
var socketobj = {};
io.sockets.on('connection', function(socket){
socketobj[socket.id] = socket;
socket.on('disconnect', function(data){
delete socketobj[socket.id];
});
});
I am using each of these client objects to store extra information, such as associated usernames etc. in the form of socketobj[socket.id].user = username;
The issue I am having is that a separate portion of my code will be running, and if the client disconnects just prior to the server accessing their client object, it will come up as undefined (because the object has just been deleted), and it will throw an exception.
How can I prevent this from happening? At the very minimum, how can I stop the errors from crashing my server everytime they are thrown?
Ok, I didn't know it was event based not multithreaded, here's a new answer.
Just check if the entry exists before accessing it. If it does not, it just got deleted and you can do nothing/a different thing as is appropriate.

Resources