Node `net` module IPC server intermitent - javascript

Following the official node documentation of net and child_process modules, I archived this: a server that spawns a child and connect through net module. But the connection is intermittent. The code is self explanatory, but I've add details in the code comments:
// server.js
const childProcess = require('child_process').fork('child.js');
const server = require('net').createServer((socket) => {
console.log('got socket connection'); // this callback is intermitent
socket.on('data', (stream) => {
console.log(stream.toString());
})
});
server.on('connection', () => {
console.log('someone connected to server'); // this is running only if the code above runs (but its intermitent)
});
server.on('listening', () => {
console.log('server is listening'); // this is the first log to execute
childProcess.send('server', server); // send the server connection to forked child
});
server.listen(null, function () {
console.log('server listen callback'); // this is the second log to execute
});
// child.js
console.log('forked'); // this is the third log to execute
const net = require('net');
process.on('message', (m, server) => {
if (m === 'server') {
const socket = net.connect(server.address());
socket.on('ready', () => {
console.log('child is ready'); // this is the fourth log to execute
socket.write('child first message'); // this is always running
})
}
});
the expected log when execute node server is:
server is listening
server listen callback
forked
child is ready
got socket connection
someone connected to server
child first message
but as the socket callback (at createServer) is intermitent, we get this 50% of times:
server is listening
server listen callback
forked
child is ready
IDK what to do anymore, already tried everything I could... What am I doing wrong?

Just found what was the problem... when I read the documentation I misunderstood that literally the net server is being sent to the child process to share the "connections" to divide the processing in more than one process, and what I was trying to archive was just an 2 way communication with the forked child. I'll let this answer here if someone arrive at the same problem as me. This is the final code:
// server.js
const childProcess = require('child_process').fork('child.js');
const server = require('net').createServer((socket) => {
console.log('got socket connection');
socket.on('data', (stream) => {
console.log(stream.toString());
})
});
server.on('connection', () => {
console.log('someone connected to server');
});
server.listen(null, function () {
childProcess.send(server.address());
});
// child.js
console.log('forked');
const net = require('net');
process.on('message', (message) => {
if (message.port) {
const socket = net.connect(message);
socket.on('ready', () => {
console.log('child is ready');
socket.write('child first message');
})
}
});

Related

Spawning Java File

How can i spawn a java file while receiving stdout output?
I am trying to start a minecraft server file using child_process' spawn function, and attempting to get the output thats getting sent.
Heres what i've tried
var childP = require("child_process")
var server = childP.spawn("java", ["-jar", "Launch.jar", "nogui"])
server.on("spawn", () => {
console.log("Server started")
})
server.on("message", (message) => {
console.log(message)
})
server.on("error", (err) => {
console.log(err)
})
server.on("disconnect", () => {
console.log("Server disconnected");
})
server.on("exit", (code) => {
console.log(`Server exited with code ${code}`)
})
Easily done by just doing server.stdout.on("data"), should've looked more into the spawn event before asking the question :p
var childP = require("child_process")
var server = childP.spawn("java", ["-jar", "Launch.jar", "nogui"])
server.stdout.on("data", (data) => {
console.log(data.toString().trim())
})
To spawn a Java file and receive its standard output using the child_process module in Node.js, you can use the spawn function as follows:
`const { spawn } = require('child_process');
const javaProcess = spawn('java', ['-jar', 'minecraft_server.jar']);
javaProcess.stdout.on('data', (data) => {
console.log(stdout: ${data});
});
javaProcess.stderr.on('data', (data) => {
console.error(stderr: ${data});
});
javaProcess.on('close', (code) => {
console.log(child process exited with code ${code});
});`

Websocket memory leak node.js. Event emitters?

