WebSocket to Serial bridge, send control chars like `\r\n` does not work - node.js

Im developing a WebSocket to Serial bridge.
The WebSocket server send some commands that are writen 1:1 to the serial device.
const { WebSocket } = require("ws");
const { autoDetect } = require("#serialport/bindings-cpp");
const { SerialPort } = require("serialport");
const binding = autoDetect()
const ws = new WebSocket("ws://example.com");
ws.on("open", () => {
console.log("WebSocket connected to:", ws.url);
const port = new SerialPort({
binding,
path: "/dev/ttyUSB0",
baudRate: 19200,
});
ws.on("message", (chunk) => {
console.log("From server", chunk);
port.write("sw i03\r\n"); // this works!
port.write(chunk) // this does not!
});
port.on("data", (data) => {
console.log("From port", data);
ws.send(data);
});
});
The messages string that comes from the server is sw i02\r\n.
Message format is the following, "sw i0\r\n", where <n> is a number between 1 - 8.
The problem is, \r\n is not interpreted as newline/control char, but literally as "\r\n" and not the control character they should represent.
Why does the serial device not recognize the message from the WebSocket as correct command, but when i rewrite it to a static port.write("sw i03\r\n")?
I simply dont understand whats the difference between the message from the WebSocket and the static port.write(..) i used to test.
The serial device is a Aten 8 port HDMI Switcher (VS0801H): https://www.aten.com/us/en/products/professional-audiovideo/video-switches/vs0801h/
EDIT/Workaround:
I changed the code/command payload, so now control character are stored in the backend/server side anymore and add them later on the "client"/serial side:
ws.on("message", (chunk) => {
console.log("From server", String(chunk));
port.write(`${chunk}\r\n`); // chunk = "sw i0<n>"
});
If any one know how to handle my problem, please let me know.
The solution i cam up with, feels more like a hack than a real problem solving solution.

Related

How to discard incoming event in Socket.io-client

