Node.js [net library]: How to make the buffer object a string? - javascript

I am fairly new to Node.js, and I am creating a TCP client that sends and receives data from a certain server.
My problem is with the "data" event emitted when data is received through the socket.
client.on('data', function(data) {
console.log('[TCP] Client received: ' + data); // Logs the message as it is supposed to be.
console.log(data.split(" ")); // Does not work because it says that data is not a string
});
I tried toString(data) but it did not output it as it was logged by the console.
So my question is: How can I convert this object to a string as it is logged in the console?
Thank you for your input :)

if data is a Buffer instance as it looks like, it's
client.on('data', function(data) {
console.log(data.toString('utf8'));
})

Related

Is this a correct way to parse incoming JSON over websocket, and respond depending on the type of message?

So I am receiving JSON over a websocket from a chargepoint using OCPP 1.6 JSON.
I am trying to parse the message and respond appropriately, depending on what the message is, using Node.js
Here is the message that I recieve:
[ 2,
'bc7MRxWrWFnfQzepuhKSsevqXEqheQSqMcu3',
'BootNotification',
{ chargePointVendor: 'AVT-Company',
chargePointModel: 'AVT-Express',
chargePointSerialNumber: 'avt.001.13.1',
chargeBoxSerialNumber: 'avt.001.13.1.01',
firmwareVersion: '0.9.87',
iccid: '',
imsi: '',
meterType: 'AVT NQC-ACDC',
meterSerialNumber: 'avt.001.13.1.01' } ]
In this case it is the 'BootNotification' message, to which I need to respond with an 'Accepted' message.
Here is my code:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
//Make incoming JSON into javascript object
var msg = JSON.parse(message)
// Print whole message to console
console.log(msg)
// Print only message type to console. For example BootNotification, Heartbeat etc...
console.log("Message type: " + msg[2])
// Send response depending on what the message type is
if (msg[2] === "BootNotification") {
//Send correct response
} // Add all the message types
});
});
With this I get the message type printed to the console as a string:
Message type: BootNotification
So my question is that is this the correct way to get the type of the message?
I am new to this so I want to make sure.
The specification for OCPP 1.6 JSON is available here: OpenChargeAlliance website
I guess YES. JSON.parse is the built-in to, well, pares JSON strings. In case that goes wrong it throws an error, so you might try/catch this.
Since the response you get is an array, there is no other way as to access its items with a numeric index.
In such cases I personally prefer to have something like that:
const handlers = {
'BootNotification': request => { 'msg': 'what a request' }
};
Than you can:
let respone = {'msg': 'Cannot handle this'}
if (handlers.hasOwnProperty(msg[2])) {
response = handlers[msg[2]](msg);
}
But that is just the way I would go.
If you are asking about OCPP message structure (not parsing a JSON), I can provide you the details about OCPP 1.6 version.
In OCPP 1.6, the client (Charging Station) sends a CALL (similar to request in HTTP) to server (Charging Station Management Systems). All CALLs have a strict structure of 4 elements:
MessageTypeId (integer)
UniqueId (UUID, string)
Action (string)
Payload (JSON object containing the arguments relevant to the Action.)
or as in your example:
[
2,
'bc7MRxWrWFnfQzepuhKSsevqXEqheQSqMcu3',
'BootNotification',
{ chargePointVendor: 'AVT-Company',
chargePointModel: 'AVT-Express',
chargePointSerialNumber: 'avt.001.13.1',
chargeBoxSerialNumber: 'avt.001.13.1.01',
firmwareVersion: '0.9.87',
iccid: '',
imsi: '',
meterType: 'AVT NQC-ACDC',
meterSerialNumber: 'avt.001.13.1.01' }
]
So the Type of Action should be always at index of 2 (as you retrieve it when you parse received message). You can refer to #philipp anwser on way how to handle an errors when parsing.

Send CR LF in JavaScript string to node.js serialport server