I am getting the event emitter leak after using my code 10 times essentially. I understand the default of event emitter auto sending out a warning in the console. My question is what in this code is directly creating the event listeners? Is it poor coding on my part or is it just how the websockets are stacked onto each other?
I'll explain the code a bit. I have one websocket within another and I figured it would serve the data to a web page essentially flowing from Twitch to a localhost site. However, if I use the keywords more than 10 times, I get the error. I do not understand enough about WebSockets to really understand why my code creates a new listener with each msg.text received so anyone with a bit more understanding please help!
I believe me issue to be similar to this though I am having a hard time conceptualizing my own code here
const { paintballShot } = require('./JavaScript/paintballGunFire');
const { readPin } = require('./JavaScript/readPin');
const ws = require('ws');
const express = require('express');
const app = express();
//CONNECT TO TWITCH
let client = new ChatClient({
connection: {
type: "websocket",
secure: true,
}
});
//connected?
client.on("ready", () => console.log("Successfully connected to chat"));
client.on("close", (error) => {
if (error != null) {
console.error("Client closed due to error", error);
}
});
//create headless websocket
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', function connection(socket) {
//call other websocket connected to Twitch from inside the new websocket
client.on("PRIVMSG", (msg, error) => {
if (msg.messageText === "right") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "left") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "fire") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
paintballShot();
}
if (msg.messageText === "pin") {
readPin();
}
process.on('uncaughtException', function (err) {
console.log(err);
});
});
client.connect();
client.join("channel");
socket.on('message', message => console.log(message));
});
// `server` is a vanilla Node.js HTTP server
const server = app.listen(3000);
server.on('upgrade', (request, socket, head) => {
wsServer.handleUpgrade(request, socket, head, socket => {
wsServer.emit('connection', socket, request);
});
});
process.on('uncaughtException', function (err) {
console.log(err);
});
To wrap this up, the library I am using (Dank TwitchIRC) does have a connection rate limiter that seems to work if you add it to your chat client in the beginning. If I set it low enough, depending on the messages received from Twitch, it will end connections just as fast, meaning no memory leak.

How to make connection with MQTT mosquito broker in React?

I am trying to make a connection between my React web app and a mosquito broker which runs on docker. To do this i am using a MQTT.js libary.
Here is my code so far:
const mqtt = require('mqtt')
const client = mqtt.connect('tcp://172.19.0.4:1883')
console.log('mounted');
client.on('connect', function () {
console.log('connected')
client.subscribe('/powertest', function (err) {
if (!err) {
// client.publish('presence', 'Hello mqtt')
console.log('error')
}
})
})
client.on('message', function (topic, message) {
// message is Buffer
console.log(message.toString())
// client.end()
})
This code is in the componentDidMount lifecycle event. When I run it, it shows no errors and it does not enter the on connect area. All I see in the console is the "mounted" log message.
How do I make it connect with the broker?
Let's put the subscriber and the publisher in the same file:
var mqtt = require('mqtt')
var client = mqtt.connect('mqtt://test.mosquitto.org')
client.on('connect', function () {
client.subscribe('presence', function (err) {
if (!err) {
client.publish('presence', 'Hello mqtt')
}
})
})
client.on('message', function (topic, message) {
// message is Buffer
console.log(message.toString())
client.end()
})

Node.js setInterval() timing/scheduling alternatives

I'm trying to develop a Node.js server that acts as a metronome (sends a repeated timing message) for everybody connected. I have socket.io rooms working so clients can "subscribe" to different metronomes, but sync between them drifts wildly. I've been using multiple setInterval() calls to schedule timing messages, and I understand that it isn't a very reliable clock source:
Client:
const socket = io('localhost:8000', {});
socket
.on('connect', function() {
console.log('connected');
})
.on('message', function(payload) {
console.log(payload);
});
// window.max is specific to the Max/MSP web browser object.
// This basically just subscribes to room 'inst0' or 'inst1'.
window.max.bindInlet('subscribe', function(inst) {
socket.emit('subscribe', inst);
});
Server:
io.sockets
.on('connection', (socket) => {
console.log('max connected!');
socket
.on('subscribe', (payload) => {
console.log('subscription: ' + payload);
Object.keys(socket.rooms).forEach(key => socket.leave(key));
socket.join('inst'+payload);
});
});
setInterval(() => {
io.to('inst0').emit('message', 'bang');
}, 500);
setInterval(() => {
io.to('inst1').emit('message', 'bang');
}, 250);
Are there other strategies for event scheduling like this? In a latency-free world the messages would have sample-accurate timing (44.1kHz resolution), but I'd be ecstatic to get something even around 30Hz.

