From 73e16055c978ede7f44fc0d6a314effabda83d30 Mon Sep 17 00:00:00 2001
From: Luiz N <lngj2003@gmail.com>
Date: Tue, 27 Apr 2021 18:33:59 -0300
Subject: [PATCH 1/2] Updated relay server

Added optional SSL
Ping check
Connection counter
---
 websocket-relay.js | 180 +++++++++++++++++++++++++++++----------------
 1 file changed, 118 insertions(+), 62 deletions(-)

diff --git a/websocket-relay.js b/websocket-relay.js
index 1cb47f15..c69a60d1 100755
--- a/websocket-relay.js
+++ b/websocket-relay.js
@@ -1,89 +1,145 @@
+"use strict";
 // Use the websocket-relay to serve a raw MPEG-TS over WebSockets. You can use
 // ffmpeg to feed the relay. ffmpeg -> websocket-relay -> browser
 // Example:
-// node websocket-relay yoursecret 8081 8082
+// node websocket-relay
 // ffmpeg -i <some input> -f mpegts http://localhost:8081/yoursecret
 
-var fs = require('fs'),
-	http = require('http'),
-	WebSocket = require('ws');
-
-if (process.argv.length < 3) {
-	console.log(
-		'Usage: \n' +
-		'node websocket-relay.js <secret> [<stream-port> <websocket-port>]'
-	);
-	process.exit();
-}
+//Configs
+var cfg = {
+	ssl: true,
+	host: 'localhost',
+	input_port: 8081,
+	output_port: 8082,
+	ssl_key: 'privkey.key',
+	ssl_cert: 'pubcert.crt',
+	stream_secret: 'yoursecret',
+	record_stream: false,
+	stream_path: 'recordings/'
+};
+process.title = 'Stream Server';
 
-var STREAM_SECRET = process.argv[2],
-	STREAM_PORT = process.argv[3] || 8081,
-	WEBSOCKET_PORT = process.argv[4] || 8082,
-	RECORD_STREAM = false;
+// Node Configs (Don't touch)
+var fs = require('fs');
+var http = require('http');
+var https = require('https');
+var websocket = require('ws');
+var ws_input = false;
+var ws_output = false;
 
