| 436 | os.environ["HOST_OS_FOR_SHORTCUT"] = host_os_map[camoufox_os] |
| 437 | |
| 438 | def _start_server(self): |
| 439 | logger.info( |
| 440 | f"--- Step 5: Starting integrated FastAPI server on port {self.args.server_port} ---" |
| 441 | ) |
| 442 | if app is None: |
| 443 | logger.error("FastAPI app not found.") |
| 444 | sys.exit(1) |
| 445 | |
| 446 | if not self.args.exit_on_auth_save: |
| 447 | try: |
| 448 | uvicorn.run( |
| 449 | app, host="0.0.0.0", port=self.args.server_port, log_config=None |
| 450 | ) |
| 451 | except Exception as e: |
| 452 | logger.critical(f"Uvicorn error: {e}", exc_info=True) |
| 453 | sys.exit(1) |
| 454 | else: |
| 455 | server_config = uvicorn.Config( |
| 456 | app, host="0.0.0.0", port=self.args.server_port, log_config=None |
| 457 | ) |
| 458 | server = uvicorn.Server(server_config) |
| 459 | stop_watcher = threading.Event() |
| 460 | |
| 461 | def watch_for_saved_auth_and_shutdown(): |
| 462 | os.makedirs(SAVED_AUTH_DIR, exist_ok=True) |
| 463 | initial_files = set(os.listdir(SAVED_AUTH_DIR)) |
| 464 | while not stop_watcher.is_set(): |
| 465 | try: |
| 466 | new_files = set(os.listdir(SAVED_AUTH_DIR)) - initial_files |
| 467 | if new_files: |
| 468 | logger.info( |
| 469 | f"New auth file detected: {', '.join(new_files)}. Shutting down in 3s..." |
| 470 | ) |
| 471 | time.sleep(3) |
| 472 | server.should_exit = True |
| 473 | break |
| 474 | except Exception: |
| 475 | pass |
| 476 | if stop_watcher.wait(1): |
| 477 | break |
| 478 | |
| 479 | watcher_thread = threading.Thread(target=watch_for_saved_auth_and_shutdown) |
| 480 | try: |
| 481 | watcher_thread.start() |
| 482 | server.run() |
| 483 | except Exception as e: |
| 484 | logger.critical(f"Uvicorn error: {e}", exc_info=True) |
| 485 | sys.exit(1) |
| 486 | finally: |
| 487 | stop_watcher.set() |
| 488 | if watcher_thread.is_alive(): |
| 489 | watcher_thread.join() |
| 490 | |
| 491 | |
| 492 | def signal_handler(sig, frame): |