variable no longer in scope within a socket message fuction? - node.js

This is a file that listens to messages on port 5000.
The console.log(status) within the function listen seems to be printing true and false
However when exporting status to other files , I still get "none" instead of true and false ... Any suggestions?
var dgram = require('dgram');
var net = require('net');
var status="none";
var num=0;
var LOCAL_UDP_PORT=5000;
exports.listen=function(){
// TCP and UDP listeners
var sock = dgram.createSocket('udp4');
sock.on('message', function(msg, rinfo) {
try{
var obj = JSON.parse(msg);
if (obj.class == ".Announce") {
if(obj.dev.id == "BLA") {
status=true;
}
else
status=false;
}
console.log(status);
}
} catch(e){
// do nothing an err
}
});
sock.bind(LOCAL_UDP_PORT);
}
//Initialize
exports.status=status;
listen();

I guess the reason is, status take a string object, and when you do status=true/false, the reference changes, but exports.status would hold the original reference
try
var status={val:"none"};
...
status.val = true;
...
// in the module reading the value,
var status = status.val;

The incoming socket messages are asynchronous. That means they arrive sometime in the future. If you want to notify another module when they come in, then you will need to create a notification system and export the notification system so the other module can register an interest in getting notified.
You could create the notification system using an eventEmitter, using callbacks, using promises, etc... Why technique you choose would determine exactly what you would export and how the caller would register their interest.

Related

The behaviour of standard input's readable event in Node JS

I wrote a UDP client to send lines from standard input to an UDP socket:
var PORT = 12000;
var HOST = '127.0.0.1';
var dgram = require('dgram');
var client = dgram.createSocket('udp4');
process.stdin.on("readable",
function() {
var chunk = process.stdin.read();
if (chunk !== null) {
client.send(chunk, PORT, HOST);
}
}
);
client.on("message",
function (message, remote) {
process.stdout.write(message);
}
);
Now, the readable event fires on the first time but stops working afterwards.
I successfully used this on a TCP chat client and server before: I got a readable event infinitely.
What could cause the problem here?
The code works if I subscribe to the data event on standard input. That fires every time I type a new line into the standard input.
See data event documentation at Stream class.

How to emit socket to specific socket connection?

In my node app,
socket.on('test', function (req) {
controller.test(socket, req, 'test');
})
This way I store all users socket connections in server...
var userSockets = []; //Used to store all connected users data.
userSockets[user.id] = socket; // Storing whole socket object.
// E.x: userSockets[14] = socket; // Stored like this.
Function to get all socket data
getUserSocket() {
return userSockets;
}
Now I need to emit to the specific socket, I have tried this but I got an error.
let allUserSocketListData = databaseHelper.getUserSocket();
allUserSocketListData[result.data[0].id].emit('response' , data);
// E.x: allUserSocketListData[14].emit('response' , data);
Error:
.emit() is not a function.
Update
I have one function in that I'm storing all user's socket data.
validateUser(user, socket) {
... // My some code
userSockets[user.id] = socket;
}
Namespaces and rooms were build for that specific reason, but when you need something handy without extra code, sending emits directly can do job.
Here's a quick approach:
1: Your connection event should store the socket ID and not the whole object
let socketIds = []
socketServer.on("connection",(socket)=>{
socketIds.push(socket.id)
socket.emit("message", "hey")
})
2: Now if you want to send something on the first client only for example, you should first check if it's already registered and proceed with the emit.
if (socketServer.sockets.connected.hasOwnProperty(socketIds[0])){
socketServer.sockets.connected[socketIds[0]].emit("message", "hey again")
} else {
console.error("Error: Wrong Id")
}

How do I output a stream of tuples from a Storm spout with emit() and sync()?

