mirror of
https://github.com/smittix/intercept.git
synced 2026-04-25 23:29:59 -07:00
perf: add destroy() lifecycle to all mode modules to prevent resource leaks
Mode modules were leaking EventSource connections, setInterval timers, and setTimeout timers on every mode switch, causing progressive browser sluggishness. Added destroy() to 8 modules missing it (meshtastic, bluetooth, wifi, bt_locate, sstv, sstv-general, websdr, spy-stations) and centralized all destroy calls in switchMode() via a moduleDestroyMap that cleanly tears down only the previous mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,12 +12,12 @@ const SSTV = (function() {
|
||||
let progress = 0;
|
||||
let issMap = null;
|
||||
let issMarker = null;
|
||||
let issTrackLine = null;
|
||||
let issPosition = null;
|
||||
let issUpdateInterval = null;
|
||||
let countdownInterval = null;
|
||||
let nextPassData = null;
|
||||
let pendingMapInvalidate = false;
|
||||
let issTrackLine = null;
|
||||
let issPosition = null;
|
||||
let issUpdateInterval = null;
|
||||
let countdownInterval = null;
|
||||
let nextPassData = null;
|
||||
let pendingMapInvalidate = false;
|
||||
|
||||
// ISS frequency
|
||||
const ISS_FREQ = 145.800;
|
||||
@@ -38,31 +38,31 @@ const SSTV = (function() {
|
||||
/**
|
||||
* Initialize the SSTV mode
|
||||
*/
|
||||
function init() {
|
||||
checkStatus();
|
||||
loadImages();
|
||||
loadLocationInputs();
|
||||
loadIssSchedule();
|
||||
initMap();
|
||||
startIssTracking();
|
||||
startCountdown();
|
||||
// Ensure Leaflet recomputes dimensions after the SSTV pane becomes visible.
|
||||
setTimeout(() => invalidateMap(), 80);
|
||||
setTimeout(() => invalidateMap(), 260);
|
||||
}
|
||||
|
||||
function isMapContainerVisible() {
|
||||
if (!issMap || typeof issMap.getContainer !== 'function') return false;
|
||||
const container = issMap.getContainer();
|
||||
if (!container) return false;
|
||||
if (container.offsetWidth <= 0 || container.offsetHeight <= 0) return false;
|
||||
if (container.style && container.style.display === 'none') return false;
|
||||
if (typeof window.getComputedStyle === 'function') {
|
||||
const style = window.getComputedStyle(container);
|
||||
if (style.display === 'none' || style.visibility === 'hidden') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function init() {
|
||||
checkStatus();
|
||||
loadImages();
|
||||
loadLocationInputs();
|
||||
loadIssSchedule();
|
||||
initMap();
|
||||
startIssTracking();
|
||||
startCountdown();
|
||||
// Ensure Leaflet recomputes dimensions after the SSTV pane becomes visible.
|
||||
setTimeout(() => invalidateMap(), 80);
|
||||
setTimeout(() => invalidateMap(), 260);
|
||||
}
|
||||
|
||||
function isMapContainerVisible() {
|
||||
if (!issMap || typeof issMap.getContainer !== 'function') return false;
|
||||
const container = issMap.getContainer();
|
||||
if (!container) return false;
|
||||
if (container.offsetWidth <= 0 || container.offsetHeight <= 0) return false;
|
||||
if (container.style && container.style.display === 'none') return false;
|
||||
if (typeof window.getComputedStyle === 'function') {
|
||||
const style = window.getComputedStyle(container);
|
||||
if (style.display === 'none' || style.visibility === 'hidden') return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load location into input fields
|
||||
@@ -189,9 +189,9 @@ const SSTV = (function() {
|
||||
/**
|
||||
* Initialize Leaflet map for ISS tracking
|
||||
*/
|
||||
async function initMap() {
|
||||
const mapContainer = document.getElementById('sstvIssMap');
|
||||
if (!mapContainer || issMap) return;
|
||||
async function initMap() {
|
||||
const mapContainer = document.getElementById('sstvIssMap');
|
||||
if (!mapContainer || issMap) return;
|
||||
|
||||
// Create map
|
||||
issMap = L.map('sstvIssMap', {
|
||||
@@ -231,21 +231,21 @@ const SSTV = (function() {
|
||||
issMarker = L.marker([0, 0], { icon: issIcon }).addTo(issMap);
|
||||
|
||||
// Create ground track line
|
||||
issTrackLine = L.polyline([], {
|
||||
color: '#00d4ff',
|
||||
weight: 2,
|
||||
opacity: 0.6,
|
||||
dashArray: '5, 5'
|
||||
}).addTo(issMap);
|
||||
|
||||
issMap.on('resize moveend zoomend', () => {
|
||||
if (pendingMapInvalidate) invalidateMap();
|
||||
});
|
||||
|
||||
// Initial layout passes for first-time mode load.
|
||||
setTimeout(() => invalidateMap(), 40);
|
||||
setTimeout(() => invalidateMap(), 180);
|
||||
}
|
||||
issTrackLine = L.polyline([], {
|
||||
color: '#00d4ff',
|
||||
weight: 2,
|
||||
opacity: 0.6,
|
||||
dashArray: '5, 5'
|
||||
}).addTo(issMap);
|
||||
|
||||
issMap.on('resize moveend zoomend', () => {
|
||||
if (pendingMapInvalidate) invalidateMap();
|
||||
});
|
||||
|
||||
// Initial layout passes for first-time mode load.
|
||||
setTimeout(() => invalidateMap(), 40);
|
||||
setTimeout(() => invalidateMap(), 180);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start ISS position tracking
|
||||
@@ -454,9 +454,9 @@ const SSTV = (function() {
|
||||
/**
|
||||
* Update map with ISS position
|
||||
*/
|
||||
function updateMap() {
|
||||
if (!issMap || !issPosition) return;
|
||||
if (pendingMapInvalidate) invalidateMap();
|
||||
function updateMap() {
|
||||
if (!issMap || !issPosition) return;
|
||||
if (pendingMapInvalidate) invalidateMap();
|
||||
|
||||
const lat = issPosition.lat;
|
||||
const lon = issPosition.lon;
|
||||
@@ -516,13 +516,13 @@ const SSTV = (function() {
|
||||
issTrackLine.setLatLngs(segments.length > 0 ? segments : []);
|
||||
}
|
||||
|
||||
// Pan map to follow ISS only when the map pane is currently renderable.
|
||||
if (isMapContainerVisible()) {
|
||||
issMap.panTo([lat, lon], { animate: true, duration: 0.5 });
|
||||
} else {
|
||||
pendingMapInvalidate = true;
|
||||
}
|
||||
}
|
||||
// Pan map to follow ISS only when the map pane is currently renderable.
|
||||
if (isMapContainerVisible()) {
|
||||
issMap.panTo([lat, lon], { animate: true, duration: 0.5 });
|
||||
} else {
|
||||
pendingMapInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check current decoder status
|
||||
@@ -1335,27 +1335,27 @@ const SSTV = (function() {
|
||||
/**
|
||||
* Show status message
|
||||
*/
|
||||
function showStatusMessage(message, type) {
|
||||
if (typeof showNotification === 'function') {
|
||||
showNotification('SSTV', message);
|
||||
} else {
|
||||
console.log(`[SSTV ${type}] ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate ISS map size after pane/layout changes.
|
||||
*/
|
||||
function invalidateMap() {
|
||||
if (!issMap) return false;
|
||||
if (!isMapContainerVisible()) {
|
||||
pendingMapInvalidate = true;
|
||||
return false;
|
||||
}
|
||||
issMap.invalidateSize({ pan: false, animate: false });
|
||||
pendingMapInvalidate = false;
|
||||
return true;
|
||||
}
|
||||
function showStatusMessage(message, type) {
|
||||
if (typeof showNotification === 'function') {
|
||||
showNotification('SSTV', message);
|
||||
} else {
|
||||
console.log(`[SSTV ${type}] ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate ISS map size after pane/layout changes.
|
||||
*/
|
||||
function invalidateMap() {
|
||||
if (!issMap) return false;
|
||||
if (!isMapContainerVisible()) {
|
||||
pendingMapInvalidate = true;
|
||||
return false;
|
||||
}
|
||||
issMap.invalidateSize({ pan: false, animate: false });
|
||||
pendingMapInvalidate = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Public API
|
||||
return {
|
||||
@@ -1370,12 +1370,25 @@ const SSTV = (function() {
|
||||
deleteAllImages,
|
||||
downloadImage,
|
||||
useGPS,
|
||||
updateTLE,
|
||||
stopIssTracking,
|
||||
stopCountdown,
|
||||
invalidateMap
|
||||
};
|
||||
})();
|
||||
updateTLE,
|
||||
stopIssTracking,
|
||||
stopCountdown,
|
||||
invalidateMap,
|
||||
destroy
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy — close SSE stream and clear ISS tracking/countdown timers for clean mode switching.
|
||||
*/
|
||||
function destroy() {
|
||||
if (eventSource) {
|
||||
eventSource.close();
|
||||
eventSource = null;
|
||||
}
|
||||
stopIssTracking();
|
||||
stopCountdown();
|
||||
}
|
||||
})();
|
||||
|
||||
// Initialize when DOM is ready (will be called by selectMode)
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
Reference in New Issue
Block a user