Fix dry-mode API failures and fast SIGTERM shutdown

This commit is contained in:
2026-02-13 01:36:53 +01:00
parent 68a3540e6d
commit b20eb713a1
3 changed files with 44 additions and 19 deletions

View File

@@ -115,7 +115,18 @@ def main() -> None:
web = WebPortal(state=state, network_manager=nm, broadcaster=broadcaster) web = WebPortal(state=state, network_manager=nm, broadcaster=broadcaster)
try: try:
web.run(host="0.0.0.0", port=80) web_thread = threading.Thread(
target=web.run,
kwargs={"host": "0.0.0.0", "port": 80},
daemon=True,
name="web-portal",
)
web_thread.start()
while not stop_event.wait(1):
if not web_thread.is_alive():
LOG.error("Web server thread exited unexpectedly")
break
finally: finally:
bridge.stop() bridge.stop()
supervisor.stop() supervisor.stop()

View File

@@ -173,18 +173,21 @@ class NetworkManager:
return sorted_items return sorted_items
def _scan_with_wpa_cli(self) -> List[str]: def _scan_with_wpa_cli(self) -> List[str]:
cmd_scan = ["wpa_cli", "-i", self.interface, "scan"] try:
proc = self._run(cmd_scan, timeout=15) cmd_scan = ["wpa_cli", "-i", self.interface, "scan"]
if proc.returncode != 0 or "OK" not in proc.stdout: proc = self._run(cmd_scan, timeout=15)
return [] if proc.returncode != 0 or "OK" not in proc.stdout:
return []
for _ in range(8): for _ in range(8):
time.sleep(1) time.sleep(1)
proc_results = self._run(["wpa_cli", "-i", self.interface, "scan_results"], timeout=10) proc_results = self._run(["wpa_cli", "-i", self.interface, "scan_results"], timeout=10)
if proc_results.returncode == 0 and len(proc_results.stdout.splitlines()) > 1: if proc_results.returncode == 0 and len(proc_results.stdout.splitlines()) > 1:
parsed = self._parse_scan_results(proc_results.stdout) parsed = self._parse_scan_results(proc_results.stdout)
if parsed: if parsed:
return [ssid for ssid, _signal in parsed] return [ssid for ssid, _signal in parsed]
except Exception:
return []
return [] return []
def _scan_with_iw(self) -> List[str]: def _scan_with_iw(self) -> List[str]:
@@ -208,9 +211,12 @@ class NetworkManager:
return ssids return ssids
def scan_networks(self) -> List[str]: def scan_networks(self) -> List[str]:
ssids = self._scan_with_wpa_cli() try:
if not ssids: ssids = self._scan_with_wpa_cli()
ssids = self._scan_with_iw() if not ssids:
ssids = self._scan_with_iw()
except Exception:
ssids = []
if ssids: if ssids:
self.state.set_known_ssids(ssids) self.state.set_known_ssids(ssids)

View File

@@ -36,13 +36,21 @@ class WebPortal:
@self.app.route("/api/status", methods=["GET"]) @self.app.route("/api/status", methods=["GET"])
def status() -> Response: def status() -> Response:
self.network_manager.refresh_state() try:
return jsonify(self.state.snapshot()) self.network_manager.refresh_state()
return jsonify(self.state.snapshot())
except Exception as exc:
self.state.update_status("Status update failed", str(exc))
return jsonify(self.state.snapshot()), 503
@self.app.route("/api/scan", methods=["POST", "GET"]) @self.app.route("/api/scan", methods=["POST", "GET"])
def scan() -> Response: def scan() -> Response:
ssids = self.network_manager.scan_networks() try:
return jsonify({"ok": True, "ssids": ssids}) ssids = self.network_manager.scan_networks()
return jsonify({"ok": True, "ssids": ssids})
except Exception as exc:
self.state.update_status("Scan failed", str(exc))
return jsonify({"ok": False, "ssids": [], "message": str(exc)}), 503
@self.app.route("/api/connect", methods=["POST"]) @self.app.route("/api/connect", methods=["POST"])
def connect() -> Response: def connect() -> Response: