diff --git a/src/main.py b/src/main.py index a02c473..7d3c357 100644 --- a/src/main.py +++ b/src/main.py @@ -115,7 +115,18 @@ def main() -> None: web = WebPortal(state=state, network_manager=nm, broadcaster=broadcaster) 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: bridge.stop() supervisor.stop() diff --git a/src/network_manager.py b/src/network_manager.py index cbd6955..d026d27 100644 --- a/src/network_manager.py +++ b/src/network_manager.py @@ -173,18 +173,21 @@ class NetworkManager: return sorted_items def _scan_with_wpa_cli(self) -> List[str]: - cmd_scan = ["wpa_cli", "-i", self.interface, "scan"] - proc = self._run(cmd_scan, timeout=15) - if proc.returncode != 0 or "OK" not in proc.stdout: - return [] + try: + cmd_scan = ["wpa_cli", "-i", self.interface, "scan"] + proc = self._run(cmd_scan, timeout=15) + if proc.returncode != 0 or "OK" not in proc.stdout: + return [] - for _ in range(8): - time.sleep(1) - 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: - parsed = self._parse_scan_results(proc_results.stdout) - if parsed: - return [ssid for ssid, _signal in parsed] + for _ in range(8): + time.sleep(1) + 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: + parsed = self._parse_scan_results(proc_results.stdout) + if parsed: + return [ssid for ssid, _signal in parsed] + except Exception: + return [] return [] def _scan_with_iw(self) -> List[str]: @@ -208,9 +211,12 @@ class NetworkManager: return ssids def scan_networks(self) -> List[str]: - ssids = self._scan_with_wpa_cli() - if not ssids: - ssids = self._scan_with_iw() + try: + ssids = self._scan_with_wpa_cli() + if not ssids: + ssids = self._scan_with_iw() + except Exception: + ssids = [] if ssids: self.state.set_known_ssids(ssids) diff --git a/src/webapp.py b/src/webapp.py index c8f1dde..068d32e 100644 --- a/src/webapp.py +++ b/src/webapp.py @@ -36,13 +36,21 @@ class WebPortal: @self.app.route("/api/status", methods=["GET"]) def status() -> Response: - self.network_manager.refresh_state() - return jsonify(self.state.snapshot()) + try: + 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"]) def scan() -> Response: - ssids = self.network_manager.scan_networks() - return jsonify({"ok": True, "ssids": ssids}) + try: + 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"]) def connect() -> Response: