- desktop/Cargo.toml: Tauri + plugins (dialog, notification, fs, updater) - desktop/tauri.conf.json: Windows (.msi/.nsis) + Linux (.deb/.AppImage) config - desktop/src/main.rs: spawn Python backend, health check, tray icon, commands - desktop/build.rs: Tauri build hook - desktop/python-embed/sidecar.py: uvicorn launcher with port auto-detect - build-windows.bat: automated Windows build with Python embed download - build-linux.sh: automated Linux build with venv - desktop/README.md: architecture doc + usage guide - desktop/validate-structure.sh: CI validation script - ROADMAP.md: #77 Tauri Desktop section added
73 lines
2.1 KiB
Python
73 lines
2.1 KiB
Python
#!/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()
|