"""Start all jrxml-agent services (validator, API, frontend).""" import subprocess import sys import time import urllib.request from pathlib import Path ROOT = Path(__file__).parent VENV_PYTHON = ROOT / ".venv" / "Scripts" / "python.exe" FRONTEND_DIR = ROOT / "frontend" def kill_port(port: int): """Kill any process listening on the given port.""" import os import signal try: result = subprocess.run( ["netstat", "-ano"], capture_output=True, text=True ) for line in result.stdout.splitlines(): if f":{port}" in line and "LISTENING" in line: parts = line.split() pid = int(parts[-1]) print(f" Killing PID {pid} on port {port}") os.kill(pid, signal.SIGTERM) except Exception as e: print(f" (cleanup note: {e})") def wait_http(url: str, timeout: int = 60, interval: float = 2.0) -> bool: """Wait until an HTTP endpoint responds 200, or timeout.""" deadline = time.time() + timeout while time.time() < deadline: try: urllib.request.urlopen(url, timeout=2) return True except Exception: time.sleep(interval) return False def wait_port(port: int, timeout: int = 60, interval: float = 3.0) -> bool: """Wait until a TCP port is listening.""" deadline = time.time() + timeout while time.time() < deadline: try: result = subprocess.run( ["netstat", "-ano"], capture_output=True, text=True ) for line in result.stdout.splitlines(): if f":{port}" in line and "LISTENING" in line: return True except Exception: pass time.sleep(interval) return False def main(): if not VENV_PYTHON.exists(): print("[ERROR] .venv not found. Create a virtual environment first.") sys.exit(1) print("=" * 48) print(" jrxml-agent launcher (full stack)") print("=" * 48) # -- cleanup -- print("\n[Cleanup] Checking residual processes...") for port in (8000, 8001, 5173): kill_port(port) # -- 1. Validator -- print("\n[1/3] Starting validator on :8001 ...") subprocess.Popen( [str(VENV_PYTHON), "-c", "import uvicorn; uvicorn.run('validation_service.main:app',host='0.0.0.0',port=8001,reload=False)"], cwd=str(ROOT), creationflags=subprocess.CREATE_NO_WINDOW, ) if not wait_http("http://localhost:8001/health"): print("[FAIL] Validator did not start in time.") sys.exit(1) print(" :8001 ready") # -- 2. API -- print("[2/3] Starting API on :8000 ...") subprocess.Popen( [str(VENV_PYTHON), "-c", "import uvicorn; uvicorn.run('api_server:app',host='0.0.0.0',port=8000,reload=False)"], cwd=str(ROOT), creationflags=subprocess.CREATE_NO_WINDOW, ) if not wait_http("http://localhost:8000/api/health"): print("[FAIL] API server did not start in time.") sys.exit(1) print(" :8000 ready") # -- 3. Frontend -- print("[3/3] Starting frontend on :5173 ...") if not (FRONTEND_DIR / "node_modules").exists(): print(" Installing npm dependencies...") subprocess.run(["npm", "install"], cwd=str(FRONTEND_DIR), check=True) subprocess.Popen( "npm run dev", cwd=str(FRONTEND_DIR), creationflags=subprocess.CREATE_NO_WINDOW, shell=True, ) if not wait_port(5173): print("[FAIL] Frontend did not start in time.") sys.exit(1) print(" :5173 ready") print("\n" + "=" * 48) print(" All services ready:") print(" Frontend: http://localhost:5173") print(" API: http://localhost:8000/docs") print(" Validator: http://localhost:8001/health") print(" Press Ctrl+C to stop all services") print("=" * 48) try: while True: time.sleep(1) except KeyboardInterrupt: print("\nShutting down...") if __name__ == "__main__": main()