run.py
Rama main · réplica de lectura del repositorio original.
#!/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,
)