mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Fix dashboard startup regressions and mode utilities
This commit is contained in:
@@ -725,11 +725,12 @@ def agent_management_page():
|
||||
return render_template('agents.html', version=VERSION)
|
||||
|
||||
|
||||
@controller_bp.route('/monitor')
|
||||
def network_monitor_page():
|
||||
"""Render the network monitor page for multi-agent aggregated view."""
|
||||
from flask import render_template
|
||||
return render_template('network_monitor.html')
|
||||
@controller_bp.route('/monitor')
|
||||
def network_monitor_page():
|
||||
"""Render the network monitor page for multi-agent aggregated view."""
|
||||
from flask import render_template
|
||||
from config import VERSION
|
||||
return render_template('network_monitor.html', version=VERSION)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
@@ -66,8 +66,8 @@ AUTO_RX_PATHS = [
|
||||
]
|
||||
|
||||
|
||||
def find_auto_rx() -> str | None:
|
||||
"""Find radiosonde_auto_rx script/binary."""
|
||||
def find_auto_rx() -> str | None:
|
||||
"""Find radiosonde_auto_rx script/binary."""
|
||||
# Check PATH first
|
||||
path = shutil.which('radiosonde_auto_rx')
|
||||
if path:
|
||||
@@ -77,10 +77,66 @@ def find_auto_rx() -> str | None:
|
||||
if os.path.isfile(p) and os.access(p, os.X_OK):
|
||||
return p
|
||||
# Check for Python script (not executable but runnable)
|
||||
for p in AUTO_RX_PATHS:
|
||||
if os.path.isfile(p):
|
||||
return p
|
||||
return None
|
||||
for p in AUTO_RX_PATHS:
|
||||
if os.path.isfile(p):
|
||||
return p
|
||||
return None
|
||||
|
||||
|
||||
def _iter_auto_rx_python_candidates(auto_rx_path: str):
|
||||
"""Yield plausible Python interpreters for radiosonde_auto_rx."""
|
||||
auto_rx_abs = os.path.abspath(auto_rx_path)
|
||||
auto_rx_dir = os.path.dirname(auto_rx_abs)
|
||||
install_root = os.path.dirname(auto_rx_dir)
|
||||
|
||||
candidates = [
|
||||
sys.executable,
|
||||
os.path.join(install_root, 'venv', 'bin', 'python'),
|
||||
os.path.join(install_root, '.venv', 'bin', 'python'),
|
||||
os.path.join(auto_rx_dir, 'venv', 'bin', 'python'),
|
||||
os.path.join(auto_rx_dir, '.venv', 'bin', 'python'),
|
||||
shutil.which('python3'),
|
||||
]
|
||||
|
||||
seen: set[str] = set()
|
||||
for candidate in candidates:
|
||||
if not candidate:
|
||||
continue
|
||||
candidate_abs = os.path.abspath(candidate)
|
||||
if candidate_abs in seen:
|
||||
continue
|
||||
seen.add(candidate_abs)
|
||||
if os.path.isfile(candidate_abs) and os.access(candidate_abs, os.X_OK):
|
||||
yield candidate_abs
|
||||
|
||||
|
||||
def _resolve_auto_rx_python(auto_rx_path: str) -> tuple[str | None, str, list[str]]:
|
||||
"""Pick a Python interpreter that can import autorx.scan successfully."""
|
||||
auto_rx_dir = os.path.dirname(os.path.abspath(auto_rx_path))
|
||||
checked: list[str] = []
|
||||
last_error = 'No usable Python interpreter found'
|
||||
|
||||
for python_bin in _iter_auto_rx_python_candidates(auto_rx_path):
|
||||
checked.append(python_bin)
|
||||
try:
|
||||
dep_check = subprocess.run(
|
||||
[python_bin, '-c', 'import autorx.scan'],
|
||||
cwd=auto_rx_dir,
|
||||
capture_output=True,
|
||||
timeout=10,
|
||||
)
|
||||
except Exception as exc:
|
||||
last_error = str(exc)
|
||||
continue
|
||||
|
||||
if dep_check.returncode == 0:
|
||||
return python_bin, '', checked
|
||||
|
||||
stderr_output = dep_check.stderr.decode('utf-8', errors='ignore').strip()
|
||||
stdout_output = dep_check.stdout.decode('utf-8', errors='ignore').strip()
|
||||
last_error = stderr_output or stdout_output or f'Interpreter exited with code {dep_check.returncode}'
|
||||
|
||||
return None, last_error, checked
|
||||
|
||||
|
||||
def generate_station_cfg(
|
||||
@@ -544,33 +600,31 @@ def start_radiosonde():
|
||||
logger.error(f"Failed to generate radiosonde config: {e}")
|
||||
return api_error(str(e), 500)
|
||||
|
||||
# Build command - auto_rx -c expects the path to station.cfg
|
||||
cfg_abs = os.path.abspath(cfg_path)
|
||||
if auto_rx_path.endswith('.py'):
|
||||
cmd = [sys.executable, auto_rx_path, '-c', cfg_abs]
|
||||
else:
|
||||
cmd = [auto_rx_path, '-c', cfg_abs]
|
||||
|
||||
# Set cwd to the auto_rx directory so 'from autorx.scan import ...' works
|
||||
auto_rx_dir = os.path.dirname(os.path.abspath(auto_rx_path))
|
||||
|
||||
# Quick dependency check before launching the full process
|
||||
if auto_rx_path.endswith('.py'):
|
||||
dep_check = subprocess.run(
|
||||
[sys.executable, '-c', 'import autorx.scan'],
|
||||
cwd=auto_rx_dir,
|
||||
capture_output=True,
|
||||
timeout=10,
|
||||
)
|
||||
if dep_check.returncode != 0:
|
||||
dep_error = dep_check.stderr.decode('utf-8', errors='ignore').strip()
|
||||
logger.error(f"radiosonde_auto_rx dependency check failed:\n{dep_error}")
|
||||
app_module.release_sdr_device(device_int, sdr_type_str)
|
||||
return api_error(
|
||||
'radiosonde_auto_rx dependencies not satisfied. '
|
||||
f'Re-run setup.sh to install. Error: {dep_error[:500]}',
|
||||
500,
|
||||
)
|
||||
# Build command - auto_rx -c expects the path to station.cfg
|
||||
cfg_abs = os.path.abspath(cfg_path)
|
||||
if auto_rx_path.endswith('.py'):
|
||||
selected_python, dep_error, checked_interpreters = _resolve_auto_rx_python(auto_rx_path)
|
||||
if not selected_python:
|
||||
logger.error(
|
||||
"radiosonde_auto_rx dependency check failed across interpreters %s: %s",
|
||||
checked_interpreters,
|
||||
dep_error,
|
||||
)
|
||||
app_module.release_sdr_device(device_int, sdr_type_str)
|
||||
checked_msg = ', '.join(checked_interpreters) if checked_interpreters else 'none'
|
||||
return api_error(
|
||||
'radiosonde_auto_rx dependencies not satisfied. '
|
||||
'Install or repair its Python environment (missing packages such as semver). '
|
||||
f'Checked interpreters: {checked_msg}. '
|
||||
f'Last error: {dep_error[:500]}',
|
||||
500,
|
||||
)
|
||||
cmd = [selected_python, auto_rx_path, '-c', cfg_abs]
|
||||
else:
|
||||
cmd = [auto_rx_path, '-c', cfg_abs]
|
||||
|
||||
# Set cwd to the auto_rx directory so 'from autorx.scan import ...' works
|
||||
auto_rx_dir = os.path.dirname(os.path.abspath(auto_rx_path))
|
||||
|
||||
try:
|
||||
logger.info(f"Starting radiosonde_auto_rx: {' '.join(cmd)}")
|
||||
|
||||
@@ -30,12 +30,13 @@ satellite_bp = Blueprint('satellite', __name__, url_prefix='/satellite')
|
||||
_cached_timescale = None
|
||||
|
||||
|
||||
def _get_timescale():
|
||||
global _cached_timescale
|
||||
if _cached_timescale is None:
|
||||
from skyfield.api import load
|
||||
_cached_timescale = load.timescale()
|
||||
return _cached_timescale
|
||||
def _get_timescale():
|
||||
global _cached_timescale
|
||||
if _cached_timescale is None:
|
||||
from skyfield.api import load
|
||||
# Use bundled timescale data so the first request does not block on network I/O.
|
||||
_cached_timescale = load.timescale(builtin=True)
|
||||
return _cached_timescale
|
||||
|
||||
# Maximum response size for external requests (1MB)
|
||||
MAX_RESPONSE_SIZE = 1024 * 1024
|
||||
|
||||
@@ -472,14 +472,14 @@ def stream_progress():
|
||||
return response
|
||||
|
||||
|
||||
def _get_timescale():
|
||||
"""Return a cached skyfield timescale (expensive to create)."""
|
||||
global _timescale
|
||||
with _timescale_lock:
|
||||
if _timescale is None:
|
||||
from skyfield.api import load
|
||||
_timescale = load.timescale()
|
||||
return _timescale
|
||||
def _get_timescale():
|
||||
"""Return a cached skyfield timescale (expensive to create)."""
|
||||
global _timescale
|
||||
with _timescale_lock:
|
||||
if _timescale is None:
|
||||
from skyfield.api import load
|
||||
_timescale = load.timescale(builtin=True)
|
||||
return _timescale
|
||||
|
||||
|
||||
@sstv_bp.route('/iss-schedule')
|
||||
|
||||
Reference in New Issue
Block a user