I've successfully followed the instructions for creating a webpage to talk to serial ports found here. And here's the GitHub repository for his project. I've modified it slightly to use Windows COM ports and fake the Arduino data. Now I'm trying to modify it further to talk to one of my company's test boards. I've established two-way communication, so I know I can talk in both directions over the serial port.
Sending id?CRLF over serial to the board will get a response of something like id=91. I can do this in PuTTY by just typing in id? & hitting the Enter key, or in DockLight by creating a send sequence id?rn, both of which work as expected, I get the id=91 response.
However, in the client.js JavaScript, trying to send: socket.send("id?\r\n"); in the console doesn't work, but I see it show up with an extra line in the server response. So I see something like this:
Message received
id?
<=blank line
So I tried to send the ASCII equivalents by doing:
var id = String.fromCharCode(10,13);
socket.send("id?" + id);
Which also doesn't work, although two extra lines show up in the server.
Message received
id?
<=blank line
<=another blank line
EDIT: I've also tried: socket.send('id?\u000d\u000a'); Same results as the first Message received blurb above.
I see the sent command arrive at the server (I've modified it a bit to do a console.log upon receipt of a message from the client):
function openSocket(socket){
console.log('new user address: ' + socket.handshake.address);
// send something to the web client with the data:
socket.emit('message', 'Hello, ' + socket.handshake.address);
// this function runs if there's input from the client:
socket.on('message', function(data) {
console.log("Message received");
console.log(data);
//here's where the CRLF should get sent along with the id? command
myPort.write(data);// send the data to the serial device
});
// this function runs if there's input from the serialport:
myPort.on('data', function(data) {
//here's where I'm hoping to see the response from the board
console.log('message', data);
socket.emit('message', data); // send the data to the client
});
}
I'm not positive that the CRLF is the problem, but I'm pretty sure it is. Possibly it's being swallowed by the server?
How can I embed it in a string to be sent to the server so it get interpreted properly and sent along to the serial port?
Other SO pages I've read:
How can I insert new line/carriage returns into an element.textContent?
JavaScript string newline character?
Well, it turns out that the problem wasn't exactly the CRLF like I thought, it was how the string terminator was being handled. All of our devices use what we can an "S prompt" (s>) for when a command has been processed. When it's done the last thing the board does is return an S prompt, so I'd modified the original server parser code to look for that. However that's a response terminator, not a request terminator. Once I changed it back to parser: serialport.parsers.readline('\n') it started to work.
// serial port initialization:
var serialport = require('serialport'), // include the serialport library
SerialPort = serialport.SerialPort, // make a local instance of serial
portName = process.argv[2], // get the port name from the command line
portConfig = {
baudRate: 9600,
// call myPort.on('data') when a newline is received:
parser: serialport.parsers.readline('\n')
//changed from '\n' to 's>' and works.
//parser: serialport.parsers.readline('s>')
};

node.js - should socket.get work on client?

I'm new to node.js and I'm making a simple chat app to get started. I'm a bit confused with the socket.set and socket.get methods.
The way the app works, is - first the client sets its username (pseudo):
function setPseudo() {
if ($("#pseudoInput").val() != "")
{
socket.emit('setPseudo', $("#pseudoInput").val());
$('#chatControls').show();
$('#pseudoInput').hide();
$('#pseudoSet').hide();
}
}
On the server, the pseudo is fetched with:
socket.on('setPseudo', function (data) {
socket.set('pseudo', data);
});
If I understand correctly, the server sets the pseudo variable with data received from this particular client. The server can later get that variable with socket.get. The following code broadcasts a message from a client to all clients:
socket.on('message', function (message) {
socket.get('pseudo', function (error, name) {
var data = { 'message' : message, pseudo : name };
socket.broadcast.emit('message', data);
console.log("user " + name + " send this : " + message);
})
});
What I don't understand is, why can't the client itself use socket.get to fetch its own pseudo? Using socket.get('pseudo') gives an error saying socket.get is not a function. Or am I overcomplicating this, and it would be better to just store the pseudo in a hidden field on the client or something similar? It just feels strange that a client should have to get its own username from the server.
EDIT:
Upon clicking Send, this code displays the sent message on the client itself. However, the displayed username is "Me". How can I modify it to show the client's username from the server?
addMessage($('#messageInput').val(), "Me", new Date().toISOString(), true);
function addMessage(msg, pseudo) {
$("#chatEntries").append('<div class="message"><p>' + pseudo + ' : ' + msg + '</p></div>');
}
You have to realize that although socket is a name used by both the server and the client, and interfaces are similar these are two independent things. (i.e. server socket and client socket) describing two ends of one connection.
If server sets some data on a socket what it actually does is it saves some data in its own memory and remembers that this data is associated with the socket. So how would client read something from server's memory? How can machine A read data from machine's B memory? Well, the only (reasonable) possibility is to send that data over network and this is actually what happens.
As for the other question: it's actually natural for the client to get its own name from the server or at least validate that name. Consider this scenario: two clients connect to the server and use the same name. This would lead to a conflict so it is up to the server to solve the problem. Basically you would tell one of the clients "sorry, this name is already being used, use something else".

nodejs send list of all clients fail

js.
Currently I have done several tests successfully
Hello world
server-client communication with events
many rooms
But i can't send the client, to the clients, i use socket.io
The reason I want to do this, is to have a list of current clients
EDIT:
I need to store information for each user in server side
i try use
var io = require('socket.io');
var socket = io.listen(9876);
socket.on('connection', function(client) {
client.join('room');
console.log('new client ' + client.toString());
client.in('room').emit('list', client ); //<-- Error here
client.on('message', function(event) {
console.log('client message! ', event);
client.send(event);
});
client.on('chat', function(data) {
client.broadcast.in('room').emit('LDS', data);
client.in('room').emit('LDS', data);
});
client.on('disconnect', function() {
console.log('out');
});
});
but throws this error
connections property is deprecated. Use getConnections() method
C:\Repos\InWeb\NO\node_modules\socket.io\lib\parser.js:75
data = JSON.stringify(ev);
^
TypeError: Converting circular structure to JSON
at Object.stringify (native)
The original idea is send a list of clients, like this
var listClients;
socket.on('connection', function(client) {
client.join('room');
listClients.push(client);
client.in('room').emit('list', listClients); //<-- But throws same error
I guess that the error is given by the client context
I can fix it?
You send whole object client, you should use something like this
Socket.io Connected User Count
or create array with name and id and send array not whole node object.

socket.io not working on several clients

I'm trying to build a simple chat client and am having some issues getting it working across multiple clients. Chances are I've missed something really simple. When I send something from one client it is logged in that client but not in any others.
Server:
var io = require('socket.io').listen(5000);
io.sockets.on('connection', function (socket) {
socket.on('send', function (data) {
socket.emit('receive', data);
});
});
Client:
var socket = io.connect('http://localhost:5000');
socket.on('receive', function(data){
console.log("Data received at " + new Date() + ": " + data);
});
The socket variable that gets passed to your callback function is a handle on the client that connected, so socket.emit is behaving correctly, i.e. it should only send to the client that originated it.
Try:
socket.broadcast.emit('receive', data);
to send to everybody except the originating client, or
io.sockets.emit('receive', data);
to send to all clients including the originator.
You want to emit on all sockets, not just the one that sent the message.
So you should be using:
io.sockets.emit('recieve', data);
This is assuming that you aren't logging the data on the sending client before sending it to the server. In that case you'll want to use:
socket.broadcast.emit('recieve', data);
Which will send the message to all connected clients except the sender.
See here for reference on Socket.io
Edit: Trevor beat me to it. However, for some additional clarification: io.sockets is the same as io.of(''). Which is handy to know for when you start using namespaces in a scoket.io app.

Categories

Resources