Fix APRS stop/start not repopulating stations

- Make stopAprs() async and await backend stop completion before
  re-enabling the Start button, preventing race where a late stop
  request kills newly started processes
- Add cache-buster param to EventSource URL to prevent browser
  SSE connection reuse between stop/start cycles
- Capture aprs_active_device locally in stream_aprs_output so the
  old thread's finally block doesn't release a device claimed by
  a new session

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-02-25 18:31:10 +00:00
parent 6daddafad7
commit aebcbc77be
2 changed files with 247 additions and 243 deletions
+8 -5
View File
@@ -1449,7 +1449,11 @@ def stream_aprs_output(rtl_process: subprocess.Popen, decoder_process: subproces
- type='meter': Audio level meter readings (rate-limited) - type='meter': Audio level meter readings (rate-limited)
""" """
global aprs_packet_count, aprs_station_count, aprs_last_packet_time, aprs_stations global aprs_packet_count, aprs_station_count, aprs_last_packet_time, aprs_stations
global _last_meter_time, _last_meter_level global _last_meter_time, _last_meter_level, aprs_active_device
# Capture the device claimed by THIS session so the finally block only
# releases our own device, not one claimed by a subsequent start.
my_device = aprs_active_device
# Reset meter state # Reset meter state
_last_meter_time = 0.0 _last_meter_time = 0.0
@@ -1543,7 +1547,6 @@ def stream_aprs_output(rtl_process: subprocess.Popen, decoder_process: subproces
logger.error(f"APRS stream error: {e}") logger.error(f"APRS stream error: {e}")
app_module.aprs_queue.put({'type': 'error', 'message': str(e)}) app_module.aprs_queue.put({'type': 'error', 'message': str(e)})
finally: finally:
global aprs_active_device
app_module.aprs_queue.put({'type': 'status', 'status': 'stopped'}) app_module.aprs_queue.put({'type': 'status', 'status': 'stopped'})
# Cleanup processes # Cleanup processes
for proc in [rtl_process, decoder_process]: for proc in [rtl_process, decoder_process]:
@@ -1555,9 +1558,9 @@ def stream_aprs_output(rtl_process: subprocess.Popen, decoder_process: subproces
proc.kill() proc.kill()
except Exception: except Exception:
pass pass
# Release SDR device # Release SDR device — only if it's still ours (not reclaimed by a new start)
if aprs_active_device is not None: if my_device is not None and aprs_active_device == my_device:
app_module.release_sdr_device(aprs_active_device) app_module.release_sdr_device(my_device)
aprs_active_device = None aprs_active_device = None
+6 -5
View File
@@ -9687,7 +9687,7 @@
}); });
} }
function stopAprs() { async function stopAprs() {
const isAgentMode = aprsCurrentAgent !== null; const isAgentMode = aprsCurrentAgent !== null;
const endpoint = isAgentMode const endpoint = isAgentMode
? `/controller/agents/${aprsCurrentAgent}/aprs/stop` ? `/controller/agents/${aprsCurrentAgent}/aprs/stop`
@@ -9697,9 +9697,8 @@
isAprsRunning = false; isAprsRunning = false;
aprsCurrentAgent = null; aprsCurrentAgent = null;
resetAprsAgentStationTracking(); resetAprsAgentStationTracking();
document.getElementById('aprsStripStartBtn').style.display = 'inline-block';
document.getElementById('aprsStripStopBtn').style.display = 'none'; document.getElementById('aprsStripStopBtn').style.display = 'none';
document.getElementById('aprsMapStatus').textContent = 'STANDBY'; document.getElementById('aprsMapStatus').textContent = 'STOPPING';
document.getElementById('aprsMapStatus').style.color = ''; document.getElementById('aprsMapStatus').style.color = '';
updateAprsStatus('standby'); updateAprsStatus('standby');
document.getElementById('aprsStripFreq').textContent = '--'; document.getElementById('aprsStripFreq').textContent = '--';
@@ -9722,7 +9721,9 @@
aprsPollTimer = null; aprsPollTimer = null;
} }
return postStopRequest(endpoint, timeoutMs); await postStopRequest(endpoint, timeoutMs);
document.getElementById('aprsStripStartBtn').style.display = 'inline-block';
document.getElementById('aprsMapStatus').textContent = 'STANDBY';
} }
function startAprsStream(isAgentMode = false) { function startAprsStream(isAgentMode = false) {
@@ -9730,7 +9731,7 @@
// Use different stream endpoint for agent mode // Use different stream endpoint for agent mode
const streamUrl = isAgentMode ? '/controller/stream/all' : '/aprs/stream'; const streamUrl = isAgentMode ? '/controller/stream/all' : '/aprs/stream';
aprsEventSource = new EventSource(streamUrl); aprsEventSource = new EventSource(streamUrl + (streamUrl.includes('?') ? '&' : '?') + 't=' + Date.now());
aprsEventSource.onmessage = function (e) { aprsEventSource.onmessage = function (e) {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);