cannot emit sIo.sockets.clients() - node.js

It seems that socket.io cannot send the list of connected users, like this:
socket.emit('users', sIo.sockets.clients());
It gives me the following error:
/Users/enrico/Desktop/helloExpress/node_modules/socket.io/lib/parser.js:75
data = JSON.stringify(ev);
^
TypeError: Converting circular structure to JSON
Apparently it cannot stringify the returned value from sIo.sockets.clients() Any ideas on how to fix this? Thanks in advance.

Since the problem is a circular reference there no real 'fixing it'. Circular reference means that some object in the structure points to another part of the object, making an infinite loop. What you can do is something like this.
var returnList = [];
var clients = sIo.sockets.clients(); // grab list of clients, assuming its an array
for(var i = 0; i < clients.length; i++) {
var client = clients[i]; // next client in array
// push values into return list
returnList.push({
name: client.name,
someOther: client.value,
another: client.thing
});
}
// emit cleaned up list
socket.emit('users', returnList);
With this code you can cherry pick the values you want and send only those. This is good for several other reasons. Since this clients list is likely an internal implementation is might also send information about other clients connection.
This is all also pretty speculative as I'm not 100% what libraries you're using, looks like Socket.IO but I cannot find any socket.clients() method.

Related

web3js subscribe logs to fast for Javascript to handle

I am using web3js to subscribe to logs, I listening to swap events, the problem is that the .on(data) is so fast in giving data JavaScript can not keep up. lets say I add a variable let count = 0; each time I get a new log I increase the number ++count, sometimes the logs come so fast I get a double number.
The real problem is I need it to be in the exact order as it is coming in, that's why I give the number to each log, but that does not work.
How would I make sure that each data item I get from the log events that they are in order?
I tried to create a promise sequence
let sequence = Promise.resolve();
let count = 0;
web3.eth.subscribe('logs', {
fromBlock: block,
topics: [
[swapEvent]
]
}).on('data', (logData)=>{
sequence = sequence.then(()=>{
++count
processData(logData)
})
});
function processData(){
return new Promise(resolve=>{
// do some stuff
resolve();
})
};
In a simple test with a loop and random time to resolve this works fine, but in the actual code with socket it does not keep the order.
Anyone has some idea how I can make the socket data keep in order and process one by one?
Not sure why but my problem got solved with this.
sequence = sequence.then(()=>processData(logData))
before it was
sequence = sequence.then(()=>{
processData(logData)
})
Now its doing all in sequence.

Copying a websocket not possible in Node.js?

So, I want to move a websocket instance on my Node.js server from one array to the other. I use JSON.parse(JSON.stringify(theitem)), and it sticks in there just fine - but then it gives me a peculiar error.
var ws = require("ws");
var server = new ws.Server({server:app.server, path:"/whatever", port:8080})
var clients = [];
var OtherClients = [];
server.on("connection", function(socket){
socket.send("Hello!"); // This works.
socket.on("message", function(msg){console.log("whatever");})
clients.push({socket:socket, OtherInformation:"whatever!"});
NextFunction();
})
function NextFunction(){
for(let i = 0; i < clients.length; i+=2){ // Every second one, meant to represent arbitrary logic...
clients.forEach(TheClient=>{
TheClient.socket.send("Arbitrary string!"); // This one works.
})
}
OtherClients[0] = JSON.parse(JSON.stringify(clients[clients.length-1]));
clients.splice(0,1);
OtherClients[0].socket.send("Another arbitrary string!"); // Crash here.
}
This gives me the error TypeError: OtherClients[0].socket.send is not a function. How?
Moreover, I noticed that socket.send is not actually a member of the socket object (even in the original version where I can send it). What's going on?
Am I really not allowed to copy a WebSocket object, or am I missing the point entirely?
You can't stringify a webSocket object and then parse it back into a functioning object. A webSocket object represents a local TCP connection and can't easily be serialized like that.
If you just want to move the socket object from one array to another, you can just take the socket object and add it to another array, no serialization to JSON necessary. You could do it like this:
// remove last socket from clients array and
// add it to the beginning of the OtherClients array
OtherClients.unshift(clients.pop());

Destroy socket before or after removing it from array

In my node.js application I have a collection of client sockets as an array. When a communication error occurs, I simply call destroy on the socket.
My question is: should I destroy the socket before or after removing it from the array? The documentation doesn't say much.
var clientSockets = []
var destroySocketBefore = function(socket) {
socket.destroy()
var socketIdx = clientSockets.indexOf(socket)
if (socketIdx > -1) {
clientSockets.splice(socketIdx, 1)
}
}
var destroySocketAfter = function(socket) {
var socketIdx = clientSockets.indexOf(socket)
if (socketIdx > -1) {
clientSockets.splice(socketIdx, 1)
}
socket.destroy()
}
In the case of destroySocketBefore, I am not sure if the socket will be found in the array if I destroy it before searching for it, so there is a possibility that array still incorporates invalid sockets in subsequent logic.
In the case of destroySocketAfter, I am not sure if calling destroy on a socket that was removed from array will have the desired result. Is there a possibility that the system will delete the socket object after splicing the array, so sometimes I get to call destroyon a null object.
I tested and it seems that both methods work as there is no difference between them, so I am not sure which method is the correct one.
Either solution is valid and the two are effectively the same. The destroyed socket will get removed no matter what since there are no race conditions or anything like that (since javascript execution in node all happens on the same thread).
splice will only remove the socket from an user defined array and will have no effect to it been closed, therefore the second method is the best option according to your answers.

