Node.js BinaryServer: Send a message to the client on stream end? - javascript

I'm using a node.js BinaryServer for streaming binary data and I want a callback event from the server, after the client calls for the .Stream.end() function.
I can't seem to understand - How can I send a message or some kind of notification when the node.js server actually closes the stream connection ?
Node JS:
server.on('connection', function(client) {
client.on('stream', function (stream, meta) {
stream.on('end', function () {
fileWriter.end();
// <--- I want to send an event to the client here
});
});
});
client JS:
client = new BinaryClient(nodeURL);
window.Stream = client.createStream({ metaData });
....
window.Stream.end();
// <--- I want to recieve the callback message

On the server side, you can send streams to the client with .send. You can send a variety of data types, but a simple string will probably suffice in this case.
On the client side you can also listen to the 'stream' event to receive data back from the server.
Node JS:
server.on('connection', function(client) {
client.on('stream', function (stream, meta) {
stream.on('end', function () {
fileWriter.end();
client.send('finished');
});
});
});
client JS:
client = new BinaryClient(nodeURL);
client.on('stream', data => {
console.log(data); // do something with data
});
window.Stream = client.createStream({ metaData });
....
window.Stream.end();

Related

Javascript: How can I interact with a TCP Socket API using net.connect properly?

I'm fairly new to Javascript and am trying to wrap my head around async, promises, etc.
I have an application running a TCP API (non-HTTP) on the localhost. I'm building an Electron app to interact with this API. I need to send a single request to the API every second and retrieve a single JSON object it returns.
I'm able to do this successfully (for while) by running something like this:
const net = require('net');
function apiCall() {
if (running) {
setTimeout(() => {
// Send the request
request = '{"id":1,"jsonrpc":"2.0","method":"getdetails"}'
socketClient = net.connect({host:'localhost', port:8888}, () => {
socketClient.write(request + '\r\n');
});
// Listen for the response
var response;
socketClient.on('data', (data) => {
response = JSON.parse(data).result;
updateUI(response);
socketClient.end();
});
// On disconnect
socketClient.on('end', () => {
console.log('Disconnected from API');
});
apiCall();
}, refreshRate)
}
}
After running this for an extended amount of time, it appears that the API server is crashing:
Error: connect ECONNREFUSED 127.0.0.1:8888
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146)
Unfortunately, I have no control over the API server or its source code. I'd like some clarification on whether my client might be causing the API server to crash by sending requests this way.
Should I be opening and closing the connection for each request or keep it open and send requests only every second?
If I should be keeping the connection open, how can I do this, and do I need to worry about keep-alive?
It looks like that every time you call apiCall you are creating a new socket client and you are not removing the old socket client instances. This is a memory leak and it will cause the application to crash after running for some time
You can keep a running connection instead like below
const net = require("net");
const { once } = require("events");
let socketClient;
function apiCall() {
if (running) {
setTimeout(async () => {
const request = '{"id":1,"jsonrpc":"2.0","method":"getdetails"}';
// Create the socket client if it was not already created
if (!socketClient) {
socketClient = net.connect({ host: "localhost", port: 8888 });
// On disconnect
socketClient.on("end", () => {
console.log("Disconnected from API");
socketClient.destroy();
socketClient = null;
});
// Wait until connection is established
await once(socketClient, "connect");
}
// Send the request
socketClient.write(request + "\r\n");
// Listen for the response
const data = await once(socketClient, "data");
const response = JSON.parse(data).result;
updateUI(response);
apiCall();
}, refreshRate);
}
}

Not able to receive socket data sent from client 1 to server and back to client 2

I'm having some trouble using sockets to connect an electron app to an node(express) website hosted on heroku.
Basically I have 2 clients, for simplicity I'm going to call them teacher and student. So teacher sends data to express and express has to send the data back to student. Since a socket has to be opened from the client side, I'm thus sending a ping to express from student with some dummy data to get the socket connected and then broadcasting the data from express.
What I have tried
teacher and student are in the same app/ teacher is not used when student is used and vice versa
function pingServer() {
socket.emit("givebackinfo", "sendinfo");
setTimeout(pingServer, 5);
}
ipcMain.on("serverPing:getbackinfo", function (E, item) {
console.log(item);
if (item == "returninfo") {
socket.emit("givebackinfo", "sendinfo");
// pingServer()
} else {
console.log("error");}
});
// receive data from express
socket.on("datareturns", (msg) => {
console.log(msg);
mainWindow.webContents.send("RedrawData", msg);
});
The Issue
In express I receive the "sendinfo" but I'm not able to send data back to the client that pinged it
express
rowDelivered = 0;
// Connection for students => sends back relevant data
io.on('connection', (socket) => {
socket.broadcast.emit('datareturns', "returns");
socket.on('givebackinfo', (msg) => {
console.log(msg)
socket.broadcast.emit('datareturns', "returns");
// socket.emit('datareturns', "sendinfo returns")
if (msg != "sendinfo") {
(knex('test').where('id', '>', rowDelivered).then((data) => {
// console.log(data);
// console.log(rowDelivered);
if (data.length >= 1) {
console.log(data)
socket.broadcast.emit('datareturns', data);
} else {
// statement
}
})).then(() => {
knex('test').max('id').then((maxId) => {
rowDelivered = maxId[0].max
});
})
} else {
socket.broadcast.emit("datareturns", "value wrong for redraw data");
}
});
});