(xpost github issue)
I'm new to Storm. I found the helpful node-storm library and I have successfully submitted topologies, but I can't get my spout to emit a stream of tuples.
node-storm's wordcount example works fine.
I want a spout that subscribes to a websocket and outputs any messages as tuples.
Here's my attempt so far. I think I have some misconfiguration, because I know I my wsEmitter is emitting future events, but my Storm UI shows zero spout emits.
I suspect that maybe I shouldn't be binding the listener inside the spout function?
Does this function get invoked multiple times? (looks like it... see https://github.com/RallySoftware/node-storm/blob/master/lib/spout.js#L4 )
What does sync actually do and when should I use it?
var storm = require('node-storm');
var wsEmitter = require('./wsEmitter.js')();
wsEmitter.init(); // subscribe to websocket
var futuresSpout = storm.spout(function(sync) {
var self = this;
console.log('subscribing to ws');
wsEmitter.on('future', function(data){ // websocket data arrived
self.emit([data]);
sync();
});
})
.declareOutputFields(["a"]);
Turns out I had two problems. First, my topology wasn't executing because one of my bolts (not shown) failed to set .declareOutputFields().
Second, I need to delay the emits from the spout until the supervisor asks for one emit with nextTick(). I did that by buffering any incoming messages until the supervisor calls the spout:
module.exports = (function(){
var storm = require('node-storm');
var wsEmitter = require('./wsEmitter.js')();
wsEmitter.init();
var queue = [];
var queueEmpty = true;
wsEmitter.on('thing', function(data){
var trade = JSON.parse(data);
trade.timeReported = new Date().valueOf();
queue.push(trade);
queueEmpty = false;
});
return storm.spout(function(sync) {
var self = this;
setTimeout(function(){
if(!queueEmpty){
self.emit([queue.shift()]);
queueEmpty =
( queue.length === 0
? true
: false )
}
sync();
}, 100);
})
.declareOutputFields(['trade'])
})()

What should I be using? Socket.io rooms or Redis pub-sub?

Pretty simple question. I am building a realtime game using nodejs as my backend and I am wondering if there is any information available on which one is more reliable and which one is more efficient?
I am heavily using both Redis and Socket.io throughout my code. So I want to know whether I should be utilizing Socket.io's Rooms or I would be better off using redis' pub-sub ?
Update:
Just realized there is a very important reason why you may want to use redis pub/sub over socket.io rooms. With Socket.io rooms when you publish to listeners, the (browser)clients recieve the message, with redis it is actually the (redis~on server)clients who recieve messages. For this reason, if you want to inform all (server)clients of information specific to each client and maybe do some processing before passing on to browser clients, you are better off using redis. Using redis you can just fire off an event to generate each users individual data, where as with socket.io you have to actually generate all the users unique data at once, then loop through them and send them their individual data, which almost defeats the purpose of rooms, at least for me.
Unfortunately for my purposes I am stuck with redis for now.
Update 2: Ended up developing a plugin to use only 2 redis connections but still allow for individual client processing, see answer below....
Redis pub/sub is great in case all clients have direct access to redis. If you have multiple node servers, one can push a message to the others.
But if you also have clients in the browser, you need something else to push data from a server to a client, and in this case, socket.io is great.
Now, if you use socket.io with the Redis store, socket.io will use Redis pub/sub under the hood to propagate messages between servers, and servers will propagate messages to clients.
So using socket.io rooms with socket.io configured with the Redis store is probably the simplest for you.
I ended up writing a node plugin to allow for many pub-sub clients but only require 2 redis connections instead of a new one on every single socketio connection, it should work in general, figured someone else may find use for it.
This code assumed you have socket.io running and setup, basically in this example any number of socket.io clients can connect and it will always still only use 2 redis connections, but all clients can subscribe to their own channels. In this example, all clients get a message 'sweet message!' after 10 seconds.
Example with socket.io (utilizing redis pub-sub):
var
RPubSubFactory = require('rpss.js');
var
redOne = redis.createClient(port, host),
redTwo = redis.createClient(port, host);
var pSCFactory = new RPubSubFactory(redOne);
io.sockets.on('connection', function(socket){
var cps = pSCFactory.createClient();
cps.onMessage(function(channel, message){
socket.emit('message', message);
});
io.sockets.on('disconnect', function(socket){
// Dont actually need to unsub, because end() will cleanup all subs,
// but if you need to sometime during the connection lifetime, you can.
cps.unsubscribe('cool_channel');
cps.end();
});
cps.subscribe('cool_channel')
});
setTimeout(function(){
redTwo.publish('cool_channel', 'sweet message!');
},10000);
Actual plugin code:
var RPubSubFactory = function(){
var
len,indx,tarr;
var
dbcom = false,
rPubSubIdCounter = 1,
clientLookup = {},
globalSubscriptions = {};
// public
this.createClient = function()
{
return new RPubSupClient();
}
// private
var constructor = function(tdbcom)
{
dbcom = tdbcom;
dbcom.on("message", incommingMessage);
}
var incommingMessage = function(rawchannel, strMessage)
{
len = globalSubscriptions[rawchannel].length;
for(var i=0;i<len;i++){
//console.log(globalSubscriptions[rawchannel][i]+' incomming on channel '+rawchannel);
clientLookup[globalSubscriptions[rawchannel][i]]._incommingMessage(rawchannel, strMessage);
}
}
// class
var RPubSupClient = function()
{
var
id = -1,
localSubscriptions = [];
this.id = -1;
this._incommingMessage = function(){};
this.subscribe = function(channel)
{
//console.log('client '+id+' subscribing to '+channel);
if(!(channel in globalSubscriptions)){
globalSubscriptions[channel] = [id];
dbcom.subscribe(channel);
}
else if(globalSubscriptions[channel].indexOf(id) == -1){
globalSubscriptions[channel].push(id);
}
if(localSubscriptions.indexOf(channel) == -1){
localSubscriptions.push(channel);
}
}
this.unsubscribe = function(channel)
{
//console.log('client '+id+' unsubscribing to '+channel);
if(channel in globalSubscriptions)
{
indx = globalSubscriptions[channel].indexOf(id);
if(indx != -1){
globalSubscriptions[channel].splice(indx, 1);
if(globalSubscriptions[channel].length == 0){
delete globalSubscriptions[channel];
dbcom.unsubscribe(channel);
}
}
}
indx = localSubscriptions.indexOf(channel);
if(indx != -1){
localSubscriptions.splice(indx, 1);
}
}
this.onMessage = function(msgFn)
{
this._incommingMessage = msgFn;
}
this.end = function()
{
//console.log('end client id = '+id+' closing subscriptions='+localSubscriptions.join(','));
tarr = localSubscriptions.slice(0);
len = tarr.length;
for(var i=0;i<len;i++){
this.unsubscribe(tarr[i]);
}
localSubscriptions = [];
delete clientLookup[id];
}
var constructor = function(){
this.id = id = rPubSubIdCounter++;
clientLookup[id] = this;
//console.log('new client id = '+id);
}
constructor.apply(this, arguments);
}
constructor.apply(this, arguments);
};
module.exports = RPubSubFactory;
I mucked around and tried to improve the efficiency as much as I could, but after doing some different speed tests, I concluded this was the fastest I could get it.
For up-to-date version: https://github.com/Jezternz/node-redis-pubsub

Writing data to a socket in Node

I'm getting a weird result when writing to a socket. I wrote a simple experiment with a client and a server:
server.js
var net = require('net');
net.createServer(function (connection) {
connection.on('data', function (data) {
console.log('data: ' + data);
});
}).listen(1337);
client.js
var net = require('net');
var client = net.connect({port: 1337}, function () {
var i = 0;
function send() {
client.write('a');
if (++i < 100) {
process.nextTick(send);
} else {
client.end();
}
}
send();
});
I expected the server to show 100 lines of data: a, but I ended up getting a smaller number of data: aaaaaaa lines. There's socket.setNoDelay() that seems to be what I want, but it doesn't seem to have any effect.
What am I missing?
Thanks a lot,
The TCP protocol only sends exactly the bytes you write in the socket. They will not be separated into messages, that's up to you. If you would like to get 100 lines of a then you would have to define 100 separate messages, and choose a delimiter for them. Usually people delimit messages sent to a TCP socket by \r\n.
So you would need to change your server to
var net = require('net');
net.createServer(function (connection) {
connection.on('data', function (buffer) {
var data = buffer.toString();
if (data.indexOf('\r\n') > -1) { // If there's more than one line in the buffer
var lines = data.split('\r\n'); // Split the lines
var i = lines.length;
while (i--) { // This will read your lines in reverse, be careful
console.log(lines[i]); // Print each line
}
} else {
console.log(data); // If only one line came through, print it
}
});
}).listen(1337);
And your client to
var net = require('net');
var client = net.connect({port: 1337}, function () {
var i = 0;
function send() {
client.write('a\r\n'); // Notice the \r\n part. This is what will help you separate messages on the server
if (++i < 100) {
process.nextTick(send);
} else {
client.end();
}
}
send();
});
And then I believe you would get 100 lines of a.
This module also provides a very interesting way to do it, and of course ZeroMQ would also shine in this because it already has a nice protocol that puts things in envelopes and sends them.
Also interestingly but out of the scope of your question, the messages you send write to the socket on one side will not arrive in the same order on the server. If you change your send function to
function send() {
if (++i < 100) {
client.write('a'+i+'\r\n');
process.nextTick(send);
} else {
client.end();
}
}
you can see them arriving not in the order you sent them.
By "The TCP protocol only sends exactly the bytes you write in the socket" I mean that if you do socket.write("1"); socket.write("2"), you will receive "12" on the server, because that's what you wrote on the socket. You have to explicitly separate your messages by something so that the server can know when a message starts and when a message ends.
About receiving things in order or not, you'll notice that if you remove the process.nexTick and have your client like:
var net = require('net');
var client = net.connect({port: 1337}, function () {
var i = 100;
while (i--) {
client.write('a'+i+'\r\n');
}
});
you'll get two messages on the server (at least I got): first numbers 83 - 99 and then 0 - 82, despite having wrote them in order.
Its because TCP splits it in packets in some magic way. The first package was actually larger than the second one, so it got there last. You can read more about how TCP works in the wikipedia page of course, and this video is probably going to say more than what you need to hear but its good to understand everything you're working with.

Resources