Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 111 additions & 14 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ let currentCAT=null;
var WServer;
let wsServer;
let wsClients = new Set();
let isShuttingDown = false;
let activeConnections = new Set(); // Track active TCP connections
let activeHttpRequests = new Set(); // Track active HTTP requests for cancellation

const DemoAdif='<call:5>DJ7NT <gridsquare:4>JO30 <mode:3>FT8 <rst_sent:3>-15 <rst_rcvd:2>33 <qso_date:8>20240110 <time_on:6>051855 <qso_date_off:8>20240110 <time_off:6>051855 <band:3>40m <freq:8>7.155783 <station_callsign:5>TE1ST <my_gridsquare:6>JO30OO <eor>';

Expand Down Expand Up @@ -112,7 +115,8 @@ ipcMain.on("setCAT", async (event,arg) => {
});

ipcMain.on("quit", async (event,arg) => {
app.isQuitting = true;
console.log('Quit requested from renderer');
shutdownApplication();
app.quit();
event.returnValue=true;
});
Expand All @@ -123,6 +127,84 @@ ipcMain.on("radio_status_update", async (event,arg) => {
event.returnValue=true;
});

function cleanupConnections() {
console.log('Cleaning up active TCP connections...');

// Close all tracked TCP connections
activeConnections.forEach(connection => {
try {
if (connection && !connection.destroyed) {
connection.destroy();
console.log('Closed TCP connection');
}
} catch (error) {
console.error('Error closing TCP connection:', error);
}
});

// Clear the connections set
activeConnections.clear();
console.log('All TCP connections cleaned up');

// Abort all in-flight HTTP requests
activeHttpRequests.forEach(request => {
try {
request.abort();
console.log('Aborted HTTP request');
} catch (error) {
console.error('Error aborting HTTP request:', error);
}
});

// Clear the HTTP requests set
activeHttpRequests.clear();
console.log('All HTTP requests aborted');
}

function shutdownApplication() {
if (isShuttingDown) {
console.log('Shutdown already in progress, ignoring duplicate request');
return;
}

isShuttingDown = true;
console.log('Initiating application shutdown...');

try {
// Signal renderer to clear timers and connections
if (s_mainWindow && !s_mainWindow.isDestroyed()) {
console.log('Sending cleanup signal to renderer...');
s_mainWindow.webContents.send('cleanup');
}

// Clean up TCP connections
cleanupConnections();

// Close all servers
if (WServer) {
console.log('Closing UDP server...');
WServer.close();
}
if (httpServer) {
console.log('Closing HTTP server...');
httpServer.close();
}
if (wsServer) {
console.log('Closing WebSocket server and clients...');
// Close all WebSocket client connections
wsClients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.close();
}
});
wsClients.clear();
wsServer.close();
}
} catch (error) {
console.error('Error during server shutdown:', error);
}
}