Client-side event when Node server comes online

In my client-side node code, I have something like this:
var socket = io('//localhost:1337');
$(function() {
if ( !socket.connected )
NodeOfflineError();
});
Now, let's say I had a NodeBackOnlineAlert() function to go along with the NodeOfflineError() function, how would I know when to call it?
Is there a listener for the polling that checks whether the server is live?
You can have listeners that run the function and have a function to reconnect when the socket is disconnected:
socket.on("disconnect", function() {
NodeOfflineError();
socket.socket.reconnect();
});
socket.on("connect", function() {
NodeOnlineAlert()
});
socket.on("reconnect", function() {
NodeBackOnlineAlert()
});
You can use the listener events of socket io (assuming you use socket io)
const socket = io('//localhost:1337')
$(() => {
socket.on('connected', socket => {
console.log('connected!')
socket.on('disconnect', () => {
NodeOfflineError()
})
})
socket.on('reconnect', () => {
NodeBackOnlineAlert()
})
})
http://socket.io/docs/ Check the part where it says 'Sending and receiving events' also http://socket.io/docs/client-api/ :)
You could use Server Sent Events: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events. The MDN guide should have everything you need to implement them (they're quite simple!). This library might prove useful for your server: https://www.npmjs.com/package/sse

Mocha: testing event receiver

I have been trying to test this code with no luck.
The logic:
This code will connect two clients -Client1 and Client2-, then Client1 will send a message to Client2 - thru a server. When the Server receives the message from Client1, it (the server) will respond to Client1 with an acknowledge message, and then, it will send the new message thru the 'newMessage' event.
The test:
Each client always listens to 'newMessage' event. In this test I want:
a. Connect Client1 and Client2 to server
b. Send a message from Client1 to Client2
c. When Client2 receives the 'newMessage' event, check the incoming data
I dont know if this is possible, all my approaches failed, but in fact, the application works.
describe('> Test case:\n', function () {
describe('> Connect Client1 & Client2', function () {
this.timeout(2000);
// Instantiate testing clients
var client1 = new virtualClient(),
client2 = new virtualClient();
beforeEach(function (done) {
// Connect the test clients
Promise.all([client1.connect( users[0] ), client2.connect( users[1] )]).then(function () {
// When both clients are connected, set a callback function to handle 'newMessage' event on Client2 (I wonder where to test this...)
client2.client.setNewMessageCallback(function(data) {
console.log("-----> Client2 received 'onNewMessage' broadcast");
// Can I use a it() here?
});
done();
}).catch(function (error) {
console.log(error);
});
});
describe('Client1 sends a message to room with Client2', function () {
// I now send a message from Client1 to Client2: this will make
// the server fire the 'newMessage' event and Client2 should
// receive it
it('- Client1 sends a message to Client2', function (done) {
client1.client.sendMessage(client2.data.user._id)
.then(function (response) {
// Should return an Object with properties 'roomId' and 'localRoomId'
response.should.be.an.instanceOf( Object );
done();
});
});
});
});
});

Acknowledgment for socket.io custom event

I am looking for a method to acknowledge a socket.emit call.
socket.emit('message', msg);
I have seen a mechanism where the receiver would send another custom event as an acknowledgement, but this would add thousands of transports in my chat application. Please advice an efficient method.
The third argument to the emit method accepts a callback that will be passed to the server so that you can call in acknowledgement with any data you wish. It's actually really convenient and saves the effort of having paired call-response events.
I'm updating my answer with some code that I just tested.
First on the server side:
io.sockets.on('connection', function (sock) {
console.log('Connected client');
sock.emit('connected', {
connected: 'Yay!'
});
// the client passes 'callback' as a function. When we invoke the callback on the server
// the code on the client side will run
sock.on('testmessage', function (data, callback) {
console.log('Socket (server-side): received message:', data);
var responseData = {
string1: 'I like ',
string2: 'bananas ',
string3: ' dude!'
};
//console.log('connection data:', evData);
callback(responseData);
});
});
On the client side:
console.log('starting connection...');
var socket = io.connect('http://localhost:3000');
socket.on('error', function (evData) {
console.error('Connection Error:', evData);
});
// 'connected' is our custom message that let's us know the user is connected
socket.on('connected', function (data) {
console.log('Socket connected (client side):', data);
// Now that we are connected let's send our test call with callback
socket.emit('testmessage', {
payload: 'let us see if this worketh'
}, function (responseData) {
console.log('Callback called with data:', responseData);
});
});

Categories

Resources