#!/usr/bin/env python3 """ ObsiGate Desktop — Sidecar Launcher ==================================== Lancé par le shell Tauri, démarre le backend FastAPI. Utilise le port 17890 (127.0.0.1 uniquement, pas d'exposition réseau). """ import sys import os import subprocess import time import signal BACKEND_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) HOST = "127.0.0.1" PORT = int(os.environ.get("OBSIGATE_PORT", "17890")) def find_free_port(start: int) -> int: """Trouve le premier port libre à partir de `start`.""" import socket port = start while port < start + 100: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: if s.connect_ex((HOST, port)) != 0: return port port += 1 raise RuntimeError(f"No free port found in range {start}-{start+99}") def main(): port = find_free_port(PORT) # Create log directory if sys.platform == "win32": log_dir = os.path.join(os.environ.get("APPDATA", os.path.expanduser("~")), "ObsiGate", "logs") else: log_dir = os.path.join(os.path.expanduser("~"), ".local", "share", "obsigate", "logs") os.makedirs(log_dir, exist_ok=True) log_file = os.path.join(log_dir, "backend.log") print(f"ObsiGate backend starting on {HOST}:{port} — logs: {log_file}") # Launch uvicorn cmd = [ sys.executable, "-m", "uvicorn", "backend.main:app", "--host", HOST, "--port", str(port), "--log-level", "info", ] with open(log_file, "a") as log: log.write(f"\n--- ObsiGate started at {time.ctime()} ---\n") proc = subprocess.Popen(cmd, cwd=BACKEND_DIR, stdout=log, stderr=log) def handle_signal(signum, frame): print("Shutting down ObsiGate backend...") proc.terminate() proc.wait(timeout=10) sys.exit(0) signal.signal(signal.SIGTERM, handle_signal) signal.signal(signal.SIGINT, handle_signal) # Wait for backend to finish proc.wait() if __name__ == "__main__": main()