node: custom emitter backing up when socket.io connection is established - javascript

I have a spawn function that is continuously outputting new information. I'm monitoring the output of that spawn via the 'data' event and emitted a custom emitter that I call 'updated' that emits whenever new data is received from the spawn. After each 'data' event occurs the data stored in partialData is emitted with the 'updated' emitter and then cleared.
This seems to work fine but when socket.io is implemented, the 'data' event seems to be ran but the results in partialData don't get processed, pile up on each other, and then several occurrences of the 'data' event get emitted at once. Why is this occuring and how do I resolve this issue? In the real application I'm using this in JSON strings are being handled and the pileup is causing node to crash.
This example is a simplified version of a larger application but the symptoms are the same. The following example consists of a bash script to emit a timestamp every 1/5th of second which should be ran from the same directory as the node code. After you launch the node command the terminal will output the timestamp and length of partialData. You will notice a change in the length of partialData whenever you browse to 127.0.0.1:3000. This is the issue.
emitter.sh:
#!/bin/bash
while [[ 1 ]]; do
echo `date +%s`
usleep 20000
done
emitter.js:
var express = require('/usr/local/lib/node_modules/express');
var http = require('http');
var spawn = require('child_process').spawn;
var events = require('events');
var util = require('util');
var app = express();
var server = http.createServer(app);
var io = require('/usr/local/lib/node_modules/socket.io').listen(server);
runCommand = function (arg1) {
var self = this;
var partialData = '';
var cmd = spawn(arg1);
cmd.stdout.setEncoding('utf8');
cmd.stdout.on('data', function(data) {
partialData += data.substr(0,data.length-1);
console.log('data: '+partialData.trim());
console.log('length: '+partialData.length);
partialData = '';
self.emit('updated', data);
});
}
util.inherits(runCommand, events.EventEmitter);
var result = new runCommand('./emitter.sh');
app.get('/', function(req, res){
res.send(
"<script src='/socket.io/socket.io.js'></script>\n"+
"<script>\n"+
"var socket=io.connect('http://127.0.0.1:3000');\n"+
"</script>\n"
);
});
server.listen(3000);
io.sockets.on('connection', function(webSocket) {
console.log('socket established');
});

There's no guarantee that the data event will be triggered every time your shell script has outputted a line; when other I/O takes place (like your socket.io example), the output is allowed to be buffered.
If you want line-support, you can use the readline module:
var cmd = spawn(arg1);
cmd.stdout.setEncoding('utf8');
var linereader = require('readline').createInterface(cmd.stdout, cmd.stdin);
linereader.on('line', function(line) {
...
});

Related

NodeJS - where to place functions for eval()

I have a NodeJS-Server which communicated with the fronend via Websocket-Connection.
When the Server gets a on('message'), it should run a function which name is given the message via eval().
it workes fine, unless I completely don't know where to put the funcions to be called.
var http = require('http');
var ws = require('ws');
function render(vars) {
var server = http.createServer(function(req, res) {
.....
});
/* WEBSOCKET */
var wsServer = new ws.Server({server});
wsServer.on('connection', socket => {
socket.on('message', message => {
console.log('WS from template <-- ', message);
var wsIn = JSON.parse(message);
eval(wsIn.action);
});
});
}
when a message is incoming, eval(wsIn.action) should run a function called.. .lets assume runme.. so where would I now need to declare this function ? I try everything but whatever I do, i get
ReferenceError:: runme is not defined
edit:
I found out something interesting:
when i call a function normal like runme(); in my onMessage.. everything is cool.. but with eval(runme); nothing happens.. no error, no output, nothing..

Why does this loop break my code?

Fair warning, I am a novice with javascript and ool. I am trying to put together a simple script to parse data out to a web socket. The script should be able to handle an infinite number of payloads.
This code works, although can only handle on payload at a time:
#!/usr/bin/env node
var io = require('socket.io-client');
var i=1
socket = io.connect('http://10.0.9.1:80');
var data = JSON.parse(process.argv[2]);
socket.on('connect', function(){
console.log('Emitting');
socket.emit('widget', data);
process.exit(0);
});
Wrapping the code in a loop with a logic test breaks it. No syntax errors, but it does not seem to call the emit method.
#!/usr/bin/env node
var io = require('socket.io-client');
var i=1
var data
while (true) {
i++
if ( process.argv[i] ) {
socket = io.connect('http://10.0.9.1:80');
data = JSON.parse(process.argv[2]);
socket.on('connect', function(){
console.log('Emitting');
socket.emit('widget', data);
});
} else {
process.exit(0);
};
};
The sockets you are creating are async, so you end up creating a bunch of sockets and then call process.exit(0) before there's time to establish the connection
There were many mistakes in my first attempt. Clues from ControlAltDel and mrid made me realize my loop structure was all wrong. The loop should have been placed within the on('connect') like so:
#!/usr/bin/env node
var io = require('socket.io-client');
var i=1
var data
socket = io.connect('http://10.0.9.1:80');
socket.on('connect', function(){
while (true) {
i++;
if ( process.argv[i] ) {
data = JSON.parse(process.argv[i]);
console.log('Emitting ');
socket.emit('widget', data);
} else {
process.exit(0);
};
}
});

Using Socket.IO from Node.js to connect to external server