Issue with socket.io updating component to show new message in chatroom

I am building a chat app with React, Node/Express and socket.io. I have my sockets successfully set to my express server via http.createServer. I have a listener on client and server listening for new messages coming into the chat room. Ideally, I want each instance of the chat to be updated when there is an additional message, like any chat room that ever existed :)
Now I have a successful listen between client and server. I know because of a console.log server-side. However, I am not re-rendering the chat component when I submit a new message from a different instance.
So my code in my client-side (again React) component is as follows and I am using the socket CDN with script tags in my index.html (script tags not shown):
Socket CDN here
var socket = io('')
So that is the socket you see client side :
componentDidMount() {
return axios.get(`api/messages`)
.then((result) => {
if (result.data.length) {
this.setState({
messages: [ ...this.state.messages, ...result.data]
} , () => {
console.log("The state after messages are mounted : ", this.state)
})
}
})
.catch((err) => { throw err})
socket.on('new message', msg => {
this.newMessage(msg);
})
};
newMessage(msg) {
this.setState({
messages: [...this.state.messages, msg]
}, () => {
this.setState({ message: '' })
return this.scrollToBottom()
});
};
onSubmitMessage(event) {
event.preventDefault();
const content = this.state.message;
const msg = {
content,
createdAt : new Date(),
userId : "one",
chatRoomId : "two"
}
axios.post(`api/messages/`, msg)
.then(() => {
this.newMessage(msg);
socket.emit('new message', msg); //HERE'S THE SOCKETS IN ACTION
})
};
Here is the server-side code Node/Express:
//in server.js
const io = new socketIo(server)
require('./socketEvents')(io);
const connections = [];
Then a separate file for my socket events
//in socketEvents.js
module.exports = (io) => {
io.on('connection', (socket) => {
console.log("Beautiful sockets are connected")
socket.once('disconnect', () => {
console.log("socket is disconnected");
});
//DOESN'T DO ANYTHING YET
socket.on('join global', (username) => {
socket.join(username);
console.log("New user in the global chat : ", username)
});
socket.on('new message', (msg) => {
console.log("The new message from sockets : ", msg);
socket.emit('new message', msg.content);
});
});
}
My sockets server side are linked up with the client. I'm just not seeing new messages in different instances. Is it because I'm not re-rendering after the server receives the message?
Thanks in advance, please let me know if you need me to clarify anything.
Cheers!
I figured it out... I'm going to leave this post up with a walkthrough in an attempt to help others who are having trouble with sockets. I may post a blog about it. Will update if I do.
So the code listens on the client side for a message to be sent inside of my onSubmitMessage function.
onSubmitMessage(event) {
event.preventDefault(); //prevents HTML <form> from going on its own post
const content = this.state.message;
//Create message object
const msg = {
content,
createdAt : new Date(),
userId : "one",
chatRoomId : "two"
}
//HERE'S THE IMPORTANT PART!!!
axios.post(`api/messages/`, msg)
.then(() => {
// wrapped in a promise, send a handler to server called
// ('new message') with the message object
this.newMessage(msg);
socket.emit('new message', msg);
})
.then(() => {
//Another promise then waits for the handler to come back from server
//*****IMPORTANT*************
//Then invoke newMessage function to get the post on all sockets
socket.on('message', (msg) => {
this.newMessage(msg);
})
})
};
Now on the server side this is what's happening:
// This is where the listener is for the client side handle
socket.on('new message', (msg) => {
// broadcast.emit will send the msg object back to client side and
// post to every instance expcept for the creator of the message
socket.broadcast.emit('message', msg);
});
SO the data path is (C) for client, (S) for server:
receive message object from user and -------->
(C)socket.emit('new message') -----> (S) socket.on('new message') -------> (S) socket.broadcast.emit('message') --------> (C)socket.on('message')
Back in the client side, I can invoke my newMessage function, which will set the message to state so I can display it.
I hope someone finds this useful! Surprisingly, this seems to go relatively unanswered on Stack. If anyone has any questions feel free to ask!

Categories