Ctrl K
ComunidadGuías…

run.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""
Server runner for MediKeep.

This script starts the FastAPI server:
- Development mode: Hot reload enabled
- Windows EXE mode: Production server without reload
"""

import os
import sys

import uvicorn
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

# Add the app directory to Python path
sys.path.append(os.path.join(os.path.dirname(__file__), "app"))

if __name__ == "__main__":
    # Import and configure custom Uvicorn logging
    from app.core.config import settings
    from app.core.logging.config import get_logger
    from app.core.logging.uvicorn_logging import get_uvicorn_log_config
    from app.core.platform.windows_config import is_windows_exe

    # Get log level from environment variable for consistency
    log_level = os.getenv("LOG_LEVEL", "INFO").lower()

    # Detect if running as Windows EXE
    is_exe = is_windows_exe()

    # Setup logger for startup messages
    logger = get_logger(__name__, "app")

    # SSL configuration
    ssl_kwargs = {}
    if (
        settings.ENABLE_SSL
        and os.path.exists(settings.SSL_CERTFILE)
        and os.path.exists(settings.SSL_KEYFILE)
    ):
        ssl_kwargs.update(
            {
                "ssl_certfile": settings.SSL_CERTFILE,
                "ssl_keyfile": settings.SSL_KEYFILE,
            }
        )
        logger.info("HTTPS enabled: https://127.0.0.1:8000")
    else:
        logger.info("HTTP mode: http://127.0.0.1:8000")

    # Configure uvicorn based on execution mode
    if is_exe:
        # Windows EXE mode - production settings with system tray
        import signal
        import threading
        import time
        import webbrowser
        from app.core.utils.shutdown_manager import get_shutdown_manager, shutdown_application
        from app.core.platform.system_tray import is_tray_available, run_with_tray

        logger.info("Starting MediKeep in Windows EXE mode")
        logger.info(f"Data directory: {os.getenv('APPDATA')}\\Roaming\\MediKeep")

        # Get shutdown manager and configure timeout
        shutdown_manager = get_shutdown_manager(timeout=5)

        # Server reference for shutdown
        server_instance = None
        server_thread = None

        def run_server():
            """Run the uvicorn server in a separate thread."""
            global server_instance
            logger.info("Starting FastAPI server on http://127.0.0.1:8000")

            # Create uvicorn config
            config = uvicorn.Config(
                "app.main:app",
                host="127.0.0.1",
                port=8000,
                reload=False,
                log_level=log_level,
                log_config=get_uvicorn_log_config(),
                **ssl_kwargs,
            )
            server_instance = uvicorn.Server(config)

            # Run server
            try:
                server_instance.run()
            except Exception as e:
                logger.error(f"Server error: {e}")

        def shutdown_server():
            """Gracefully shutdown the uvicorn server."""
            if server_instance:
                logger.info("Shutting down FastAPI server...")
                try:
                    # Signal the server to shut down
                    server_instance.should_exit = True
                    # Wait briefly for shutdown
                    time.sleep(1)
                except Exception as e:
                    logger.error(f"Error during server shutdown: {e}")
            else:
                logger.warning("No server instance to shutdown")

        def shutdown_database():
            """Close all database connections."""
            try:
                from app.core.database import engine
                logger.info("Closing database connections...")
                engine.dispose()
                logger.info("Database connections closed")
            except Exception as e:
                logger.error(f"Error closing database: {e}")

        # Register shutdown handlers (executed in reverse order)
        shutdown_manager.register_handler(shutdown_database, "Database Cleanup")
        shutdown_manager.register_handler(shutdown_server, "Uvicorn Server")

        # Handle Ctrl+C gracefully
        def signal_handler(sig, frame):
            logger.info("Received interrupt signal (Ctrl+C)")
            shutdown_application(exit_code=0)

        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)

        # Check if system tray is available
        tray_available = is_tray_available()
        logger.info(f"System tray available: {tray_available}")

        if tray_available:
            logger.info("Starting system tray application")

            # Start server in background thread (non-daemon so it keeps running)
            server_thread = threading.Thread(target=run_server, daemon=False)
            server_thread.start()

            # Wait for server to start
            time.sleep(3)

            # Open browser automatically
            server_url = f"http://127.0.0.1:8000"
            logger.info(f"Opening browser to {server_url}")
            webbrowser.open(server_url)

            # Run system tray (this blocks until user quits from tray menu)
            try:
                run_with_tray(server_url)
            except Exception as e:
                logger.error(f"System tray failed: {e}")
                # If tray fails, keep server running in background
                server_thread.join()
        else:
            logger.warning("System tray not available, running in headless mode")
            # No tray available - just run server
            run_server()
    else:
        # Development mode - hot reload enabled
        logger.info("Starting MediKeep in development mode with hot reload")
        uvicorn.run(
            "app.main:app",
            host="127.0.0.1",
            port=8000,
            reload=True,
            reload_dirs=["app"],
            log_level=log_level,
            log_config=get_uvicorn_log_config(),
            access_log=True,  # Enable access logging to see HTTP requests
            **ssl_kwargs,
        )