Hi I am trying to make a tracker app and I'm using socket.io for both server and client. On my client app, I want to disregard message event whenever my browser is not on focus. my code is like this for the client app :
const socket = io('http://localhost:4000');
const [browserState, setBrowserState] = useState('');
useEffect(() => {
socket.on('connect', () => {
console.log('connected');
socket.on("message", payload => {
//payload need to be passed to Map component
console.log(payload);
});
});
},[]);
useEffect(() => {
document.onvisibilitychange = function(){
setBrowserState(document.visibilityState)
}
if(browserState === 'hidden') socket.volatile.emit("message", payload => payload)
},[browserState]);
and on my server is just simply:
io.on('connection', socket => {
socket.on('message', (payload)=>{
console.log(payload)
io.emit('message', payload)
});
The problem is on the client-side for the code socket.volatile.emit("message", payload => payload). if I use socket.volatile.on it's working. but I still receive message event on the client. if I use socket.volatile.emit the server is crashing.
Additional Question: is it okay if my client side io.protocol = 5 and my server is io.protocol = 4?
I'm really new to this. Please advise. :) Thanks!
It can be discarded easily by not replying to incoming sockets
io.on('connection', socket => {
socket.on('message', (payload)=>{
console.log(payload)
// removed this line io.emit('message', payload)
});

How to trigger websocket send from another function in Node?

It's been a while since I've worked with Node and Websockets. Basically how do I get socket.send() to work from another function is what I'm stuck on.
const server = new WebSocket.Server({ port: 8080 });
server.on('connection', socket => {
socket.on('message', message => {
console.log(`received from a client: ${message}`);
});
socket.send('yo world!');
});
function onMessageHandler (target, context, msg, self) {
client.say(target, response);
server.socket.send(response);
console.log(response);
}
}
How do I get my onMessageHandler to trigger a socket send, this is fail... server.socket.send(response);
Seeing your question i think there is a lack of understanding on how Websockets work. I am assuming you're using https://github.com/websockets/ws
There are two things. First is the WebSocketerver which you've named as server and then an Individual Socket which you've named as socket
Now the thing to understand is socket is not accessible outside server.on() callback The reason for this is there could be 1000 of sockets connected at a given instance and there would be no way to uniquely identify a particular socket you want to send message to.
So ask yourself the question that your application wants to send message to an individual socket to send to everyone who is connected to your server (basically broadcast)
If you want to send to an individual, you will have to uniquely identify the user
this._wss = new WebSocket.Server({
port: ENV_APP_PORT_WS
});
this._wss.on("connection", async (ws: AppWebSocket, req: IncomingMessage) => {
// const ipAddress = req.connection.remoteAddress; // IP Address of User
logger.info(req);
const queryParams = url.parse(req.url, true).query;
let authUser: User;
try {
authUser = await this._authenticateWebSocket(queryParams);
} catch (e) {
// Terminate connection and return...
}
// WS User INIT
ws.isAlive = true;
ws.userId = authUser.id;
ws.uuid = Helpers.generateUUIDV4();
ws.send(JSON.stringify({
type: "connected",
env: ENV
}));
});
The above code will add a property to each socket object that will enable it to uniquely identify a particular user/socket.
While sending =>
onMessageHandler(targetUserId: number, message: string) {
const allSockets = <AppWebSocket[]>Array.from(this._wss.clients.values());
const targetSocket = allSockets.find(w => w.userId === targetUserId);
targetSocket.send(message);
}
If You want to send to all connect users, it's quite easy:
https://github.com/websockets/ws#server-broadcast

How to write to socket after end of input stream?

I'm trying to write a very simple node TCP server which reads in the full input stream and writes out some function of the input. The output cannot be generated without the full input so the writes cannot be streamed as the input comes in. For simplicity sake in this post, I have omitted the actual transformation of the input and am just writing back the input.
My initial attempt was to write within the end event handler:
const net = require('net');
const server = net.createServer(async client => {
let data = '';
client.on('end', () => {
client.write(data);
});
client.on('data', part => {
data += part.toString();
});
client.pipe(client);
});
server.listen(8124);
But this results in a Socket.writeAfterFIN error "This socket has been ended by the other party" which led me to enabling allowHalfOpen because the docs seem to indicate that it separates the incoming and outgoing FIN packets.
const net = require('net');
const drain = client =>
new Promise(resolve => {
let data = '';
client.on('end', () => {
console.log('end');
resolve(data);
});
client.on('data', part => {
console.log('data');
data += part.toString();
});
});
const server = net.createServer({ allowHalfOpen: true }, async client => {
const req = await drain(client);
client.end(req);
});
server.listen(8124);
This works when I use e.g. echo 'abc' | nc localhost 8124, but I'm not sure whether allowHalfOpen should be necessary here. Is there another way to write shortly after the end of the input stream?
Using netcat instead of curl resolves the issue. e.g. echo 'abc' | nc localhost 8124. This is also more in line with what I need to do anyway since I don't need HTTP for this server.

node-ipc error "Messages are large, You may want to consider smaller messages."

So I am trying to setup a socket server in node.js using node-ipc, then send data from a client. I can connect perfectly fine, however when I send data I recieve the error Messages are large, You may want to consider smaller messages. I have followed all advice here, however, have still been unsuccessful in resolving the problem. I have tried sending from a socket connection in C and also from terminal. Any advice would be great, thanks in advance.
main.js
const ipc = require("node-ipc");
const socket = '/tmp/edufuse.sock';
ipc.serve(
socket,
function(){
ipc.server.on(
'myEvent',
function(data){
ipc.log('got a message : '.debug, data);
}
);
}
);
ipc.server.start();
test.json
```json
{ type: message, data: { foo: bar } }
command from terminal
pr -tF test.json | nc -U /tmp/edufuse.sock
Unfortunately, it appears this is an underlying problem with node-ipc. In order to get around this, I used net sockets and TCP.
const net = require('net');
const port = 8080;
const host = '127.0.0.1';
var server = net.createServer(function(socket) {
socket.on('data', function(data){
let str = data.toString('utf8');
console.log(str);
try {
let json = JSON.parse(str);
console.log(json);
} catch (e) {
console.log('error str: ' + str);
}
});
socket.on('error', function(err) {
console.log(err)
})
});
server.listen(port, host);

Flushing node.js socker writes

I have a node.js sample where a client socket makes two writes to a server. I'm trying to make sure the server receives the writes one by one, using the socket.write with a callback:
var net = require('net');
const HOST = '127.0.0.1';
const PORT = 7000;
var server = new net.Server(socket => {
socket.on('data', data => {
console.log("Server received: " + data);
})
});
server.listen(PORT, HOST);
var client = new net.Socket();
client.connect(PORT, HOST);
client.write("call 1", "utf8", () => {
client.write("call 2");
});
When I run it I get output:
Server received: call 1call 2
According to the docs here https://nodejs.org/api/net.html#net_socket_write_data_encoding_callback:
... The optional callback parameter will be executed when the data is finally written out...
What does data is finally written out mean? How can I make the server produce:
Server received: call 1
Server received: call 2
Thanks,
Dinko
You are dealing with a stream. It does not know anything about the beginning and end of your messages.
You need to add delimiter (eg \n: client.write("call 2\n");)
You need split data by delimiter on the receiver (eg node split package).
You can set a timeout for the second event.
client.write("call 1", "utf8")
setTimeout(() => {
client.write("call 2");
}, 100);

Resources