function show_noti(arg) {
if (Notification.isSupported()) {
try {
Expand Down Expand Up @@ -161,19 +243,13 @@ ipcMain.on("test", async (event,arg) => {
});

app.on('before-quit', () => {
console.log('Shutting down servers...');
if (WServer) {
WServer.close();
}
if (httpServer) {
httpServer.close();
}
console.log('before-quit event triggered');
shutdownApplication();
});

process.on('SIGINT', () => {
console.log('SIGINT received, closing servers...');
if (WServer) WServer.close();
if (httpServer) httpServer.close();
console.log('SIGINT received, initiating shutdown...');
shutdownApplication();
process.exit(0);
});

Expand Down Expand Up @@ -205,8 +281,12 @@ if (!gotTheLock) {
}

app.on('window-all-closed', function () {
console.log('All windows closed, initiating shutdown...');
if (!isShuttingDown) {
shutdownApplication();
}
if (process.platform !== 'darwin') app.quit();
app.quit();
else app.quit();
})

function normalizeTxPwr(adifdata) {
Expand Down Expand Up @@ -306,6 +386,9 @@ function send2wavelog(o_cfg,adif, dryrun = false) {
const body = [];
res.on('data', (chunk) => body.push(chunk));
res.on('end', () => {
// Remove request from tracking when completed
activeHttpRequests.delete(req);

let resString = Buffer.concat(body).toString();
if (rej) {
if (resString.indexOf('html>')>0) {
Expand All @@ -321,19 +404,26 @@ function send2wavelog(o_cfg,adif, dryrun = false) {
})

req.on('error', (err) => {
// Remove request from tracking on error
activeHttpRequests.delete(req);
rej=true;
req.destroy();
result.resString='{"status":"failed","reason":"internet problem"}';
reject(result);
})

req.on('timeout', (err) => {
// Remove request from tracking on timeout
activeHttpRequests.delete(req);
rej=true;
req.destroy();
result.resString='{"status":"failed","reason":"timeout"}';
reject(result);
})

// Track the HTTP request for cleanup
activeHttpRequests.add(req);

req.write(postData);
req.end();
});
Expand Down Expand Up @@ -615,8 +705,15 @@ async function settrx(qrg, mode = '') {
client.end();
});

client.on("error", (err) => {});
client.on("close", () => {});
// Track the connection for cleanup
activeConnections.add(client);

client.on("error", (err) => {
activeConnections.delete(client);
});
client.on("close", () => {
activeConnections.delete(client);
});
}

// Broadcast frequency/mode change to WebSocket clients
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Gateway for connecting WSJT-* and FLRig to Wavelog",
"keywords": [],
"main": "./main.js",
"version": "1.1.11",
"version": "1.1.12",
"author": "DJ7NT",
"scripts": {
"start": "electron-forge start",
Expand Down
85 changes: 82 additions & 3 deletions renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
let cfg={};
let active_cfg=0;
let trxpoll=undefined;
let utcTimeInterval=undefined;
let activeConnections = new Set(); // Track active TCP connections in renderer
let activeAbortControllers = new Set(); // Track active HTTP requests for cancellation

const {ipcRenderer} = require('electron')
const net = require('net');
Expand Down Expand Up @@ -81,6 +84,7 @@ $(document).ready(function() {
});

bt_quit.addEventListener('click', () => {
cleanup(); // Clear all timers and connections before quit
const x=ipcRenderer.sendSync("quit", '');
});

Expand Down Expand Up @@ -115,7 +119,7 @@ $(document).ready(function() {
getStations();
});

setInterval(updateUtcTime, 1000);
utcTimeInterval = setInterval(updateUtcTime, 1000);
window.onload = updateUtcTime;

$("#config-tab").on("click",function() {
Expand All @@ -139,6 +143,11 @@ $(document).ready(function() {
ipcRenderer.send('get_info_result', result);
});

// Handle cleanup request from main process
ipcRenderer.on('cleanup', () => {
cleanup();
});

// Dropdown change handler
$('#radio_type').change(function() {
updateRadioFields();
Expand Down Expand Up @@ -260,6 +269,9 @@ async function get_trx() {

async function getInfo(which) {
if (cfg.profiles[active_cfg].flrig_ena){
const abortController = new AbortController();
activeAbortControllers.add(abortController);

try {
const response = await fetch(
"http://"+$("#radio_host").val()+':'+$("#radio_port").val(), {
Expand All @@ -270,8 +282,10 @@ async function getInfo(which) {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: '<?xml version="1.0"?><methodCall><methodName>'+which+'</methodName></methodCall>',
signal: abortController.signal
}
);

const data = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(data, "application/xml");
Expand All @@ -292,6 +306,9 @@ async function getInfo(which) {
}
} catch (e) {
return '';
} finally {
// Always clean up abort controller when done
activeAbortControllers.delete(abortController);
}
}
if (cfg.profiles[active_cfg].hamlib_ena) {
Expand All @@ -303,6 +320,10 @@ async function getInfo(which) {
return new Promise((resolve, reject) => {
if (commands[which]) {
const client = net.createConnection({ host, port }, () => client.write(commands[which]));

// Track the connection for cleanup
activeConnections.add(client);

client.on('data', (data) => {
data = data.toString()
if(data.startsWith("RPRT")){
Expand All @@ -312,8 +333,13 @@ async function getInfo(which) {
}
client.end();
});
client.on('error', (err) => reject());
client.on("close", () => {});
client.on('error', (err) => {
activeConnections.delete(client);
reject();
});
client.on("close", () => {
activeConnections.delete(client);
});
} else {
resolve(undefined);
}
Expand Down Expand Up @@ -396,6 +422,59 @@ async function informWavelog(CAT) {
return x;
}

function cleanupConnections() {
console.log('Cleaning up renderer TCP connections...');

// Close all tracked TCP connections
activeConnections.forEach(connection => {
try {
if (connection && !connection.destroyed) {
connection.destroy();
console.log('Closed renderer TCP connection');
}
} catch (error) {
console.error('Error closing renderer TCP connection:', error);
}
});

// Clear the connections set
activeConnections.clear();
console.log('All renderer TCP connections cleaned up');

// Abort all in-flight HTTP requests
activeAbortControllers.forEach(controller => {
try {
controller.abort();
console.log('Aborted HTTP request');
} catch (error) {
console.error('Error aborting HTTP request:', error);
}
});

// Clear the abort controllers set
activeAbortControllers.clear();
console.log('All HTTP requests aborted');
}

function cleanup() {
// Clear radio polling timeout
if (trxpoll) {
clearTimeout(trxpoll);
trxpoll = undefined;
console.log('Cleared radio polling timeout');
}

// Clear UTC time update interval
if (utcTimeInterval) {
clearInterval(utcTimeInterval);
utcTimeInterval = undefined;
console.log('Cleared UTC time update interval');
}

// Clean up TCP connections
cleanupConnections();
}

function updateUtcTime() {
const now = new Date();

Expand Down