Parse TCP JSON Stream and emit each object via Socket.io - json

I am working with a data feed that sends a JSON stream over a TCP socket and I'm using node.js/socket.io to emit the stream to a browser client.
Everything is working except I need each JSON object to emitted as a separate message from the socket.io server. In the client the messages are received like this:
//Message 1:
{"type":"TYPE_1","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
//Message 2:
{"type":"TYPE_2","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
{"type":"TYPE_3","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
//Message 3:
{"type":"TYPE_4","odds":[{"eventId":"foo","od
//Message 4:
ds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
The data feed docs state: "All messages sending to your application will form a JSON stream (no delimiter between messages), so you may need a decoder that support JSON stream."
So the stream is strictly correct but I need each object as separate message.
I have looked at https://www.npmjs.com/package/JSONStream and others but am very new to nodejs and socketio and am not sure how to implement them in to the server.
Have also read How can I parse the first JSON object on a stream in JS, nodejs JSON.parse(data_from_TCP_socket), http://www.sebastianseilund.com/json-socket-sending-json-over-tcp-in-node.js-using-sockets.
I think it's something to do with buffer chunk lengths and them being too big so the messages get split but that could be wrong! I'm guessing I need a delimiter check that balances brackets but not sure how to go about it or if the right approach.
My Server Script:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var net = require('net');
var port = 8992; // Datafeed port
var host = '127.0.0.1'; // Datafeed IP address
//Whenever someone connects this gets executed
io.on('connection', function(socket){
console.log('A user connected to me the server');
//Whenever someone disconnects this piece of code executed
socket.on('disconnect', function () {
console.log('A user disconnected');
});
});
//Create a TCP socket to read data from datafeed
var socket = net.createConnection(port, host);
socket.on('error', function(error) {
console.log("Error Connecting");
});
socket.on('connect', function(connect) {
console.log('connection established');
socket.write('{"type":"SUBSCRIBE"}');
});
socket.on('data', function(data) {
//console.log('DATA ' + socket.remoteAddress + ': ' + data);
var data = data.toString();
io.sockets.emit('event', JSON.stringify(data));
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
My Client:
<!DOCTYPE html>
<html>
<head><title>Hello world</title></head>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io.connect('http://localhost:3000');
</script>
<body>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
<ul id="messages"></ul>
<script>
socket.on('event', function(data){
var t = JSON.parse(data.toString('utf8'));
$('#messages').prepend($('<li>').text(t));
console.log('Got event from Server:', t);
});
</script>
</body>
</html>
Any help or guidance would be amazing as really struggling with this.

A common delimiter to use is a newline character (\n). If you have that appended to your JSON messages it will be very easy to parse the messages. For example:
var sockBuf = '';
socket.setEncoding('utf8');
socket.on('data', function(data) {
sockBuf += data;
var i;
var l = 0;
while ((i = sockBuf.indexOf('\n', l)) !== -1) {
io.sockets.emit('event', sockBuf.slice(l, i));
l = i + 1;
}
if (l)
sockBuf = sockBuf.slice(l);
});
or a more efficient, but slightly less simple solution:
var sockBuf = '';
socket.setEncoding('utf8');
socket.on('data', function(data) {
var i = data.indexOf('\n');
if (i === -1) {
sockBuf += data;
return;
}
io.sockets.emit('event', sockBuf + data.slice(0, i));
var l = i + 1;
while ((i = data.indexOf('\n', l)) !== -1) {
io.sockets.emit('event', data.slice(l, i));
l = i + 1;
}
sockBuf = data.slice(l);
});

Related

nodejs server app.post issue XML Parsing Error: syntax error Location: http://localhost:3000/get_messages Line Number 1, Column 1:

I followed a tutorial on YouTube to create a private user to user chat.
https://www.youtube.com/watch?v=Ozrm_xftcjQ
Everything on the chat works accept that i keep getting this Error:
XML Parsing Error: syntax error Location: http://localhost:3000/get_messages Line Number 1, Column 1:
using firefox developer edition and chrome. if i click the stack trace link i get the following xml error:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /get_messages</pre>
</body>
</html>
but i have no GET calls at all..
The code looks as follows:
server.js file
var port = process.env.PORT || 3000;
//creating express instance
var express = require("express");
var app = express();
//creating http instance
var http = require("http").createServer(app);
//app.use(express.static(__dirname));
//creating socket instance
var io = require("socket.io")(http);
//create body parser instance
var bodyParser = require("body-parser");
app.use(bodyParser.json());
//enable url encode for POST requests
app.use(bodyParser.urlencoded({ extended : true }));
//create instance of mysql
var mysql = require('mysql');
//create mysql connection
// connectionLimit: 100,debug: true
var connection = mysql.createConnection({
host: 'localhost',
user: 'xxx',
password: 'xxx',
database: 'chatio'
});
connection.connect(function(error){
if(error){
console.log(error);
return;
}
console.log('database connected');
})
//enable header request for post requests
app.use(function(request, result, next){
result.setHeader("Access-Control-Allow-Origin", "*");
next();
})
//create api to return all messages
app.post("/get_messages", function(request, result){
console.log(request);
console.log(result);
connection.query("SELECT * FROM chat_messages WHERE (`from_id` = '"+request.body.sender+"' AND `to_id` = '"+request.body.receiver+"') OR (`from_id` = '"+request.body.receiver+"' AND `to_id` = '"+request.body.sender+"')", function(error, messages){
if(error){
console.log(error);
return;
}
console.log(messages);
//response will be in JSON
result.end(JSON.stringify(messages));
});
})
io.on("connection", function(socket){
socket.on("send_message", function(data){
//send event to receiver
var socketId = users[data.receiver];
io.to(socketId).emit("new_message", data);
//save in database
connection.query("INSERT INTO chat_messages (`from_id`,`to_id`,`message`) VALUES ('"+data.sender+"', '"+data.receiver+"', '"+data.message+"')", function(error, result){
if(error){
console.log(error);
return;
}
console.log('message saved');
});
})
})
http.listen(port, function(){
console.log("server started");
})
inde.php file code as follows:
//creating io connection
var io = io("http://localhost:3000");
var receiver = "johnny";
var sender = "steven";
function onUserSelected(){
$.ajax({
url: "http://localhost:3000/get_messages",
method:"POST",
cache: false,
data: {
"sender" : sender,
"receiver" : receiver
},
dataType: "json",
success: function(response){
var messages = response; //JSON.parse();
var html = "";
for(var i = 0; i < messages.length; i++){
html += "<li>" +messages[i].from_id + " says: " + messages[i].message + "</li>";
document.getElementById('messages').innerHTML += html;
}
}
});
return;
}
}
i figured it out..
the problem comes from this line:
result.end(JSON.stringify(messages));
I dont exactly understand why, but i changed it to
result.send(JSON.stringify(messages));
and now the bug is gone

socket.io Updating all the open pages

I am trying to create a chat website, something like a discord clone. I am using socket.io to connect my front end and back-end but I cant figure out how to make it that when someone enters a message that message to be displayed on all currently open browser pages
Server.js (My server file I use):
const express = require("express");
const app = express();
const http = require("http").Server(app);
const port = 4000;
const io = require("socket.io")(http);
app.get("/", (req, res) => {
res.sendFile("ChatRoom.html", {"root": __dirname});
});
io.on("connection", (socket) => {
console.log("A user has connected");
socket.on("messageSend", (data) =>{
console.log(data);
io.emit("chatUpdate", data);
});
});
http.listen(port, () => {
console.log("Server.js listening on port " + port );
});
And my Javascript code in the HTML file:
var socket = io();
document.addEventListener('keydown', InputText);
function InputText(e)
{
//Checks if the pressed button is Enter and if the input box is empty
if( e.keyCode == 13 && document.getElementById("chat_input").value != "")
{
//Gets the div which the message will be ridden to
var parent = document.getElementById("chat");
//Current date to be used when displaying the exact time of sending the
messgae
let d = new Date()//.getTimezoneOffset();
//Getting the properties of the input
var value = document.getElementById("chat_input");
//Telling the server that a message has been sent - function
emitter(parent, value.value, d);
//Setting the text box back to blank
value.value = "";
}
}
//Function
function emitter(holder, text, date){
socket.emit("messageSend", text);
socket.once("chatUpdate", (message) => {
var z = document.createElement("p");
z.innerText = date.getHours() +":"+ date.getMinutes() + " | " +
message;
z.style = 'border-top: 1px solid Black;border-bottom: 1px solid
Black;font-size:20px; margin: 0;padding: 10px;';
holder.appendChild(z);
});
}
Once you have emitted the message you need to be listening for it in the client, if the action you are trying to achieve is sending the message to another user that has the socket currently open on their window. Because you are sending it to a user not the server, so you would need to be connecting to the socket so it's very possible your socket might need to be defined more like this.
var socket = io.connect('Your:/url/of/windowlocation/whileonsocket/here')
Hope this helps!

sensor data is not uploading on artik cloud

I am trying to send sensor data to artik cloud via node.js. (using web socket and serial port). But its sending null. Anyone knows the reason? I just copied the code from tutorial so there is no syntax error.
var webSocketUrl = "wss://api.artik.cloud/v1.1/websocket?ack=true";
var device_id = "####";
var device_token = "#####";
var isWebSocketReady = false;
var ws = null;
var serialport = require("serialport");
var portName = 'COM5';
var sp= new serialport.SerialPort(portName, {
baudRate: 9600,
parser: serialport.parsers.readline("\r\n")
});
var WebSocket = require('ws');
/**
* Gets the current time in millis
*/
function getTimeMillis(){
return parseInt(Date.now().toString());
}
/**
* Create a /websocket bi-directional connection
*/
function start() {
//Create the websocket connection
isWebSocketReady = false;
ws = new WebSocket(webSocketUrl);
ws.on('open', function() {
console.log("Websocket connection is open ....");
register();
});
ws.on('message', function(data, flags) {
console.log("Received message: " + data + '\n');
});
ws.on('close', function() {
console.log("Websocket connection is closed ....");
});
}
/**
* Sends a register message to the websocket and starts the message flooder
*/
function register(){
console.log("Registering device on the websocket connection");
try{
var registerMessage = '{"type":"register", "sdid":"'+device_id+'", "Authorization":"bearer '+device_token+'", "cid":"'+getTimeMillis()+'"}';
console.log('Sending register message ' + registerMessage + '\n');
ws.send(registerMessage, {mask: true});
isWebSocketReady = true;
}
catch (e) {
console.error('Failed to register messages. Error in registering message: ' + e.toString());
}
}
/**
* Send one message to ARTIK Cloud
*/
function sendData(temperature){
try{
// ts = ', "ts": '+getTimeMillis();
var data = {
"temp": temperature
};
var payload = '{"sdid":"'+device_id+'", "data": '+JSON.stringify(data)+', "cid":"'+getTimeMillis()+'"}';
console.log('Sending payload ' + payload);
ws.send(payload, {mask: true});
} catch (e) {
console.error('Error in sending a message: ' + e.toString());
}
}
/**
* All start here
*/
start(); // create websocket connection
sp.on("open", function () {
sp.on('data', function(data) {
if (!isWebSocketReady){
console.log("WebSocket is not ready. Skip sending data to ARTIK Cloud (data:" + data +")");
return;
}
console.log("Serial port received data:" + data);
//var parsedStrs = data.split(",");
var temperature = parseInt(data);
sendData(temperature);
});
});
If you reference our First IoT Sample:
https://developer.artik.cloud/documentation/tutorials/your-first-iot-device.html
The node.js sample sends the value from the temperature sensor. As a dependency it requires a connected Arduino, Raspberry Pi, and a DHT temperature sensor located at the right pin. If you are seeing null "before" sending the data to ARTIK Cloud, you are not getting any value from the sensor.
In particular, output and print to console the "temperature" value from the following function in case of any parsing errors:
function sendData(temperature) //...
Email us at developer#artik.cloud if you need additional information.
Thanks!
In this line:
var temperature = parseInt(data);
If you're getting empty or non numeric data (you can verify this in the previous line where you're logging the variable's content), then temperature will be NaN (not a number). Then, when you build the JSON payload for Artik Cloud, you'll end up with something like:
{
"sdid": "cbd3f844967d464da3c4f4989f80f86c",
"data": {
"temp":null
},
"cid":"1495817841624"
}
Because the JSON.stringify of:
{"temp":NaN}
would be translated to:
{"temp":null}

node.js data fetch in json model error

I am new to node.js
I was just making an simple application
my data is inserting properly into the database as well as fetching also from the database
But the problem is when I am trying to access it in json model it is giving me error
var express = require('express');
/*
* body-parser is a piece of express middleware that
* reads a form's input and stores it as a javascript
* object accessible through `req.body`
*
* 'body-parser' must be installed (via `npm install --save body-parser`)
* For more info see: https://github.com/expressjs/body-parser
*/
var bodyParser = require('body-parser');
// create our app
var app = express();
// instruct the app to use the `bodyParser()` middleware for all routes
app.use(bodyParser.urlencoded({ extended: true }));
// A browser's default method is 'GET', so this
// is the route that express uses when we visit
// our site initially.
app.get('/', function(req, res){
// The form's action is '/' and its method is 'POST',
// so the `app.post('/', ...` route will receive the
// result of our form
var html = '<form action="/" method="post">' +
'Enter your name:' +
'<input type="text" name="userName" placeholder="Put your name" />' +
'<br>' +'Enter your city:'+'<input type="text" name="userCity" placeholder="Put your city" />' +
'<br>' +'Enter your state:'+'<input type="text" name="userState" placeholder="Put your state" />' +
'<br>' +'Enter your country:'+'<input type="text" name="userCountry" placeholder="Put your country" />' +
'<br>' +
'<button type="submit">Submit</button>' +
'</form>';
res.send(html);
});
// This route receives the posted form.
// As explained above, usage of 'body-parser' means
// that `req.body` will be filled in with the form elements
app.post('/', function(req, res){
var userName = req.body.userName;
var userCity = req.body.userCity;
var userState = req.body.userState;
var userCountry = req.body.userCountry;
// var document = {userName:userName,userCity:userCity,userState:userState,userCountry:userCountry};
var html = 'Hello: ' + userName + '.<br>' +'City: ' + userCity + '.<br>'+'State: ' + userState + '.<br>'+'country: ' + userCountry + '.<br>'+
'Try again.';
// res.send(html);
//res.send(JSON.stringify(doc));
//lets require/import the mongodb native drivers.
var mongodb = require('mongodb');
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
//We need to work with "MongoClient" interface in order to connect to a mongodb server.
var MongoClient = require('mongodb').MongoClient;
// Connection URL. This is where your mongodb server is running.
var url = 'mongodb://localhost:27017/test';
// Use connect method to connect to the Server
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
//HURRAY!! We are connected. :)
console.log('Connection established to', url);
/* var userName = req.body.userName;
var userCity = req.body.userCity;
var userState = req.body.userState;
var userCountry = req.body.userCountry;
var document = {userName:userName, userCity:userCity,userState:userState,userCountry:userCountry};*/
// do some work here with the database.
var insertDocument = function(db, callback) {
db.collection('test').insertOne( {
"userName" :userName,
"userCity" : userCity,
"userState" : userState,
"userCountry" :userCountry ,
}, function(err, result) {
assert.equal(err, null);
console.log("Inserted a document into the test collection.");
callback(result);
});
};
var findDocument = function(db, callback) {
var cursor =db.collection('test').find( );
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
console.log(doc);
// res.contentType('application/json');
res.send(JSON.stringify(doc));
/* app.get('/test', function(req, res, next) {
res.json(doc);
});*/
} else {
callback();
}
// res.send(JSON.stringify(doc));
});
};
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
insertDocument(db, function() {
findDocument(db, function() {
db.close();
});
});
});
/* var document = {name:"David", title:"About MongoDB"};
db.collection('test').insertOne(document, function(err, records) {
if (err) throw err;
console.log("Record added as "+records[0]._id);
});*/
//Close connection
// db.close();
}
});
});
app.listen(3000);
Please help me to get rid off the problem.
Thank you..
The error I am getting is cann't set headers after they are send
This kind of error usually means that you try using res.send(...) multiple times from the same route.
Here you can see that in your find document, you use a cursor.each, and send your result inside this cursor.each. This means that you send multiple results from the same route.
What you should do instead is having a variable that you use to store your result before sending it once everything is retrieved.

Call socket.io from dgram socket udp4

I'm having some problems with a small aplications that I'm developing.
I have an Arduino with a temperature sensor, I wanted to send the values to a nodejs service, and show it to a webpage. I wanted to use socket.io, but I'm just able to use UDP connection from arduino to server (ethernet). Just to keep the sensor value refreshed, seems that I have to call a io socket from the UDP service, but I can't.
My socket.io that works when I call it from a webpage.
var io = require('socket.io').listen(3000);
io.sockets.on('connection', function (socket) {
socket.on('message', function (message) {
console.log("Got message: " + message);
io.sockets.emit('SensorList', { 'temperature': temp });
});
});
This is the UDP service that reads the arduino packets:
var dgram = require("dgram");
var server = dgram.createSocket("udp4");
var fs = require('fs');
**var io = require('socket.io');**
var crlf = new Buffer(2);
crlf[0] = 0xD; //CR - Carriage return character
crlf[1] = 0xA; //LF - Line feed character
server.on("message", function (msg, rinfo) { //every time new data arrives do this:
console.log("server got: " + msg.readUInt16LE(0) + " from " + rinfo.address + ":" + rinfo.port); // you can comment this line out
**var socket = io.connect('http://localhost:3000');
socket.on('connect', function () {
socket.send(msg.readUInt16LE(0));
});**
});
server.on("listening", function () {
var address = server.address();
console.log("server listening " + address.address + ":" + address.port);
});
server.bind(6000); //listen to udp traffic on port 6000
The error is:
var socket = io.connect('http://localhostit.is:3000'); ^
TypeError: Object # has no method 'connect'
at Socket. (/Users/xfr/Documents/nodejs/temp1/app2.js:15:19)
at Socket.EventEmitter.emit (events.js:98:17)
at UDP.onMessage (dgram.js:437:8)
If I erase all the io part, I'm able to see the values in console.
If there is another way to mix 2 services in one.. tell me some clues and I'll do the search.
Thanks.
Made it!
2 in 1...
var http = require('http'),
dgram = require('dgram'),
socketio = require('socket.io');
var fs = require('fs');
var app = http.createServer(),
io = socketio.listen(app),
socket = dgram.createSocket('udp4');
var crlf = new Buffer(2);
crlf[0] = 0xD; //CR - Carriage return character
crlf[1] = 0xA; //LF - Line feed character
socket.on('message', function(content, rinfo) {
console.log('got message', content.readUInt16LE(0), 'from', rinfo.address, rinfo.port);
io.sockets.emit('udp message', content.readUInt16LE(0));
});
socket.bind(6000);
app.listen(8000);
On the webpage side:
src="socket.io.min.js"
src="jquery.min.js"
<script>
var socket = io.connect('http://local_host.com:8000');
socket.on('udp message', function(msg) {
console.log(msg) ;
temperature = msg/100;
$('#temperature h1').html(temperature+'°C');
});
</script>
bind/listen newbie issues.