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

bugfix pack, server logs

This commit is contained in:
NoobishSVK
2024-03-28 22:44:24 +01:00
parent 7f483770f2
commit 298a868ef7
13 changed files with 147 additions and 59 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
node_modules/ node_modules/
/*.json /*.json
/ffmpeg.exe /ffmpeg.exe
/serverlog.txt

View File

@@ -1,6 +1,6 @@
{ {
"name": "fm-dx-webserver", "name": "fm-dx-webserver",
"version": "1.1.8", "version": "1.1.9",
"description": "FM DX Webserver", "description": "FM DX Webserver",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@@ -1,6 +1,11 @@
const fs = require('fs');
const verboseMode = process.argv.includes('--debug'); const verboseMode = process.argv.includes('--debug');
const verboseModeFfmpeg = process.argv.includes('--ffmpegdebug'); const verboseModeFfmpeg = process.argv.includes('--ffmpegdebug');
const ANSI_ESCAPE_CODE_PATTERN = /\x1b\[[0-9;]*m/g;
const MAX_LOG_LINES = 100000;
const getCurrentTime = () => { const getCurrentTime = () => {
const currentTime = new Date(); const currentTime = new Date();
const hours = currentTime.getHours().toString().padStart(2, '0'); const hours = currentTime.getHours().toString().padStart(2, '0');
@@ -8,7 +13,12 @@ const getCurrentTime = () => {
return `\x1b[90m[${hours}:${minutes}]\x1b[0m`; return `\x1b[90m[${hours}:${minutes}]\x1b[0m`;
}; };
const removeANSIEscapeCodes = (str) => {
return str.replace(ANSI_ESCAPE_CODE_PATTERN, '');
};
const MESSAGE_PREFIX = { const MESSAGE_PREFIX = {
CHAT: "\x1b[36m[CHAT]\x1b[0m",
DEBUG: "\x1b[36m[DEBUG]\x1b[0m", DEBUG: "\x1b[36m[DEBUG]\x1b[0m",
ERROR: "\x1b[31m[ERROR]\x1b[0m", ERROR: "\x1b[31m[ERROR]\x1b[0m",
FFMPEG: "\x1b[36m[FFMPEG]\x1b[0m", FFMPEG: "\x1b[36m[FFMPEG]\x1b[0m",
@@ -21,14 +31,20 @@ const logs = [];
const maxLogLines = 250; const maxLogLines = 250;
const logDebug = (...messages) => { const logDebug = (...messages) => {
const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.DEBUG} ${messages.join(' ')}`;
if (verboseMode) { if (verboseMode) {
const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.DEBUG} ${messages.join(' ')}`;
logs.push(logMessage); logs.push(logMessage);
if (logs.length > maxLogLines) { if (logs.length > maxLogLines) {
logs.shift(); logs.shift();
} }
console.log(logMessage); console.log(logMessage);
} }
appendLogToFile(logMessage);
};
const logChat = (...messages) => {
const logMessage = `${getCurrentTime()} ${MESSAGE_PREFIX.CHAT} ${messages[0].nickname} (${messages[0].ip}) sent a chat message: ${messages[0].message}`;
appendLogToFile(logMessage);
}; };
const logError = (...messages) => { const logError = (...messages) => {
@@ -38,6 +54,7 @@ const logError = (...messages) => {
logs.shift(); logs.shift();
} }
console.log(logMessage); console.log(logMessage);
appendLogToFile(logMessage);
}; };
const logFfmpeg = (...messages) => { const logFfmpeg = (...messages) => {
@@ -48,6 +65,7 @@ const logFfmpeg = (...messages) => {
logs.shift(); logs.shift();
} }
console.log(logMessage); console.log(logMessage);
appendLogToFile(logMessage);
} }
}; };
@@ -58,6 +76,7 @@ const logInfo = (...messages) => {
logs.shift(); logs.shift();
} }
console.log(logMessage); console.log(logMessage);
appendLogToFile(logMessage);
}; };
const logWarn = (...messages) => { const logWarn = (...messages) => {
@@ -67,8 +86,36 @@ const logWarn = (...messages) => {
logs.shift(); logs.shift();
} }
console.log(logMessage); console.log(logMessage);
appendLogToFile(logMessage);
}; };
function appendLogToFile(logMessage) {
const cleanLogMessage = removeANSIEscapeCodes(logMessage);
fs.appendFile('serverlog.txt', cleanLogMessage + '\n', (err) => {
if (err) {
console.error('Error writing to server log:', err);
} else {
fs.readFile('serverlog.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading server log:', err);
} else {
const lineCount = data.split('\n').length;
if (lineCount > MAX_LOG_LINES) {
const excessLines = lineCount - MAX_LOG_LINES;
const truncatedContent = data.split('\n').slice(excessLines).join('\n');
fs.writeFile('serverlog.txt', truncatedContent, (err) => {
if (err) {
console.error('Error truncating server log:', err);
}
});
}
}
});
}
});
}
module.exports = { module.exports = {
logError, logDebug, logFfmpeg, logInfo, logWarn, logs logError, logDebug, logFfmpeg, logInfo, logWarn, logs, logChat
}; };

View File

@@ -272,6 +272,8 @@ function handleData(ws, receivedData) {
modifiedData = receivedLine.substring(1).split(",")[0]; modifiedData = receivedLine.substring(1).split(",")[0];
if((modifiedData / 1000).toFixed(3) == dataToSend.freq) { if((modifiedData / 1000).toFixed(3) == dataToSend.freq) {
resetToDefault(dataToSend);
rdsparser.clear(rds);
return; // Prevent tune spamming using scrollwheel return; // Prevent tune spamming using scrollwheel
} }
@@ -386,13 +388,18 @@ function processSignal(receivedData, st, stForced) {
initialData.st_forced = stForced; initialData.st_forced = stForced;
if (!isNaN(parsedValue)) { if (!isNaN(parsedValue)) {
dataToSend.signal = parsedValue.toFixed(2); // Convert parsedValue to a number
initialData.signal = parsedValue.toFixed(2); var signal = parseFloat(parsedValue.toFixed(2));
dataToSend.signal = signal;
initialData.signal = signal;
if(dataToSend.signal > dataToSend.highestSignal) { // Convert highestSignal to a number for comparison
dataToSend.highestSignal = dataToSend.signal; var highestSignal = parseFloat(dataToSend.highestSignal);
if (signal > highestSignal) {
dataToSend.highestSignal = signal.toString(); // Convert back to string for consistency
} }
} }
} }
module.exports = { module.exports = {

View File

@@ -61,6 +61,10 @@ router.get('/', (req, res) => {
} }
}); });
router.get('/403', (req, res) => {
res.render('403');
})
router.get('/wizard', (req, res) => { router.get('/wizard', (req, res) => {
let serialPorts; let serialPorts;

View File

@@ -21,9 +21,9 @@ const { SerialPort } = require('serialport')
const helpers = require('./helpers'); const helpers = require('./helpers');
const dataHandler = require('./datahandler'); const dataHandler = require('./datahandler');
const fmdxList = require('./fmdx_list'); const fmdxList = require('./fmdx_list');
const { logDebug, logError, logInfo, logWarn } = require('./console'); const { logDebug, logError, logInfo, logWarn, logChat } = require('./console');
const storage = require('./storage'); const storage = require('./storage');
const { configName, serverConfig, configUpdate, configSave } = require('./server_config'); const { serverConfig } = require('./server_config');
const pjson = require('../package.json'); const pjson = require('../package.json');
console.log(`\x1b[32m console.log(`\x1b[32m
@@ -70,18 +70,9 @@ function connectToSerial() {
serialport.on('open', () => { serialport.on('open', () => {
logInfo('Using COM device: ' + serverConfig.xdrd.comPort); logInfo('Using COM device: ' + serverConfig.xdrd.comPort);
serialport.write('x\n'); serialport.write('x\n');
serialport.write('W0\n');
serialport.write('M0\n');
serverConfig.audio.startupVolume ? serialport.write('Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n') : serialport.write('Y100\n');
serialport.write('D0\n');
serialport.write('A0\n');
serialport.write('F-1\n');
serialport.write('Z0\n');
serialport.write('G11\n');
serialport.write('V0\n');
serialport.write('Q0\n'); serialport.write('Q0\n');
serialport.write('C0\n'); serialport.write('M0\n');
serialport.write('I0,0\n'); serialport.write('Z0\n');
if(serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true) { if(serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true) {
serialport.write('T' + Math.round(serverConfig.defaultFreq * 1000) +'\n'); serialport.write('T' + Math.round(serverConfig.defaultFreq * 1000) +'\n');
@@ -91,6 +82,13 @@ function connectToSerial() {
serialport.write('T87500\n'); serialport.write('T87500\n');
} }
serialport.write('A0\n');
serialport.write('F-1\n');
serialport.write('W0\n');
serialport.write('D0\n');
serialport.write('G11\n');
serverConfig.audio.startupVolume ? serialport.write('Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n') : serialport.write('Y100\n');
serialport.on('data', (data) => { serialport.on('data', (data) => {
helpers.resolveDataBuffer(data, wss); helpers.resolveDataBuffer(data, wss);
}); });
@@ -158,11 +156,11 @@ function connectToXdrd() {
dataHandler.dataToSend.ant = modifiedLine; dataHandler.dataToSend.ant = modifiedLine;
} }
if (authFlags.authMsg && authFlags.firstClient) { if (authFlags.authMsg === true && authFlags.firstClient === true) {
client.write('x\n'); client.write('x\n');
client.write(serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? 'T' + Math.round(serverConfig.defaultFreq * 1000) + '\n' : 'T87500\n'); client.write(serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? 'T' + Math.round(serverConfig.defaultFreq * 1000) + '\n' : 'T87500\n');
dataHandler.initialData.freq = serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? (serverConfig.defaultFreq).toFixed(3) : (87.5).toFixed(3); dataHandler.initialData.freq = serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? Number(serverConfig.defaultFreq).toFixed(3) : (87.5).toFixed(3);
dataHandler.dataToSend.freq = serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? (serverConfig.defaultFreq).toFixed(3) : (87.5).toFixed(3); dataHandler.dataToSend.freq = serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? Number(serverConfig.defaultFreq).toFixed(3) : (87.5).toFixed(3);
client.write('A0\n'); client.write('A0\n');
client.write(serverConfig.audio.startupVolume ? 'Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n' : 'Y100\n'); client.write(serverConfig.audio.startupVolume ? 'Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n' : 'Y100\n');
client.off('data', authDataHandler); client.off('data', authDataHandler);
@@ -406,6 +404,7 @@ chatWss.on('connection', (ws, request) => {
if (storage.chatHistory.length > 50) { if (storage.chatHistory.length > 50) {
storage.chatHistory.shift(); storage.chatHistory.shift();
} }
logChat(messageData);
const modifiedMessage = JSON.stringify(messageData); const modifiedMessage = JSON.stringify(messageData);

View File

@@ -17,7 +17,9 @@
<div class="panel-100 p-10"> <div class="panel-100 p-10">
<br> <br>
<i class="text-big fa-solid fa-exclamation-triangle color-4"></i> <i class="text-big fa-solid fa-exclamation-triangle color-4"></i>
<p>You are not authorized to use this tuner. Please try again later or contact the owner.</p> <p>You are not authorized to use this tuner. <br>
There's a possibility you were kicked or banned by the administrator.<br>
Please try again later or contact the owner.</p>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -92,6 +92,11 @@ label {
display: none; display: none;
} }
#data-station-container h2 {
display: block !important;
padding: 0;
}
#data-station-name { #data-station-name {
font-size: 20px; font-size: 20px;
} }
@@ -309,11 +314,14 @@ pre {
} }
.highest-signal-container { .highest-signal-container {
margin-top: -20px !important; margin-top: -20px !important;
margin-bottom: 15px !important; margin-bottom: -15px !important;
}
#pi-code-container {
margin-bottom: 0 !important;
} }
#data-pi { #data-pi {
font-size: 24px; font-size: 24px;
margin-top: 20px; margin-top: 5px;
color: var(--color-text-2); color: var(--color-text-2);
} }
h2.show-phone { h2.show-phone {
@@ -324,16 +332,18 @@ pre {
font-size: 42px; font-size: 42px;
} }
#data-frequency { #data-frequency {
font-size: 72px; font-size: 64px;
} }
#data-rt0, #data-rt1 { #data-rt0, #data-rt1 {
font-size: 10px; font-size: 10px;
text-align: left; text-align: left;
width: 100%; width: 100%;
word-break: break-all; white-space: nowrap;
overflow-x:auto;
padding: 5px 0;
} }
#rt-container { #rt-container {
height: 32px !important; height: max-content !important;
} }
ul { ul {
font-size: 16px; font-size: 16px;
@@ -376,10 +386,12 @@ pre {
#af-list ul { #af-list ul {
height: auto !important; height: auto !important;
} }
#rt-container { #rt-container {
order: 2; order: 2;
} }
.modal-panel-footer {
width: auto !important;
}
} }
@media only screen and (min-width: 769px) and (max-height: 860px) { @media only screen and (min-width: 769px) and (max-height: 860px) {
@@ -412,6 +424,14 @@ pre {
font-size: 18px; font-size: 18px;
} }
h2.signal-heading {
margin-bottom: 0;
}
.highest-signal-container {
margin-bottom: -10px !important;
}
h2.mb-0 { h2.mb-0 {
margin-bottom: 0; margin-bottom: 0;
margin-top: 2px !important; margin-top: 2px !important;

View File

@@ -77,7 +77,7 @@
<div style="display:inline-block"> <div style="display:inline-block">
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span> <span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
</div> </div>
<span id="stereo-container" class="pointer" style="position: relative;"> <span class="pointer stereo-container" style="position: relative;">
<span style="margin-left: 20px;" class="data-st">ST</span> <span style="margin-left: 20px;" class="data-st">ST</span>
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span> <span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
</span> </span>
@@ -98,7 +98,7 @@
</div> </div>
<div class="panel-33"> <div class="panel-33">
<h2>SIGNAL</h2> <h2 class="signal-heading">SIGNAL</h2>
<div class="text-small text-gray highest-signal-container"> <div class="text-small text-gray highest-signal-container">
<i class="fa-solid fa-arrow-up"></i> <i class="fa-solid fa-arrow-up"></i>
<span id="data-signal-highest"></span> <span id="data-signal-highest"></span>
@@ -120,7 +120,7 @@
</div> </div>
<% if (antennas.enabled == true) { %> <% if (antennas.enabled == true) { %>
<div class="panel-50 no-bg h-100 m-0 dropdown" id="data-ant" style="margin-right: 25px;width:125px;"> <div class="panel-50 no-bg h-100 m-0 dropdown" id="data-ant" style="margin-right: 25px;">
<input type="text" placeholder="Ant A" readonly> <input type="text" placeholder="Ant A" readonly>
<ul class="options"> <ul class="options">
<% if(antennas.ant1.enabled == true) { %><li data-value="0" class="option"><%= antennas.ant1.name %></li><% } %> <% if(antennas.ant1.enabled == true) { %><li data-value="0" class="option"><%= antennas.ant1.name %></li><% } %>
@@ -249,8 +249,12 @@
<div class="flex-container flex-phone flex-phone-column"> <div class="flex-container flex-phone flex-phone-column">
<div class="panel-75 hover-brighten" id="rt-container" style="height: 100px;"> <div class="panel-75 hover-brighten" id="rt-container" style="height: 100px;">
<h2 style="margin-top: 4px;">RADIOTEXT</h2> <h2 style="margin-top: 4px;">RADIOTEXT</h2>
<div id="data-rt0"></div> <div id="data-rt0">
<div id="data-rt1"></div> <span></span>
</div>
<div id="data-rt1">
<span></span>
</div>
<hr class="hide-desktop"> <hr class="hide-desktop">
</div> </div>
@@ -297,7 +301,10 @@
<div style="display:inline-block"> <div style="display:inline-block">
<span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span> <span style="margin-left: 20px;display: block;margin-top: 2px;" class="data-flag"></span>
</div> </div>
<span style="margin-left: 20px;" class="data-st"></span> <span class="pointer stereo-container" style="position: relative;">
<span style="margin-left: 20px;" class="data-st">ST</span>
<span class="overlay tooltip" data-tooltip="Stereo / Mono toggle. <br><strong>Click to toggle."></span>
</span>
<span style="margin-left: 15px;" class="data-ms">MS</span> <span style="margin-left: 15px;" class="data-ms">MS</span>
</h3> </h3>
</div> </div>

View File

@@ -74,15 +74,15 @@ $(document).ready(function() {
if (savedNickname) { if (savedNickname) {
chatNicknameInput.val(savedNickname); chatNicknameInput.val(savedNickname);
} }
});
function sendMessage() { function sendMessage() {
const nickname = chatNicknameInput.val().trim() || 'Anonymous user'; const nickname = savedNickname || 'Anonymous user';
const message = chatSendInput.val().trim(); const message = chatSendInput.val().trim();
if (message) { if (message) {
const messageData = { nickname, message }; const messageData = { nickname, message };
chatSocket.send(JSON.stringify(messageData)); chatSocket.send(JSON.stringify(messageData));
chatSendInput.val(''); chatSendInput.val('');
}
} }
} });

View File

@@ -1,9 +1,9 @@
var currentDate = new Date('March 25, 2024 23:00:00'); var currentDate = new Date('March 28, 2024 22:00:00');
var day = currentDate.getDate(); var day = currentDate.getDate();
var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1 var month = currentDate.getMonth() + 1; // Months are zero-indexed, so add 1
var year = currentDate.getFullYear(); var year = currentDate.getFullYear();
var formattedDate = day + '/' + month + '/' + year; var formattedDate = day + '/' + month + '/' + year;
var currentVersion = 'v1.1.8 [' + formattedDate + ']'; var currentVersion = 'v1.1.9 [' + formattedDate + ']';
getInitialSettings(); getInitialSettings();

View File

@@ -154,7 +154,7 @@ $(document).ready(function () {
$(rtContainer).on("click", copyRt); $(rtContainer).on("click", copyRt);
$(txContainer).on("click", copyTx); $(txContainer).on("click", copyTx);
$(piCodeContainer).on("click", findOnMaps); $(piCodeContainer).on("click", findOnMaps);
$(document).on("click", "#stereo-container", toggleForcedStereo); $(document).on("click", ".stereo-container", toggleForcedStereo);
$(freqContainer).on("click", function () { $(freqContainer).on("click", function () {
textInput.focus(); textInput.focus();
}); });
@@ -476,9 +476,7 @@ function tuneDown() {
} }
function tuneTo(freq) { function tuneTo(freq) {
if (socket.readyState === WebSocket.OPEN) {
socket.send("T" + ((freq).toFixed(1) * 1000)); socket.send("T" + ((freq).toFixed(1) * 1000));
}
} }
async function copyPs() { async function copyPs() {
@@ -513,8 +511,8 @@ async function copyTx() {
} }
async function copyRt() { async function copyRt() {
var rt0 = $('#data-rt0').text(); var rt0 = $('#data-rt0 span').text();
var rt1 = $('#data-rt1').text(); var rt1 = $('#data-rt1 span').text();
try { try {
await copyToClipboard("[0] RT: " + rt0 + "\n[1] RT: " + rt1); await copyToClipboard("[0] RT: " + rt0 + "\n[1] RT: " + rt1);
@@ -578,11 +576,13 @@ function updateSignalUnits(parsedData, averageSignal) {
switch (signalUnit) { switch (signalUnit) {
case 'dbuv': case 'dbuv':
signalValue = currentSignal - 11.25; signalValue = currentSignal - 11.25;
highestSignal = highestSignal - 11.25;
signalText.text('dBµV'); signalText.text('dBµV');
break; break;
case 'dbm': case 'dbm':
signalValue = currentSignal - 120; signalValue = currentSignal - 120;
highestSignal = highestSignal - 120;
signalText.text('dBm'); signalText.text('dBm');
break; break;
@@ -606,8 +606,8 @@ function updateDataElements(parsedData) {
const $dataPi = $('#data-pi'); const $dataPi = $('#data-pi');
const $dataPs = $('#data-ps'); const $dataPs = $('#data-ps');
const $dataSt = $('.data-st'); const $dataSt = $('.data-st');
const $dataRt0 = $('#data-rt0'); const $dataRt0 = $('#data-rt0 span');
const $dataRt1 = $('#data-rt1'); const $dataRt1 = $('#data-rt1 span');
const $dataAntInput = $('#data-ant input'); const $dataAntInput = $('#data-ant input');
const $dataBwInput = $('#data-bw input'); const $dataBwInput = $('#data-bw input');
const $dataStationContainer = $('#data-station-container'); const $dataStationContainer = $('#data-station-container');

View File

@@ -259,7 +259,7 @@
<div class="panel-100 no-bg"> <div class="panel-100 no-bg">
<h3>Themes</h3> <h3>Themes</h3>
<div class="form-group"> <div class="form-group">
<label for="themes"><i class="fa-solid fa-palette"></i>Default server theme:</label> <label for="themes"><i class="fa-solid fa-palette"></i> Default server theme:</label>
<div class="dropdown" id="server-theme-selector" style="margin-right: 0;"> <div class="dropdown" id="server-theme-selector" style="margin-right: 0;">
<input type="text" placeholder="Default" id="selected-theme" readonly> <input type="text" placeholder="Default" id="selected-theme" readonly>
<ul class="options"> <ul class="options">
@@ -509,6 +509,7 @@
</div> </div>
<% } %> <% } %>
</div> </div>
<script src="js/init.js"></script>
<script src="js/settings.js"></script> <script src="js/settings.js"></script>
<script src="js/dropdown.js"></script> <script src="js/dropdown.js"></script>
<script src="js/setup.js"></script> <script src="js/setup.js"></script>