mirror of
https://github.com/smittix/intercept.git
synced 2026-07-20 07:18:11 -07:00
Capture rtl_fm stderr for pipeline error diagnostics
rtl_fm stderr was sent to DEVNULL, hiding the actual failure reason (rc=1). Now captured and surfaced in the error response. Also drains rtl_fm stderr during normal operation to prevent pipe blocking. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+19
-4
@@ -276,7 +276,7 @@ def start_dmr() -> Response:
|
|||||||
dmr_rtl_process = subprocess.Popen(
|
dmr_rtl_process = subprocess.Popen(
|
||||||
rtl_cmd,
|
rtl_cmd,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
dmr_dsd_process = subprocess.Popen(
|
dmr_dsd_process = subprocess.Popen(
|
||||||
@@ -295,18 +295,33 @@ def start_dmr() -> Response:
|
|||||||
dsd_rc = dmr_dsd_process.poll()
|
dsd_rc = dmr_dsd_process.poll()
|
||||||
if rtl_rc is not None or dsd_rc is not None:
|
if rtl_rc is not None or dsd_rc is not None:
|
||||||
# Process died — capture stderr for diagnostics
|
# Process died — capture stderr for diagnostics
|
||||||
|
rtl_err = ''
|
||||||
|
if dmr_rtl_process.stderr:
|
||||||
|
rtl_err = dmr_rtl_process.stderr.read().decode('utf-8', errors='replace')[:500]
|
||||||
dsd_err = ''
|
dsd_err = ''
|
||||||
if dmr_dsd_process.stderr:
|
if dmr_dsd_process.stderr:
|
||||||
dsd_err = dmr_dsd_process.stderr.read().decode('utf-8', errors='replace')[:500]
|
dsd_err = dmr_dsd_process.stderr.read().decode('utf-8', errors='replace')[:500]
|
||||||
logger.error(f"DSD pipeline died: rtl_fm rc={rtl_rc}, dsd rc={dsd_rc}, dsd stderr={dsd_err!r}")
|
logger.error(f"DSD pipeline died: rtl_fm rc={rtl_rc} err={rtl_err!r}, dsd rc={dsd_rc} err={dsd_err!r}")
|
||||||
if dmr_active_device is not None:
|
if dmr_active_device is not None:
|
||||||
app_module.release_sdr_device(dmr_active_device)
|
app_module.release_sdr_device(dmr_active_device)
|
||||||
dmr_active_device = None
|
dmr_active_device = None
|
||||||
|
# Surface the most relevant error to the user
|
||||||
|
detail = rtl_err.strip() or dsd_err.strip()
|
||||||
msg = 'Failed to start DSD pipeline'
|
msg = 'Failed to start DSD pipeline'
|
||||||
if dsd_err:
|
if detail:
|
||||||
msg += f': {dsd_err.strip()}'
|
msg += f': {detail}'
|
||||||
return jsonify({'status': 'error', 'message': msg}), 500
|
return jsonify({'status': 'error', 'message': msg}), 500
|
||||||
|
|
||||||
|
# Drain rtl_fm stderr in background to prevent pipe blocking
|
||||||
|
def _drain_rtl_stderr(proc):
|
||||||
|
try:
|
||||||
|
for line in proc.stderr:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
threading.Thread(target=_drain_rtl_stderr, args=(dmr_rtl_process,), daemon=True).start()
|
||||||
|
|
||||||
dmr_running = True
|
dmr_running = True
|
||||||
dmr_thread = threading.Thread(
|
dmr_thread = threading.Thread(
|
||||||
target=stream_dsd_output,
|
target=stream_dsd_output,
|
||||||
|
|||||||
Reference in New Issue
Block a user