feat: Add local system override and manual entry controls with offline systems caching
CI / lint (push) Failing after 5s
CI / test (push) Successful in 19s
Build edge-node / build (push) Successful in 32s

This commit is contained in:
Logan Cusano
2026-07-12 23:06:05 -04:00
parent 9f026fa262
commit 857325af85
8 changed files with 439 additions and 12 deletions
@@ -142,6 +142,8 @@ class MQTTManager:
async def _publish_checkin(self):
from app.internal.discord_radio import radio_bot
from app.internal.config_manager import load_node_config
config = load_node_config()
payload = {
"node_id": settings.node_id,
"name": settings.node_name,
@@ -149,6 +151,10 @@ class MQTTManager:
"lon": settings.node_lon,
"discord_connected": radio_bot.is_connected,
"timestamp": datetime.now(timezone.utc).isoformat(),
"node_type": config.node_type,
"is_overridden": config.override_system_id is not None and config.node_type != "portable",
"override_system_id": config.override_system_id,
"enforce_override_timeout": config.enforce_override_timeout,
}
self._publish(self._t_checkin, payload, qos=1)
@@ -0,0 +1,50 @@
import json
from pathlib import Path
from typing import List, Dict, Any, Optional
import httpx
from app.config import settings
from app.internal.logger import logger
from app.internal import credentials
_CACHE_FILE = Path(settings.config_path) / "systems_cache.json"
async def fetch_and_cache_systems() -> bool:
"""Fetch all systems from the C2 server and cache them locally."""
if not settings.c2_url:
logger.warning("C2_URL not configured. Skipping system caching.")
return False
url = f"{settings.c2_url}/systems"
api_key = credentials.get_api_key()
headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
try:
async with httpx.AsyncClient(timeout=10) as client:
r = await client.get(url, headers=headers)
r.raise_for_status()
systems = r.json()
_CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
_CACHE_FILE.write_text(json.dumps(systems, indent=2))
logger.info(f"Cached {len(systems)} systems from C2.")
return True
except Exception as e:
logger.warning(f"Failed to fetch systems from C2: {e}. Offline cache will be used.")
return False
def load_cached_systems() -> List[Dict[str, Any]]:
"""Load cached systems from disk."""
if _CACHE_FILE.exists():
try:
return json.loads(_CACHE_FILE.read_text())
except Exception as e:
logger.error(f"Failed to read systems cache: {e}")
return []
def get_cached_system(system_id: str) -> Optional[Dict[str, Any]]:
"""Retrieve a single system config from the cache."""
systems = load_cached_systems()
for sys in systems:
if sys.get("system_id") == system_id:
return sys
return None