Background: I have a node.js server running on my localhost (call this Server A); and an external server running node.js at https://example.net:3000 (call this Server B). I do not control or have access to Server B (it is a dashboard site for an IoT device in my home), but I need to connect to is using socket.io and emit a specific message.
I can connect to it easily from a flat javascript file (client-side), but need it running server side (ultimate goal is to make it into something I can call with an HTTP request); and examples such as How to connect two node.js servers with websockets? suggest I should be able to use socket.io-client from node.js with nearly the same code to achieve the same results. But when I run the code from node.js, I cannot connect to the socket.
Below is the code that works successfully in flat javascript file. I know it works because I see 'socket connect' in the console, and I can also test for the the socket emit at the end.
var myemail = "email#gmail.com";
var device_id = '12345';
// Create SocketIO instance, connect
var socket = io.connect('https://example.net:3000');
socket.on('connect', function(){
try {
console.log('socket connect');
socket.emit('configure', {email:myemail, deviceid:device_id});
} catch(e) {
console.log(e);
}
});
socket.emit("/" + device_id, "45678");
...and below is the code I cannot get to work when running from my node.js instance. I'd expect a message 'socket connect' in the command line log and get nothing.
var express=require('express');
var http=require('http');
var app=express();
var server = http.createServer(app);
//Variables
var myemail = "email#gmail.com";
var device_id = '12345';
var io = require('socket.io-client');
var socket = io.connect('https://example.net:3000');
//Connect listener
socket.on('connect', function(){
try {
console.log('socket connect');
socket.emit('configure', {email:myemail, deviceid:device_id});
} catch(e) {
console.log(e);
}
});
socket.emit("/" + device_id, "45678");
Any ideas?
UPDATE
Ran debug utility, results included as linked image below. Key thing I see is that engine.io tries to do an xhr poll, and gets a 503 response back from the server. (Obviously not a true 'temporary error' with the server as again, this all works from running client-side js in chrome).
debugging output image link
Solved this - issue was that the server I was connecting to required use of https, so I needed to add
{secure: true, rejectUnauthorized: false}
after the url to connect to.
Full working example:
const myemail = email#email.com;
const device_id = 12345;
io = require('socket.io-client');
var socket = io.connect('https://server.net:3000',{secure: true, rejectUnauthorized: false});
function doStuff(){
//Listener
socket.on('connect', function(){
try {
console.log('socket connect');
socket.emit('configure', {email:myemail, deviceid:device_id});
} catch(e) {
console.log(e);
}
});
socket.emit("/" + device_id, "003021");
}
doStuff();
I think the line causing the issue is :
var socket = io.connect('https://example.net:3000');
I managed to make a working example using this code :
const myemail = "email#gmail.com";
const device_id = '12345';
var socket = require('socket.io-client')('https://example.net:3000');
socket.on('connect', function(){
try{
console.log('socket connect');
socket.emit('configure', {email:myemail, deviceid:device_id});
}catch(e){ console.log(e); }
});

Socket.IO undefiend variable

I am using socket.io to create an interactive graph app. on the server side have a graph variable. When the user loads the page a test event is sent to the server, which sets up the variable and returns it to the users. I have a second event for node dragging, but when i try to drag the node the server says that the graph's nodes and link variables are undefined.
var express = require('express'),
app = express(),
http = require('http'),
socketIo = require('socket.io');
var server = http.createServer(app),
io = socketIo.listen(server);
var graph = {nodes : [], links : []}
server.listen(8080, function(){
console.log('server is listening on localhost:8080');
});
app.use(express.static(__dirname + '/'));
io.on('connect', function(socket){
// dump some test data
socket.on('test', function(){
// this just creates a few nodes in an array
var data = { ... }
graph = data;
io.emit('test', graph);
});
socket.on('eventNodeDragStart', function(index){
console.log('event node drag start: ' + index);
// undefiend, the graph.nodes is empty here
console.log(graph.nodes[index] + "\n\n");
// cannot read property of undefined
// also missing error handler on 'socket'
if(graph.nodes[index].locked) return;
graph.nodes[index].locked = true;
io.emit('eventNodeDragStart', index);
});
});
Solved the problem by replacing this line:
io.on('connect', function(socket){
with this:
io.sockets.on('connect', function(socket){
Not sure why it works, but it does.

socket.io won't emit messages

I am having troubles with app.io.emit('admin', 'balls'); inside of the games.js file. The emits inside of the io.on('connection' output in the browser.
/bin/www
var app = require('../server'); //Which has references to games.js
app.set('port', process.env.PORT || 4001);
var server = app.listen(app.get('port'));
var io = require('socket.io')(server);
io.on('connection', function (socket) {
socket.emit('admin', { hello: 'received' });
socket.on('admin', function (data) {
console.log(data);
});
});
app.io = io;
/app/controllers/admin/games.js
// inside server.js -> require('games.js')(app);
module.exports = function(app) {
//.....Other stuff
app.io.emit('admin', 'balls');
});
Html
script(src="/js/socket.io-1.3.5.js")
script.
$(function () {
var socket = io();
socket.on('admin', function (data) {
console.info(data);
});
})
console output on page load in Chrome
WebSocket connection to 'ws://localhost:4000/socket.io/?IO=3&transport=websocket&sid=QxjoI-yYF54oaQieAAAB' failed: Connection closed before receiving a handshake response
games:8 Object {hello: "received"}
I would like to be able to do emits whenever I want. Why isn't this working? Is it because I have to declare a reference to io with app.io and I am not starting the server with ('http')?
It turns out to be something in my particular build that I over looked. The code was correct in how I was going about it.
I have gulp which I am then using broswerSync to proxy my instance so it can auto reload once everything has compliled.
My server is using port 4001 but the proxied site uses 4000 so when I navigated to 4001 everything was working as expected. No JS errors

Categories