from __future__ import annotations import os from pathlib import Path import subprocess import sys import threading import time import urllib.request from tkinter import Tk, messagebox INSTALL_ROOT = Path(__file__).resolve().parent DATA_DIR = INSTALL_ROOT / "data" SUPERVISOR_LOCK = DATA_DIR / "supervisor.lock" SUPERVISOR_SCRIPT = INSTALL_ROOT / "ERPAgentSupervisor.pyw" URL = "http://127.0.0.1:8788" def _create_no_window() -> int: return getattr(subprocess, "CREATE_NO_WINDOW", 0) def _popup(title: str, message: str, error: bool = False) -> None: root = Tk() root.withdraw() if error: messagebox.showerror(title, message) else: messagebox.showinfo(title, message) root.destroy() def _pid_alive(pid: int) -> bool: if pid <= 0: return False try: os.kill(pid, 0) return True except OSError: return False def _supervisor_running() -> bool: try: if not SUPERVISOR_LOCK.exists(): return False return _pid_alive(int(SUPERVISOR_LOCK.read_text(encoding="utf-8").strip())) except Exception: return False def _pythonw() -> Path: pyw = INSTALL_ROOT / ".venv" / "Scripts" / "pythonw.exe" if pyw.exists(): return pyw py = INSTALL_ROOT / ".venv" / "Scripts" / "python.exe" if py.exists(): return py raise RuntimeError("ERP Local Agent Python environment was not found.") def _ensure_supervisor() -> None: if _supervisor_running(): return subprocess.Popen( [str(_pythonw()), str(SUPERVISOR_SCRIPT), "--background"], cwd=str(INSTALL_ROOT), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, creationflags=_create_no_window(), close_fds=True, ) deadline = time.time() + 20 while time.time() < deadline: if _supervisor_running(): return time.sleep(0.5) raise RuntimeError("ERP Local Agent supervisor did not start.") def _ready(timeout: float = 1.5) -> bool: try: with urllib.request.urlopen(URL + "/api/status", timeout=timeout) as response: return int(getattr(response, "status", 200)) < 500 except Exception: return False def _wait_ready(seconds: int = 75) -> bool: deadline = time.time() + seconds while time.time() < deadline: if _ready(): return True time.sleep(0.75) return False def main() -> None: try: _ensure_supervisor() except Exception as exc: _popup("ERP Local Agent", str(exc), error=True) return if not _wait_ready(): _popup( "ERP Local Agent", "The Local Agent supervisor is running, but the dashboard did not become ready.\n\n" f"Check logs under:\n{INSTALL_ROOT / 'logs'}", error=True, ) return try: import webview except Exception as exc: _popup( "ERP Local Agent Dashboard", "Desktop dashboard dependency could not be loaded.\n\n" f"{exc}\n\nRun the Local Agent updater/installer again.", error=True, ) return window = webview.create_window( "ERP Local Agent Dashboard", URL, width=1180, height=820, min_size=(980, 650), confirm_close=False, ) def monitor(): was_ready = True outage_seen = False while True: try: current = _ready() if was_ready and not current: outage_seen = True if outage_seen and current: try: window.load_url(URL) except Exception: pass outage_seen = False was_ready = current time.sleep(1.5) except Exception: time.sleep(2) webview.start(monitor) if __name__ == "__main__": main()