Read Serial port data using node js - node.js

I want to read data from serial port and get from data when reqested
Here is my code
const http = require('http');
const hostname = 'localhost';
const { SerialPort } = require('serialport')
const { ReadlineParser } = require('#serialport/parser-readline')
const { io } = require('socket.io');
let express = require('express')
const serialPort = new SerialPort({
path: 'COM4',
baudRate: 9600 ,
})
const parser = serialPort.pipe(new ReadlineParser({ delimiter: '\r\n' }))
let app = express();
var port = 8080;
const server = http.createServer(app);
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
app.get('/get_data', function(req, res) {
parser.on('data', function(data) {
res.json({'weight': data});
});
});
When i am try to get data i got ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client
I want serial port data when requested from localhost:8080/get_data anyone can help ?

Your data event from parser is probably firing more than once, which means you would be calling res.json more than once. As you can see in the express api documentation, res.json sets the content-type header...thus you can only call it once per request. Hence the error.
What I think would normally be done in this kind of situation is to set up a queuing system. A simple version might be done using an array, although if you were using this in a production server it might be better to use a proper message queuing system (e.g. rabbitMQ, kafka, AWS SQS, etc).
Here's an example of how you might use an array:
const queue = [];
parser.on('data', function(data) {
// push new data onto end of queue (array)
queue.push(data);
});
app.get('/get_data', function(req, res) {
if (req.params.getFullQueue === 1) {
// empty complete contents of current queue,
// sent to client as an array of { weight: x } objects
const data = queue.splice(0, queue.length)
.map(x => ({ weight: x }));
res.json(data);
} else {
// get oldest enqueued item, send it only
res.json({ weight: queue.shift() });
}
});
The if/else in the app.get is meant to illustrate these two options, depending on which you wanted to use. In production you'd probably want to implement pagination, or maybe even a websocket or EventSource so that data could be pushed as it became available.

Related

How to prevent people from connecting to any id with sockeIO?

I just set up SocketIO in my PHP project. I am completly new to websockets at all so bear with me.
I am defining the socketIO variable globally
let socketIO = io("http://localhost:3000");
When people are logging in to my application, they are connected to it with their ID comming from the database. The login script just gives back true which redirects the user in very simplified terms:
// get component
$.get(url, data, (data) => {
if (data.status) {
// connect with Node JS server
socketIO.emit("connected", data.user_id);
// redirect
load_new_page("/users/" + data.user_id);
}
});
My concern here now is that people could just go and change the data.user_id to anything they want and receive what ever the chosen id would receive.
My server.js:
// initialize express server
var express = require("express");
var app = express();
// create http server from express instance
var http = require("http").createServer(app);
// include socket IO
var socketIO = require("socket.io")(http, {
cors: {
origin: ["http://localhost"],
},
});
// start the HTTP server at port 3000
http.listen(process.env.PORT || 3000, function () {
console.log("Server started running...");
// an array to save all connected users IDs
var users = [];
// called when the io() is called from client
socketIO.on("connection", function (socket) {
// called manually from client to connect the user with server
socket.on("connected", function (id) {
users[id] = socket.id;
});
});
});
How can I prevent something like this?

Implement socket.io in node.js application controller

good afternoon. I am new to programming sockets in node.js and I need to implement socket.io in a controller of my application. The architecture I have is the following:
The file that starts the server is index.js
const express = require('express');
const app = express();
const port = 3000;
const socketRouter = require('./routes/socket')
app.use(express.json());
//Route
app.use('/socket', socketRouter);
app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
The file where I define the routes is socket.js
const { Router } = require('express');
const { showData } = require('../controllers/socket');
const router = Router();
router.post('/send-notification', showData);
module.exports = router;
And my controller is:
const { response } = require('express');
const showData = (req, res = response) => {
const notify = { data: req.body };
//socket.emit('notification', notify); // Updates Live Notification
res.send(notify);
}
module.exports={
showData
}
I need to implement socket.io in this controller to be able to emit from it but I can't get it to work. Could you tell me how to do it?
Thanks a lot
CLARIFICATION: if I implement socket.io in the main file it works, but I want to have some order and separate things. This is how it works:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.post('/send-notification', (req, res) => {
const notify = { data: req.body };
socket.emit('notification', notify); // Updates Live Notification
res.send(notify);
});
const server = app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
const socket = require('socket.io')(server);
socket.on('connection', socket => {
console.log('Socket: client connected');
});
Move your socket.io code to its own module where you can export a method that shares the socket.io server instance:
// local socketio.js module
const socketio = require('socket.io');
let io;
modules.exports = {
init: function(server) {
io = socketio(server);
return io;
},
getIO: function() {
if (!io) {
throw new Error("Can't get io instance before calling .init()");
}
return io;
}
}
Then, initialize the socketio.js module in your main app file:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
const server = app.listen(port, () => {
console.log(`Server connection on http://127.0.0.1:${port}`); // Server Connnected
});
// initialize your local socket.io module
const sio = require('./socketio.js');
sio.init(server);
// now load socket.io dependent routes
// only after .init() has been called on socket.io module
const socketRouter = require('./routes/socket')
app.use('/socket', socketRouter);
Then, anywhere you want to access the socket.io server instance, you can
require("./socketio.js") and use the .getIO() method to get the socket.io instance:
// use correct path to socketio.js depending upon where this module
// is located in the file system
const io = require("../../socketio.js").getIO();
// some Express route in a controller
const showData = (req, res) => {
const notify = { data: req.body };
// send notification to all connected clients
io.emit('notification', notify);
res.send(notify);
};
module.exports= {
showData
};
Note: A typical socket.io usage convention on the server is to use io as the server instance and socket as an individual client connection socket instance. Please don't try to use socket for both. This makes it clear that io.emit(...) is attempting to send to all connected clients and socket.emit() is attempting to send to a single connected client.
Also note that if your route is triggered by a form post where the browser itself sends the form post, then that particular client will not receive the results of io.emit(...) done from that form post route because that browser will be in the process of loading a new web page based on the response of the form post and will be destroying its current socket.io connection. If the form post is done entirely via Javascript using an Ajax call, then that webpage will stay active and will receive the results of the io.emit(...).
You can use the same socket and app (if you need to expose APIs as well) in other files if you want to separate socket messages and REST endpoints by functionality or however you choose to organize it. Here's an example of how this can be done:
Create a new file, let's say controller1.js:
function initialize(socket, app) {
socket.on('some-socket-message', socket => {
// Whatever you want to do
});
app.get('/some-endpoint', (req, res) => {
// whatever you want to do
});
}
module.exports = {initialize}
And then add the following to your controller.js
const controller1 = require('path/to/controller1');
...
// At some point after socket and app have been defined
controller1.initalize(socket, app);
This will be the bases of separating your controller however you want, while still using the same socket connection and API port in all of your controllers. You can also refactor the initialize method into different methods, but that would be at your own discretion and how you want to name functions, etc. It also does not need to be called initalize, that was just my name of preference.

How to proxy a media stream in Node?

I want to be able to proxy a remote icecast stream to client. I've been fiddling around a lot in the past few days to no avail.
Use case:
Be able to extract analyser data out of an <audio> tag src without running into CORS issues.
My solution so far
In order to address CORS issues preventing me to create an leverage sound data directly out of the <audio>'s source, I've tried to write a tiny proxy which would pipe requests to a specific stream and return statics in any other case.
Here is my code:
require('dotenv').config();
const http = require('http');
const express = require('express');
const app = express();
const PORT = process.env.PORT || 4000;
let target = 'http://direct.fipradio.fr/live/fip-midfi.mp3';
// figure out 'real' target if the server returns a 302 (redirect)
http.get(target, resp => {
if(resp.statusCode == 302) {
target = resp.headers.location;
}
});
app.use(express.static('dist'));
app.get('/api', (req, res) => {
http.get(target, audioFile => {
res.set(audioFile.headers);
audioFile.addListener('data', (chunk) => {
res.write(chunk);
});
audioFile.addListener('end', () => {
res.end();
});
}).on('error', err => {
console.error(err);
});
});
app.listen(PORT);
The problem
The client receives a response from the proxy but this gets stalled to 60kb of data about and subsequent chunks are not received, in spite of being received by the proxy:
Any suggestion is welcome!
I've found a solution, use stream pipe.
const app = express();
const PORT = process.env.PORT || 4000;
let target = 'http://direct.fipradio.fr/live/fip-midfi.mp3';
// figure out 'real' target if the server returns a 302 (redirect)
http.get(target, resp => {
if(resp.statusCode == 302) {
target = resp.headers.location;
}
});
app.use(express.static('dist'));
app.get('/api', (req, res) => {
req.pipe(request.get(target)).pipe(res);
});
app.listen(PORT);

Why does my Node application keep sending data after every refresh?

I am using node.js and express.js to build a very simple application. I want to read the content of a directory and when I browse to localhost:3000/names, the application will print an array of the content to the web page except for the content that I choose not to. Here is my code:
const express = require('express');
const fs = require('fs');
const app = express();
const port = 3000;
let result = [];
app.get('/names', (req, res) => {
const printNames = (err, file) => {
file.forEach(e => {
if (e !== 'john') {
result.push(e);
}
});
res.send(result);
};
fs.readdir('./home', printNames);
});
app.listen(port, () => {
console.log('Listening on port 3000');
});
The application works the way that I wanted to, but there is a small bug. Every time I refresh the page, the application will add on the same content of the array to the existing array. My array keeps getting bigger with every refresh. I want the application to send the array to the page and will stay the same when I refresh. I do not have the slightest idea why my application is behaving this way. Can someone explain to me why it is behaving like this and what would be the right steps to fix this?
It is because you've declared your result array in the global scope.
Your result array is getting bigger and bigger every time.
Simply move the declaration to your route and you should be fine.
This should work fine:
const express = require('express');
const fs = require('fs');
const app = express();
const port = 3000;
// let result = []; Remove this line
app.get('/names', (req, res) => {
let result = []; // And add it here
const printNames = (err, file) => {
file.forEach(e => {
if (e !== 'john') {
result.push(e);
}
});
res.send(result);
};
fs.readdir('./home', printNames);
});
app.listen(port, () => {
console.log('Listening on port 3000');
});
Read more about scopes in JavaScript here:
https://www.w3schools.com/js/js_scope.asp
Every time you request to load the page /names, it is re-running the code in that handler. If you only want to run that script once, then move it outside of the handler, and only send the result.
let result = [];
const printNames = (err, file) => {
file.forEach(e => {
if (e !== 'john') {
result.push(e);
}
});
};
fs.readdir('./home', printNames);
app.get('/names', (req, res) => {
res.send(result)
});

node js websockets used with api

I have a node js API built with express. In one of my http endpoints, I would like to accept the request and send it over websockets to another server, and then return a reply. I'm using the ws library. The problem is that the websockets communication is not synchronous, so I don't know how to return an answer to the API client. Anyway, this is what I tried but it's not complete:
const express = require('express');
const app = express();
const WebSocket = require('ws');
const uuid = require('uuid');
const bodyParser = require('body-parser');
const ws = new WebSocket('ws://localhost:7465/');
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ extended: false }));
ws.on('open', function open() {
console.log('connected');
});
ws.on('close', function close() {
console.log('disconnected');
});
ws.on('message', function incoming(data) {
console.log('Got data from server:');
console.log(data);
});
app.post('/my-http-endpoint', function (req, res) {
var payload = JSON.stringify({ body: req.body, requestID: uuid.v4() });
ws.send(Buffer.from(payload));
// How to send a reply?
})
app.listen(1337);
You will need to introduce message IDs. Generate them by counting up a number.
Add the following dictionary to your code:
let nextMessageId = 1;
const responseCallbacks = {};
When you send something (in the app.post callback in your case), do the following:
const messageId = obtainFreeMessageId(); // see below
ws.send(Buffer.from({ messageId, payload }));
responseCallbacks[messageId] = function(data) {
// make use of the response message data here
};
On message do the following (the response must contain messageId as well):
const messageId = message.messageId; // message has a message ID
const responseCallback = responseCallbacks[messageId];
if(responseCallback) {
responseCallback(message.data); // message contains your data
delete responseCallbacks[messageId];
}
Helper function for message ID generation which helps prevent possible overflow:
const MaximumMessageId = 0xFFFFFFFFFFFF; // 48-bit integer (64-bit is too much for javascript, 32-bit is a little bit too stingy)
function obtainFreeMessageId() {
const messageId = nextMessageId;
nextMessageId++;
if(nextMessageId > MaximumMessageId) {
nextMessageId = 1;
}
return messageId;
}
Consider setting a timeout which calls the response callback after a certain amount of time if you want to make sure the request comes to an end. Clear the timeout in the response callback.

Resources