Xively and Node-Red

I'm fairly new at all this but have muddled my way to getting my Arduino to post values to a Xively stream I've named "Lux and Temp." Three values; count, lux, and temperature.
Now what I want to do is take those values and do something with them using Node-Red.
http://nodered.org
I have Node-Red up and running, but I'll be danged if I can figure out how to parse the data from the Xively API feed. https://api.xively.com/v2/feeds/1823833592
Sadly, I don't have enough reputation points to be able to actually post the data it returns to here, since it has more than 3 URLs embedded in the data. It's a LONG string of data too. ;)
I'm just stumped though as to how to write the function to extract the parts I want.
My initial want is to make a simple Twitter feed out of it. Something like;
"Count 40, Lux 30, Temp 78.3"
I'll eventually want to recycle the code for other things like making my RasPi do something; maybe a display or some LEDs. In either case I need to parse the data and build various messages with it.
Anybody have any experience with the Node-Red functions that can walk me through a solution? The Node-Red site is pretty awesome, but I think it assumes I'm a MUCH more experienced user than I really am. It gives hints, but frankly about all I know is fairly basic Arduino and trivial level Python.
OK, it shouldn't be too tricky, but try putting this in a function block:
var newPayload = "";
var count, lux, temp;
var data = msg.payload.datastreams;
for (var i = 0 ; i< data.length; i++) {
if (data[i].id === 'Count') {
count = data[i].current_value;
}else if (data[i].id === 'Lux') {
lux = data[i].current_value;
} else if (data[i].id === 'Temp') {
temp = data[i].current_value;
}
}
newPayload = util.format('Count: %s, Lux: %s, Temp: %s', count, lux, temp);
msg.payload = newPayload;
return msg;
You may need to add a msg.payload = JSON.parse(msg.payload); to the start if however your getting the feed from xively is not already considered to be json.
[edit]
You could also just run the flow through a JSON parse node. (I always forget the converter nodes)
You should be able to wire that to a twitter output node.

node - send large JSON over net socket

The problem is that sending large serialized JSON (over 16,000 characters) over a net socket gets split into chunks. Each chunk fires the data event on the receiving end. So simply running JSON.parse() on the incoming data may fail with SyntaxError: Unexpected end of input.
The work around I've managed to come up with so far is to append a null character ('\u0000') to the end of the serialized JSON, and check for that on the receiving end. Here is an example:
var partialData = '';
client.on( 'data', function( data ) {
data = data.toString();
if ( data.charCodeAt( data.length - 1 ) !== 0 ) {
partialData += data;
// if data is incomplete then no need to proceed
return;
} else {
// append all but the null character to the existing partial data
partialData += data.substr( 0, data.length - 1 );
}
// pass parsed data to some function for processing
workWithData( JSON.parse( partialData ));
// reset partialData for next data transfer
partialData = '';
});
One of the failures of this model is if the receiver is connected to multiple sockets, and each socket is sending large JSON files.
The reason I'm doing this is because I need to pass data between two processes running on the same box, and I prefer not to use a port. Hence using a net socket. So there would be two questions: First, is there a better way to quickly pass large JSON data between two Node.js processes? Second, if this is the best way then how can I better handle the case where the serialized JSON is being split into chunks when sent?
You can use try...catch every time to see if it is a valid json. Not very good performance though.
You can calculate size of your json on sending side and send it before JSON.
You can append a boundary string that's unlikely be in JSON. Your \u0000 - yes, it seems to be a legit way. But most popular choice is newline.
You can use external libraries like dnode which should already do something I mentioned before. I'd recommend trying that. Really.
One of the failures of this model is if the receiver is connected to multiple sockets, and each socket is sending large JSON files.
Use different buffers for every socket. No problem here.
It is possible to identify each socket individually and build buffers for each one. I add an id to each socket when I receive a connection and then when I receive data I add that data to a buffer.
net.createServer( function(socket) {
// There are many ways to assign an id, this is just an example.
socket.id = Math.random() * 1000;
socket.on('data', function(data) {
// 'this' refers to the socket calling this callback.
buffers[this.id] += data;
});
});
Each time you can check if you have received that "key" delimiter that will tell you that a buffer is ready to be used.

Categories

Resources