Close createWebsocketStream without closing the websocket connection (node, ws) - node.js

I have been testing sending files over websocket from a client to server using the createWebsocketStream function from ws library like so:
client server
readFileStream ---> WebSocketStream ---> writeFileStream
It works insomuch as I can send even large files successfully, but when I try to close the duplex on the client side, it closes the whole websocket connection.
On the server-side, the WebsocketStream doesn't emit a close event so I can't signal based on that.
So I have two problems:
I can't start and end a duplex websocketstream on the same persistent websocket connection. To workaround this I fork a new websocket connection for streaming properties, but this kind of feels like a hack. If I understand correctly, this is because the duplex is a wrapper around the ws connection and is by design, but I would appreciate a sanity check on that.
The websocketstream doesn't emit a close event so I can't signal the filewrite stream to end based on that.
Is this by design? Is it not possible to start and end a duplex stream on the same ws connection?
If it helps, here is what I have working: I end the writeFileStream based on a ws connection closure:
server:
//server.js
const WebSocket = require('ws');
const fs = require('fs');
const wsserver = new WebSocket.Server({ port: 8080 });
const destinationFileStream = fs.createWriteStream('./bar');
wsserver.on('connection', function connection(ws) {
console.log("client connected");
duplex = WebSocket.createWebSocketStream(ws);
duplex.on('data', function(data){
destinationFileStream.write(data);
});
duplex.on('close', function(){ //<----------i want to put it here but this never triggers
console.log("the duplex channel has closed")
});
ws.on('close', function(){
console.log("websocket has closed")
destinationFileStream.end(); //<----------instead I have to put it here :(
});
destinationFileStream.on('close', function(){
console.log("file has been written successfully")
})
});
client:
//client.js
const WebSocket = require('ws');
const fs = require('fs');
// connect to the server for normal communication
const ws = new WebSocket('ws://localhost:8080');
const readFileStream = fs.createReadStream('/home/ubuntu/Downloads/atom-amd64.deb')
ws.on('open', function(){
// fork a NEW connection called wsstream with duplex properties so we can maintain a normal message channel here
var wsstream = new WebSocket('ws://localhost:8080');
var duplex = WebSocket.createWebSocketStream(wsstream, { emitClose: true });
readFileStream.on('data', function(data){
console.log('reading file stream')
duplex.write(data);
});
readFileStream.on('close', function(){
console.log("file has been read successfully")
duplex.end(); // <--- this triggers the wsstream.on('close') function
});
duplex.on('close', function(){ // <- this never fires because there's no close event
console.log("the duplex channel has closed")
});
wsstream.on('close', function(){
console.log("the wsstream has closed") // <-- closing the duplex channel closes the whole wsstream connection
});
// more functions below for the regular ws connection
});
p.s. sorry for code quality! I only started learning last week.

Related

how to know the client being disconnected from the server when using node.js websocket library ws

I am working the web socket with node.js, the code works in half that it can create connection and receive messages,
var { WebSocketServer, WebSocket } = require('ws')
const ws_server = new WebSocketServer({ port: 8080 });
ws_server.on('connection', (ws) => {
ws.on("message", function(msg,isBinary) {
console.log('on message',msg.toString());
})
// something wrong, client is not defined
ws.on('close', (client) => console.log('Client has disconnected!'),client);
});
however when the client closes the connection, I want to know what client is disconnected.
ws.on('close', (client) => console.log('Client has disconnected!'),client);
this code above gives me an error that client is not defined, so my question is how to know the client information - client id when the client is disconnected from the server.
ws client, which you have in connection callback is Object to which you can add any property you want and it is kept all the time the connection is alive, and also on close.
So add any property that will help you identify your client and use it in the client's on close callback.
const wss = new WebSocketServer({port: 8080})
wss.on('connection', (ws) =>
{ ws.user = CLIENT_NAME;
console.log('CLIENT CONNECTION ESTABLISHED', ws.user);
ws.on('close', (code, data) => {
console.log('CLIENT DISCONNECTED: ', ws.user))
}
}
)
Through the time you will maybe need authenticate the connected client, so follow these instructions. They will help you better identify the incoming client connection.

websocket connection is closing automatically

i have deployed websocket server on heroku and Everything is working good but if there is no transfer between server and client after a certain time the connection is closed. i don't know who is closing the connection server or client and how to resolve this issue.
here is my node.js client code-
const Websocket = require('ws');
var ws = new Websocket('https://secure-mountain-02060.herokuapp.com/');
ws.onmessage = function(event){
console.log(event.data);
}
ws.onclose = function(){
console.log('server close');
}
i found the solution server is closing the connection due to inactivity from client side.
for that we have to ping the server after a certain time that time can be very depending upon the server.
This is how i have solved if anyone needs.
const Websocket = require('ws');
var ws = new Websocket('https://secure-mountain-02060.herokuapp.com/');
function noop() {}
ws.onmessage = function(event){
console.log(event.data);
}
ws.onclose = function(){
console.log('server close');
}
const ping = function() {
ws.ping(noop);
}
setInterval(ping, 30000);

