mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-07-30 16:59:15 +02:00
move some stuff around, change some things slightly
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@ const LOG_FILE = process.argv.includes('--config') && process.argv[process.argv.
|
|||||||
? `serverlog_${process.argv[process.argv.indexOf('--config') + 1]}.txt`
|
? `serverlog_${process.argv[process.argv.indexOf('--config') + 1]}.txt`
|
||||||
: 'serverlog.txt';
|
: 'serverlog.txt';
|
||||||
const ANSI_ESCAPE_CODE_PATTERN = /\x1b\[[0-9;]*m/g;
|
const ANSI_ESCAPE_CODE_PATTERN = /\x1b\[[0-9;]*m/g;
|
||||||
const MAX_LOG_LINES = 5000;
|
const MAX_LOG_LINES = 3500;
|
||||||
const FLUSH_INTERVAL = 60000;
|
const FLUSH_INTERVAL = 60000;
|
||||||
const logs = [];
|
const logs = [];
|
||||||
const maxConsoleLogLines = 250;
|
const maxConsoleLogLines = 250;
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ const filterMappings = {
|
|||||||
'G00': { eq: 0, ims: 0 }
|
'G00': { eq: 0, ims: 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var legacyRdsPiBuffer = null;
|
var legacyRdsPiBuffer = null;
|
||||||
var lastUpdateTime = Date.now();
|
var lastUpdateTime = Date.now();
|
||||||
const initialData = { ...dataToSend };
|
const initialData = { ...dataToSend };
|
||||||
|
|||||||
+1
-1
@@ -466,7 +466,7 @@ router.get('/tunnelservers', async (req, res) => {
|
|||||||
{ value: "eu", host: "eu.fmtuner.org", label: "Europe" },
|
{ value: "eu", host: "eu.fmtuner.org", label: "Europe" },
|
||||||
{ value: "us", host: "us.fmtuner.org", label: "Americas" },
|
{ value: "us", host: "us.fmtuner.org", label: "Americas" },
|
||||||
{ value: "sg", host: "sg.fmtuner.org", label: "Asia & Oceania" },
|
{ value: "sg", host: "sg.fmtuner.org", label: "Asia & Oceania" },
|
||||||
{ value: "pldx", host: "pldx.fmtuner.org", label: "Poland (k201)" },
|
{ value: "pldx", host: "pldx.duckdns.org", label: "Poland (k201)" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
|
|||||||
+1
-2
@@ -23,8 +23,7 @@ function send(request) {
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success && data.token) {
|
if (data.success && data.token) {
|
||||||
if (!serverConfig.identification.token)
|
if (!serverConfig.identification.token) {
|
||||||
{
|
|
||||||
logInfo("Registered to FM-DX Server Map successfully.");
|
logInfo("Registered to FM-DX Server Map successfully.");
|
||||||
serverConfig.identification.token = data.token;
|
serverConfig.identification.token = data.token;
|
||||||
configSave();
|
configSave();
|
||||||
|
|||||||
+1
-12
@@ -292,17 +292,6 @@ function kickClient(ipAddress) {
|
|||||||
} else consoleCmd.logInfo(`Kicking client ${ipAddress} failed. No suitable client found.`);
|
} else consoleCmd.logInfo(`Kicking client ${ipAddress} failed. No suitable client found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIPv6Support(callback) {
|
|
||||||
const server = net.createServer();
|
|
||||||
|
|
||||||
server.listen(0, '::1', () => {
|
|
||||||
server.close(() => callback(true));
|
|
||||||
}).on('error', (error) => {
|
|
||||||
if (error.code === 'EADDRNOTAVAIL') callback(false);
|
|
||||||
else callback(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkLatency(host, port = 80, timeout = 2000) {
|
function checkLatency(host, port = 80, timeout = 2000) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
@@ -459,7 +448,7 @@ function getIpAddress(request) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
authenticateWithXdrd, parseMarkdown, handleConnect,
|
authenticateWithXdrd, parseMarkdown, handleConnect,
|
||||||
removeMarkdown, formatUptime, resolveDataBuffer,
|
removeMarkdown, formatUptime, resolveDataBuffer,
|
||||||
kickClient, checkIPv6Support, checkLatency,
|
kickClient, checkLatency,
|
||||||
antispamProtection, escapeHtml, findServerFiles,
|
antispamProtection, escapeHtml, findServerFiles,
|
||||||
startPluginsWithDelay, getIpAddress
|
startPluginsWithDelay, getIpAddress
|
||||||
}
|
}
|
||||||
+34
-38
@@ -10,7 +10,7 @@ const WebSocket = require('ws');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
const { SerialPort } = require('serialport');
|
const { SerialPort } = require('serialport');
|
||||||
const tunnel_connect = require('./tunnel');
|
const tunnel = require('./tunnel');
|
||||||
const { createChatServer } = require('./chat');
|
const { createChatServer } = require('./chat');
|
||||||
const figlet = require('figlet');
|
const figlet = require('figlet');
|
||||||
|
|
||||||
@@ -71,9 +71,9 @@ app.use(sessionMiddleware);
|
|||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
createChatServer(storage);
|
createChatServer(storage);
|
||||||
|
|
||||||
|
tunnel.download();
|
||||||
connectToXdrd();
|
connectToXdrd();
|
||||||
connectToSerial();
|
connectToSerial();
|
||||||
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)
|
||||||
dataHandler.state.isSerialportRetrying = false;
|
dataHandler.state.isSerialportRetrying = false;
|
||||||
@@ -285,7 +285,7 @@ app.use('/', endpoints);
|
|||||||
const tunerLockTracker = new WeakMap();
|
const tunerLockTracker = new WeakMap();
|
||||||
const ipConnectionCounts = new Map(); // Per-IP limit variables
|
const ipConnectionCounts = new Map(); // Per-IP limit variables
|
||||||
const ipLogTimestamps = new Map();
|
const ipLogTimestamps = new Map();
|
||||||
const MAX_CONNECTIONS_PER_IP = 5;
|
const MAX_CONNECTIONS_PER_IP = 4;
|
||||||
const IP_LOG_INTERVAL_MS = 60000;
|
const IP_LOG_INTERVAL_MS = 60000;
|
||||||
// Remove old per-IP limit addresses
|
// Remove old per-IP limit addresses
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
@@ -502,20 +502,23 @@ pluginsWss.on('connection', (ws, request) => {
|
|||||||
// Anti-spam
|
// Anti-spam
|
||||||
helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '10', 'data_plugins');
|
helpers.antispamProtection(message, clientIp, ws, userCommands, lastWarn, userCommandHistory, '10', 'data_plugins');
|
||||||
|
|
||||||
let messageData;
|
try {
|
||||||
|
let messageData = JSON.parse(message); // Attempt to parse the JSON
|
||||||
|
|
||||||
try { // JS Requires the try statement to have braces, unlike the if statement. This extends the huge list of proofs that this is a fucking toy language
|
if (messageData.type === "GPS" && messageData.value) {
|
||||||
messageData = JSON.parse(message); // Attempt to parse the JSON
|
const gpsData = messageData.value;
|
||||||
} catch (error) {
|
const { status, time, lat, lon, alt, mode } = gpsData;
|
||||||
// console.error("Failed to parse message:", error); // Log the error
|
|
||||||
return; // Exit if parsing fails
|
|
||||||
}
|
|
||||||
|
|
||||||
const modifiedMessage = JSON.stringify(messageData);
|
if (status === "active") {
|
||||||
|
Latitude = parseFloat(lat);
|
||||||
|
Longitude = parseFloat(lon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
// Broadcast the message to all other clients
|
// Broadcast the message to all other clients
|
||||||
pluginsWss.clients.forEach(client => {
|
pluginsWss.clients.forEach(client => {
|
||||||
if (client.readyState === WebSocket.OPEN) client.send(modifiedMessage); // Send the message to all clients
|
if (client.readyState === WebSocket.OPEN) client.send(message); // Send the message to all clients
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -524,7 +527,6 @@ pluginsWss.on('connection', (ws, request) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Websocket register for /text, /audio and /chat paths
|
|
||||||
httpServer.on('upgrade', (request, socket, head) => {
|
httpServer.on('upgrade', (request, socket, head) => {
|
||||||
const clientIp = helpers.getIpAddress(request);
|
const clientIp = helpers.getIpAddress(request);
|
||||||
if (serverConfig.webserver.banlist?.includes(clientIp)) {
|
if (serverConfig.webserver.banlist?.includes(clientIp)) {
|
||||||
@@ -543,30 +545,24 @@ httpServer.on('upgrade', (request, socket, head) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, '../web'))); // Serve the entire web folder to the user
|
app.use(express.static(path.join(__dirname, '../web'))); // Serve the entire web folder to the user
|
||||||
fmdxList.update();
|
|
||||||
|
|
||||||
helpers.checkIPv6Support((isIPv6Supported) => {
|
|
||||||
const ipv4Address = serverConfig.webserver.webserverIp === '0.0.0.0' ? 'localhost' : serverConfig.webserver.webserverIp;
|
|
||||||
const ipv6Address = '::'; // This will bind to all available IPv6 interfaces
|
|
||||||
const port = serverConfig.webserver.webserverPort;
|
|
||||||
|
|
||||||
const logServerStart = (address, isIPv6) => {
|
|
||||||
const formattedAddress = isIPv6 ? `[${address}]` : address;
|
|
||||||
logInfo(`Web server has started on address \x1b[34mhttp://${formattedAddress}:${port}\x1b[0m.`);
|
|
||||||
};
|
|
||||||
|
|
||||||
const startServer = (address, isIPv6) => {
|
|
||||||
httpServer.listen(port, address, () => {
|
|
||||||
if (!isIPv6 && !configExists()) logInfo(`Open your browser and proceed to \x1b[34mhttp://${address}:${port}\x1b[0m to continue with setup.`);
|
|
||||||
else logServerStart(address, isIPv6);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isIPv6Supported) {
|
|
||||||
startServer(ipv4Address, false); // Start on IPv4
|
|
||||||
startServer(ipv6Address, true); // Start on IPv6
|
|
||||||
} else startServer(ipv4Address, false); // Start only on IPv4
|
|
||||||
});
|
|
||||||
|
|
||||||
pluginsApi.registerServerContext({ wss, pluginsWss, httpServer, serverConfig });
|
pluginsApi.registerServerContext({ wss, pluginsWss, httpServer, serverConfig });
|
||||||
|
|
||||||
|
const ipv4Address = serverConfig.webserver.webserverIp === '0.0.0.0' ? 'localhost' : serverConfig.webserver.webserverIp;
|
||||||
|
const port = serverConfig.webserver.webserverPort;
|
||||||
|
|
||||||
|
const logServerStart = (address) => {
|
||||||
|
logInfo(`Web server has started on address \x1b[34mhttp://${address}:${port}\x1b[0m.`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const startServer = (address) => {
|
||||||
|
httpServer.listen(port, address, () => {
|
||||||
|
if (!configExists()) logInfo(`Open your browser and proceed to \x1b[34mhttp://${address}:${port}\x1b[0m to continue with setup.`);
|
||||||
|
else logServerStart(address);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
startServer(ipv4Address);
|
||||||
|
tunnel.connect();
|
||||||
|
fmdxList.update();
|
||||||
module.exports = { wss, pluginsWss, httpServer, serverConfig };
|
module.exports = { wss, pluginsWss, httpServer, serverConfig };
|
||||||
@@ -20,7 +20,7 @@ let serverConfig = {
|
|||||||
banlist: [],
|
banlist: [],
|
||||||
chatEnabled: true,
|
chatEnabled: true,
|
||||||
tuningLimit: false,
|
tuningLimit: false,
|
||||||
tuningLowerLimit: "100",
|
tuningLowerLimit: "65",
|
||||||
tuningUpperLimit: "108",
|
tuningUpperLimit: "108",
|
||||||
presets: [
|
presets: [
|
||||||
"87.5",
|
"87.5",
|
||||||
|
|||||||
+10
-2
@@ -12,7 +12,7 @@ const readline = require('readline');
|
|||||||
|
|
||||||
const fileExists = path => new Promise(resolve => fs.access(path, fs.constants.F_OK).then(() => resolve(true)).catch(() => resolve(false)));
|
const fileExists = path => new Promise(resolve => fs.access(path, fs.constants.F_OK).then(() => resolve(true)).catch(() => resolve(false)));
|
||||||
|
|
||||||
async function connect() {
|
async function download() {
|
||||||
if (serverConfig.tunnel?.enabled === true) {
|
if (serverConfig.tunnel?.enabled === true) {
|
||||||
const librariesDir = path.resolve(__dirname, '../libraries');
|
const librariesDir = path.resolve(__dirname, '../libraries');
|
||||||
if (!await fileExists(librariesDir)) await fs.mkdir(librariesDir);
|
if (!await fileExists(librariesDir)) await fs.mkdir(librariesDir);
|
||||||
@@ -33,6 +33,14 @@ async function connect() {
|
|||||||
logInfo('Downloading of frpc is completed.')
|
logInfo('Downloading of frpc is completed.')
|
||||||
if (os.platform() === 'linux' || os.platform() === 'darwin') await fs.chmod(frpcPath, 0o770);
|
if (os.platform() === 'linux' || os.platform() === 'darwin') await fs.chmod(frpcPath, 0o770);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function connect() {
|
||||||
|
if (serverConfig.tunnel?.enabled === true) {
|
||||||
|
const librariesDir = path.resolve(__dirname, '../libraries');
|
||||||
|
const frpcPath = path.resolve(librariesDir, 'frpc' + (os.platform() === 'win32' ? '.exe' : ''));
|
||||||
|
|
||||||
const cfg = ejs.render(frpcConfigTemplate, {
|
const cfg = ejs.render(frpcConfigTemplate, {
|
||||||
cfg: serverConfig.tunnel,
|
cfg: serverConfig.tunnel,
|
||||||
host: serverConfig.tunnel.community.enabled ? serverConfig.tunnel.community.host : ((serverConfig.tunnel.region == "pldx") ? "pldx.duckdns.org" : (serverConfig.tunnel.region + ".fmtuner.org")),
|
host: serverConfig.tunnel.community.enabled ? serverConfig.tunnel.community.host : ((serverConfig.tunnel.region == "pldx") ? "pldx.duckdns.org" : (serverConfig.tunnel.region + ".fmtuner.org")),
|
||||||
@@ -92,4 +100,4 @@ httpPassword = "<%= cfg.httpPassword %>"
|
|||||||
<% } %>
|
<% } %>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
module.exports = connect;
|
module.exports = { connect, download};
|
||||||
+1
-31
@@ -42,35 +42,6 @@ if (typeof algorithms[algoSetting] !== 'undefined') {
|
|||||||
// Build the TX database.
|
// Build the TX database.
|
||||||
setTimeout(buildTxDatabase, 3000);
|
setTimeout(buildTxDatabase, 3000);
|
||||||
|
|
||||||
if (serverConfig.identification.gpsMode) {
|
|
||||||
// 5-second delay before activation of GPS lat/lon websocket
|
|
||||||
setTimeout(() => {
|
|
||||||
const websocket = new WebSocket(externalWsUrl);
|
|
||||||
consoleCmd.logInfo('Set up GPS websocket for lat/lon');
|
|
||||||
// Event listener to receive data
|
|
||||||
websocket.on('message', (data) => {
|
|
||||||
try {
|
|
||||||
// Parse the received data
|
|
||||||
const parsedData = JSON.parse(data);
|
|
||||||
|
|
||||||
// Check if the dataset is of type GPS
|
|
||||||
if (parsedData.type === "GPS" && parsedData.value) {
|
|
||||||
const gpsData = parsedData.value;
|
|
||||||
const { status, time, lat, lon, alt, mode } = gpsData;
|
|
||||||
|
|
||||||
if (status === "active") {
|
|
||||||
Latitude = parseFloat(lat);
|
|
||||||
Longitude = parseFloat(lon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
consoleCmd.logError("Error processing WebSocket data:", error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to build local TX database from FMDX Maps endpoint.
|
// Function to build local TX database from FMDX Maps endpoint.
|
||||||
async function buildTxDatabase() {
|
async function buildTxDatabase() {
|
||||||
if (Latitude.length > 0 && Longitude.length > 0) {
|
if (Latitude.length > 0 && Longitude.length > 0) {
|
||||||
@@ -362,12 +333,11 @@ function checkEs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function haversine(lat1, lon1, lat2, lon2) {
|
function haversine(lat1, lon1, lat2, lon2) {
|
||||||
const R = 6371;
|
|
||||||
const dLat = deg2rad(lat2 - lat1);
|
const dLat = deg2rad(lat2 - lat1);
|
||||||
const dLon = deg2rad(lon2 - lon1);
|
const dLon = deg2rad(lon2 - lon1);
|
||||||
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
||||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||||
const distance = R * c;
|
const distance = 6371 * c;
|
||||||
|
|
||||||
const y = Math.sin(dLon) * Math.cos(deg2rad(lat2));
|
const y = Math.sin(dLon) * Math.cos(deg2rad(lat2));
|
||||||
const x = Math.cos(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) - Math.sin(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(dLon);
|
const x = Math.cos(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) - Math.sin(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(dLon);
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@
|
|||||||
<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>
|
<p>
|
||||||
The service has rejected you.<br>
|
Service refused..<br>
|
||||||
Please try again later.</p>
|
Please try again later.</p>
|
||||||
|
|
||||||
<% if (reason) { %>
|
<% if (reason) { %>
|
||||||
|
|||||||
@@ -247,7 +247,6 @@
|
|||||||
<div class="flex-container contains-dropdown">
|
<div class="flex-container contains-dropdown">
|
||||||
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
|
<div class="panel-50 p-bottom-20" style="padding-left: 20px; padding-right: 20px;">
|
||||||
<h3>Connection</h3>
|
<h3>Connection</h3>
|
||||||
<p class="text-gray">Leave the IP at 0.0.0.0 unless you explicitly know you have to change it.<br>Don't enter your public IP here.</p>
|
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '0.0.0.0', label: 'Webserver IP', id: 'webserver-webserverIp'}) %>
|
<%- include('_components', {component: 'text', cssClass: 'w-150 br-15', placeholder: '0.0.0.0', label: 'Webserver IP', id: 'webserver-webserverIp'}) %>
|
||||||
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '8080', label: 'Webserver port', id: 'webserver-webserverPort'}) %><br>
|
<%- include('_components', {component: 'text', cssClass: 'w-100 br-15', placeholder: '8080', label: 'Webserver port', id: 'webserver-webserverPort'}) %><br>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-1
@@ -615,7 +615,7 @@ let dataTimeoutPrevious = null;
|
|||||||
let connectionLost = false;
|
let connectionLost = false;
|
||||||
let requiresAudioStreamRestart = false;
|
let requiresAudioStreamRestart = false;
|
||||||
|
|
||||||
const TIMEOUT_DURATION = 5000; // 5 seconds timeout for lost connection
|
const TIMEOUT_DURATION = 3500; // 5 seconds timeout for lost connection
|
||||||
|
|
||||||
const resetDataTimeout = () => {
|
const resetDataTimeout = () => {
|
||||||
clearTimeout(dataTimeout);
|
clearTimeout(dataTimeout);
|
||||||
|
|||||||
Reference in New Issue
Block a user