-// Websocket Server
-var socketServer = new WebSocket.Server({port: WEBSOCKET_PORT, perMessageDeflate: false});
-socketServer.connectionCount = 0;
-socketServer.on('connection', function(socket, upgradeReq) {
-	socketServer.connectionCount++;
-	console.log(
-		'New WebSocket Connection: ', 
-		(upgradeReq || socket.upgradeReq).socket.remoteAddress,
-		(upgradeReq || socket.upgradeReq).headers['user-agent'],
-		'('+socketServer.connectionCount+' total)'
-	);
-	socket.on('close', function(code, message){
-		socketServer.connectionCount--;
-		console.log(
-			'Disconnected WebSocket ('+socketServer.connectionCount+' total)'
-		);
-	});
-});
-socketServer.broadcast = function(data) {
-	socketServer.clients.forEach(function each(client) {
-		if (client.readyState === WebSocket.OPEN) {
-			client.send(data);
-		}
+// Input
+var handleInputConnection = function(){
+	var app = http.createServer(onRequestInput);
+	app.headersTimeout = 0;
+	app.listen(cfg.input_port, cfg.host);
+	
+	ws_input = new websocket.Server({server:app, perMessageDeflate:false});
+	ws_input.on('connection', function(client){
+		client.ip = client._socket.remoteAddress;
+		
+		client.on('close', function(reasonCode, description){
+			console.log('['+client.ip+'] closed');
+		});
+		
+		console.log('Stream ['+client.ip+'] connected');
 	});
 };
-
-// HTTP Server to accept incomming MPEG-TS Stream from ffmpeg
-var streamServer = http.createServer( function(request, response) {
+var onRequestInput = function(request, response){
 	var params = request.url.substr(1).split('/');
 
-	if (params[0] !== STREAM_SECRET) {
-		console.log(
-			'Failed Stream Connection: '+ request.socket.remoteAddress + ':' +
-			request.socket.remotePort + ' - wrong secret.'
-		);
-		response.end();
+	if (params[0] !== cfg.stream_secret) {
+		console.log('Failed stream connection: '+request.socket.remoteAddress+':'+request.socket.remotePort+' - wrong secret');
+		return response.end();
 	}
 
 	response.connection.setTimeout(0);
-	console.log(
-		'Stream Connected: ' + 
-		request.socket.remoteAddress + ':' +
-		request.socket.remotePort
-	);
+
 	request.on('data', function(data){
-		socketServer.broadcast(data);
-		if (request.socket.recording) {
+		ws_output.broadcast(data);
+		if(request.socket.recording){
 			request.socket.recording.write(data);
 		}
 	});
 	request.on('end',function(){
-		console.log('close');
+		console.log('Stream end');
 		if (request.socket.recording) {
 			request.socket.recording.close();
 		}
 	});
 
-	// Record the stream to a local file?
-	if (RECORD_STREAM) {
-		var path = 'recordings/' + Date.now() + '.ts';
+	// Record the stream to a local file
+	if (cfg.record_stream) {
+		var path = stream_path + Date.now() + '.ts';
 		request.socket.recording = fs.createWriteStream(path);
 	}
-}).listen(STREAM_PORT);
+	
+    console.log('Stream connected');
+};
+handleInputConnection();
+
+// Output
+var handleOutputConnection = function(){
+	var app = false;
+	if(cfg.ssl){
+		app = https.createServer({
+			key: fs.readFileSync(cfg.ssl_key),
+			cert: fs.readFileSync(cfg.ssl_cert)
+		}, onRequestOutput);
+	}else{
+		app = http.createServer(onRequestOutput);
+	}
+	app.headersTimeout = 0;
+	app.listen(cfg.output_port, cfg.host);
+		
+	ws_output = new websocket.Server({server:app, perMessageDeflate:false});
+	ws_output.on('connection', function(client){
+		client.ip = client._socket.remoteAddress;
+		client.isAlive = true; //ping check
+		
+		client.on('close', function(reasonCode, description){
+			console.log('['+client.ip+'] closed.');
+			process.title = "("+ws_output.clients.size+") Stream Server";
+		});
+		
+		client.on('error', function(e){
+			console.log('Erro, cliente desconectado: '+e);
+			process.title = "("+ws_output.clients.size+") Stream Server";
+		});
+		
+		client.on('pong', function(e){
+			client.isAlive = true;
+		});
+		
+		console.log('Client ['+client.ip+'] connected');
+		process.title = "("+ws_output.clients.size+") Stream Server";
+	});
+	
+	ws_output.broadcast = function(data) {
+		ws_output.clients.forEach(function each(client){
+			if(client.readyState === websocket.OPEN){
+				client.send(data);
+			}
+		});
+	};
+};
+handleOutputConnection();
+var onRequestOutput = function(request,response){
+    console.log('Client requesting connection');
+	response.end();
+};
+
+var nop = function(){};
+var pingInterval = setInterval(function ping(){
+  ws_output.clients.forEach(function each(client){
+    if(client.isAlive){
+		client.isAlive = false;
+		client.ping(nop);
+	}else{
+		console.log('Client ['+client.ip+'] close, no ping response');
+		client.terminate();
+	}
+  });
+}, 15000);
 
-console.log('Listening for incomming MPEG-TS Stream on http://127.0.0.1:'+STREAM_PORT+'/<secret>');
-console.log('Awaiting WebSocket connections on ws://127.0.0.1:'+WEBSOCKET_PORT+'/');
+console.log('Listening for incomming MPEG-TS Stream');
+console.log('Awaiting WebSocket connections');

From 619934745ad046f30ba1fcdbaeeb534bda07bf2d Mon Sep 17 00:00:00 2001
From: Luiz N <lngj2003@gmail.com>
Date: Tue, 27 Apr 2021 18:36:23 -0300
Subject: [PATCH 2/2] Update websocket-relay.js

---
 websocket-relay.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/websocket-relay.js b/websocket-relay.js
index c69a60d1..c2a1e548 100755
--- a/websocket-relay.js
+++ b/websocket-relay.js
@@ -102,7 +102,7 @@ var handleOutputConnection = function(){
 		});
 		
 		client.on('error', function(e){
-			console.log('Erro, cliente desconectado: '+e);
+			console.log('Error, client disconnected: '+e);
 			process.title = "("+ws_output.clients.size+") Stream Server";
 		});