client undefined in websocket server

when i print client in console logconsole.log(client ${client}); it shows undefined.
I think i should do something in my client code but don't know what.
Server code -
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws, request, client) {
console.log(`client ${client}`);
ws.on('message', function message(msg) {
console.log(`Received message ${msg}`);
});
});
client code-
const Websocket = require('ws');
const ws = new Websocket('ws://localhost:8081');
function noop() {}
ws.on("message", function(event){
console.log(event);
});
const ping = function() {
ws.ping(noop);
}
setInterval(ping, 30000);
ws doesn't support client out of the box.
See: https://www.npmjs.com/package/ws#client-authentication
the gist of it is that you need to use an HTTP server to listen to any connections (not using ws to listen) and "manual" emit the connection event with additional data (like client).

How to reconnect when a WebSocket disconnects?

Example:
var WebSocket = require('ws');
var ws = new WebSocket('ws://echo.websocket.org/', {protocolVersion: 8, origin: 'http://websocket.org'});
ws.on('open', function() {
console.log('connected');
ws.send(Date.now().toString(), {mask: true});
});
ws.on('close', function() {
console.log('disconnected');
// What do I do here to reconnect?
});
What should I do when the socket closes to reconnect to the server?
You can wrap all your setup in a function and then call it from the close handler:
var WebSocket = require('ws');
var openWebSocket = function() {
var ws = new WebSocket('ws://echo.websocket.org/', {protocolVersion: 8, origin: 'http://websocket.org'});
ws.on('open', function() {
console.log('connected');
ws.send(Date.now().toString(), {mask: true});
});
ws.on('close', function() {
console.log('disconnected');
openWebSocket();
});
}
openWebSocket();
However, there is likely more logic you want here (what if the close was on purpose? what happens if you try to send a message while its reconnecting?). You're probably better off using a library. This library suggested by aembke in the comments seems reasonable. socket.io is not a bad choice (and it gives you non-WebSocket transports).

How does one properly shutdown socket.io / websocket-client?

I'm trying to create a test using LearnBoost's socket.io and the node-websocket-client. Communication between the client and server work great. After all communication is done, I close both the client and the server. Yet the program hangs, waiting on some unknown callback. Two questions:
What is the following program waiting for?
Is there a tool for diagnosing outstanding callbacks in node programs?
var connect = require('connect'),
io = require('socket.io'),
WebSocket = require('websocket-client').WebSocket;
var port = 7111;
var server = connect.createServer();
var socket = io.listen(server);
socket.on('connection', function(client) {
client.send('Welcome!');
client.on('message', function(message) {
console.log(message);
});
client.on('disconnect', function() {
console.log('closing');
server.close();
});
});
server.listen(port, function() {
var ws = new WebSocket('ws://localhost:' + port + '/socket.io/websocket');
ws.onmessage = function(message) {
console.log(message.data);
};
setTimeout(function() {
ws.send('~m~3~m~Yo!');
ws.close();
}, 10);
});
EDIT: changed the variable name of the WebSocket to ws to avoid confusion
var socket = io.listen(server);
You've created a socket on a port. You've never closed it.
socket.server.close() closes your (socket.io) socket.
When in doubt read the socket.io github examples
socket.server === server It's the server you pass in, in the liste statement so it's closed. I'm not sure what it's waiting for.
Below a way to shutdown all the connections and be able to run multiple expresso tests (using socket.io and socket.io-client).
The solution is tricky and buggy but works on 0.8.5. The main problem is regarding the library to use websockets (node-websocket-client).
Currently, on socket.io, the OS contributors have patched the websocket client. So, we must do the same on our socket.io-client npm package to be able to use finishClose method on the socket client side. Socket.io-client uses the websocket library as npm package, so you must find the file (websocket.js) and substitute it with the same on socket.io.
Afterwards, you could use finishClose method to ensure the connections are closed and with some custom server/client socket settings, the tests will run correctly.
var io = require("socket.io").listen(port);
io.set('close timeout', .2);
io.set('client store expiration', .2);
var client = require("socket.io-client").connect( "http://localhost", { port: port , 'reconnect': false, 'force new connection': true});
client.on('connect', function() {
client.disconnect();
});
client.on('disconnect', function() {
client.socket.transport.websocket.finishClose();
io.server.close();
});
io.server.on('close', function() {
setTimeout( function() {
done();
}, 500);
});
Hope, somebody can help.
The program is waiting because socket.io (server) is still listening for incoming connections. I don't know of any way to stop listening.

Resources