1
0
mirror of https://github.com/KubaPro010/fm-dx-webserver.git synced 2026-02-26 22:13:53 +01:00

Merge pull request #133 from AmateurAudioDude/fixes/v1.3.6.1-serialport-and-api

Fixes/v1.3.6.1 serialport and api
This commit is contained in:
Marek Farkaš
2025-04-22 13:14:08 +02:00
committed by GitHub
2 changed files with 64 additions and 23 deletions

View File

@@ -139,6 +139,7 @@ const callbacks = {
dataToSend.rt1 = decode_unicode(rt); dataToSend.rt1 = decode_unicode(rt);
dataToSend.rt1_errors = decode_errors(rt); dataToSend.rt1_errors = decode_errors(rt);
} }
dataToSend.rt_flag = flag;
}, 'callback_rt*'), }, 'callback_rt*'),
ptyn: koffi.register((rds, flag) => ( ptyn: koffi.register((rds, flag) => (
@@ -222,6 +223,7 @@ var dataToSend = {
af: [], af: [],
rt0: '', rt0: '',
rt1: '', rt1: '',
rt_flag: '',
ims: 0, ims: 0,
eq: 0, eq: 0,
ant: 0, ant: 0,
@@ -431,15 +433,19 @@ function handleData(wss, receivedData, rdsWss) {
} }
// Serialport retry code when port is open but communication is lost (additional code in index.js) // Serialport retry code when port is open but communication is lost (additional code in index.js)
isSerialportAlive = true; let state = {
lastFrequencyAlive = '87.500'; isSerialportAlive: true,
isSerialportRetrying: false,
lastFrequencyAlive: '87.500'
};
setInterval(() => { setInterval(() => {
lastFrequencyAlive = initialData.freq; state.lastFrequencyAlive = initialData.freq;
const serialportElapsedTime = process.hrtime(serialportUpdateTime)[0]; const serialportElapsedTime = process.hrtime(serialportUpdateTime)[0];
// Activate serialport retry if handleData has not been executed for over 8 seconds // Activate serialport retry if handleData has not been executed for over 8 seconds
if (checkSerialport && (serialportElapsedTime > 8) && !isSerialportRetrying && serverConfig.xdrd.wirelessConnection === false) { if (checkSerialport && (serialportElapsedTime > 8) && !state.isSerialportRetrying && serverConfig.xdrd.wirelessConnection === false) {
isSerialportAlive = false; state.isSerialportAlive = false;
isSerialportRetrying = true; state.isSerialportRetrying = true;
} }
}, 2000); }, 2000);
@@ -464,7 +470,13 @@ function showOnlineUsers(currentUsers) {
initialData.users = currentUsers; initialData.users = currentUsers;
} }
let prevFreq = initialData.freq || '87.500';
function processSignal(receivedData, st, stForced) { function processSignal(receivedData, st, stForced) {
if (initialData.freq !== prevFreq) {
prevFreq = initialData.freq;
dataToSend.ps_errors = '';
}
const modifiedData = receivedData.substring(2); const modifiedData = receivedData.substring(2);
const parsedValue = parseFloat(modifiedData); const parsedValue = parseFloat(modifiedData);
dataToSend.st = st; dataToSend.st = st;
@@ -490,5 +502,5 @@ function processSignal(receivedData, st, stForced) {
} }
module.exports = { module.exports = {
handleData, showOnlineUsers, dataToSend, initialData, resetToDefault handleData, showOnlineUsers, dataToSend, initialData, resetToDefault, state
}; };

View File

@@ -18,7 +18,7 @@ const path = require('path');
const net = require('net'); const net = require('net');
const client = new net.Socket(); const client = new net.Socket();
const { SerialPort } = require('serialport'); const { SerialPort } = require('serialport');
const tunnel = require('./tunnel') const tunnel = require('./tunnel');
// File imports // File imports
const helpers = require('./helpers'); const helpers = require('./helpers');
@@ -118,12 +118,12 @@ connectToSerial();
tunnel.connect(); tunnel.connect();
// Serialport retry code when port is open but communication is lost (additional code in datahandler.js) // Serialport retry code when port is open but communication is lost (additional code in datahandler.js)
isSerialportRetrying = false; dataHandler.state.isSerialportRetrying = false;
setInterval(() => { setInterval(() => {
if (!isSerialportAlive && serverConfig.xdrd.wirelessConnection === false) { if (!dataHandler.state.isSerialportAlive && serverConfig.xdrd.wirelessConnection === false) {
isSerialportAlive = true; dataHandler.state.isSerialportAlive = true;
isSerialportRetrying = true; dataHandler.state.isSerialportRetrying = true;
if (serialport && serialport.isOpen) { if (serialport && serialport.isOpen) {
logWarn('Communication lost from ' + serverConfig.xdrd.comPort + ', force closing serialport.'); logWarn('Communication lost from ' + serverConfig.xdrd.comPort + ', force closing serialport.');
setTimeout(() => { setTimeout(() => {
@@ -163,7 +163,7 @@ if (serverConfig.xdrd.wirelessConnection === false) {
} }
logInfo('Using COM device: ' + serverConfig.xdrd.comPort); logInfo('Using COM device: ' + serverConfig.xdrd.comPort);
isSerialportAlive = true; dataHandler.state.isSerialportAlive = true;
setTimeout(() => { setTimeout(() => {
serialport.write('x\n'); serialport.write('x\n');
}, 3000); }, 3000);
@@ -177,12 +177,12 @@ if (serverConfig.xdrd.wirelessConnection === false) {
serialport.write('T' + Math.round(serverConfig.defaultFreq * 1000) + '\n'); serialport.write('T' + Math.round(serverConfig.defaultFreq * 1000) + '\n');
dataHandler.initialData.freq = Number(serverConfig.defaultFreq).toFixed(3); dataHandler.initialData.freq = Number(serverConfig.defaultFreq).toFixed(3);
dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3); dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3);
} else if (lastFrequencyAlive && isSerialportRetrying) { // Serialport retry code when port is open but communication is lost } else if (dataHandler.state.lastFrequencyAlive && dataHandler.state.isSerialportRetrying) { // Serialport retry code when port is open but communication is lost
serialport.write('T' + (lastFrequencyAlive * 1000) + '\n'); serialport.write('T' + (dataHandler.state.lastFrequencyAlive * 1000) + '\n');
} else { } else {
serialport.write('T87500\n'); serialport.write('T87500\n');
} }
isSerialportRetrying = false; dataHandler.state.isSerialportRetrying = false;
serialport.write('A0\n'); serialport.write('A0\n');
serialport.write('F-1\n'); serialport.write('F-1\n');
@@ -207,7 +207,7 @@ if (serverConfig.xdrd.wirelessConnection === false) {
serialport.on('close', () => { serialport.on('close', () => {
logWarn('Disconnected from ' + serverConfig.xdrd.comPort + '. Attempting to reconnect.'); logWarn('Disconnected from ' + serverConfig.xdrd.comPort + '. Attempting to reconnect.');
setTimeout(() => { setTimeout(() => {
isSerialportRetrying = true; dataHandler.state.isSerialportRetrying = true;
connectToSerial(); connectToSerial();
}, 5000); }, 5000);
}); });
@@ -421,10 +421,12 @@ wss.on('connection', (ws, request) => {
ws.on('message', (message) => { ws.on('message', (message) => {
const command = helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '18', 'text'); const command = helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '18', 'text');
if (((command.startsWith('X') || command.startsWith('Y')) && !request.session.isAdminAuthenticated) || if (!clientIp.includes("127.0.0.1")) {
((command.startsWith('F') || command.startsWith('W')) && serverConfig.bwSwitch === false)) { if (((command.startsWith('X') || command.startsWith('Y')) && !request.session.isAdminAuthenticated) ||
logWarn(`User \x1b[90m${clientIp}\x1b[0m attempted to send a potentially dangerous command. You may consider blocking this user.`); ((command.startsWith('F') || command.startsWith('W')) && serverConfig.bwSwitch === false)) {
return; logWarn(`User \x1b[90m${clientIp}\x1b[0m attempted to send a potentially dangerous command: ${command.slice(0, 64)}.`);
return;
}
} }
if (command.includes("\'")) { if (command.includes("\'")) {
@@ -680,6 +682,26 @@ pluginsWss.on('connection', (ws, request) => {
}); });
}); });
function isPortOpen(host, port, timeout = 1000) {
return new Promise((resolve) => {
const socket = new net.Socket();
const onError = () => {
socket.destroy();
resolve(false);
};
socket.setTimeout(timeout);
socket.once('error', onError);
socket.once('timeout', onError);
socket.connect(port, host, () => {
socket.end();
resolve(true);
});
});
}
// Websocket register for /text, /audio and /chat paths // Websocket register for /text, /audio and /chat paths
httpServer.on('upgrade', (request, socket, head) => { httpServer.on('upgrade', (request, socket, head) => {
if (request.url === '/text') { if (request.url === '/text') {
@@ -689,8 +711,15 @@ httpServer.on('upgrade', (request, socket, head) => {
}); });
}); });
} else if (request.url === '/audio') { } else if (request.url === '/audio') {
proxy.ws(request, socket, head); isPortOpen('localhost', (Number(serverConfig.webserver.webserverPort) + 10)).then((open) => {
} else if (request.url === '/chat') { if (open) {
proxy.ws(request, socket, head);
} else {
logWarn(`Audio stream port ${(Number(serverConfig.webserver.webserverPort) + 10)} not yet open — skipping proxy connection.`);
socket.end(); // close socket so client isn't left hanging
}
});
} else if (request.url === '/chat') {
sessionMiddleware(request, {}, () => { sessionMiddleware(request, {}, () => {
chatWss.handleUpgrade(request, socket, head, (ws) => { chatWss.handleUpgrade(request, socket, head, (ws) => {
chatWss.emit('connection', ws, request); chatWss.emit('connection', ws, request);