""" Gondulf IndieAuth Server - Main application entry point. FastAPI application with health check endpoint and core service initialization. """ import logging from fastapi import FastAPI from fastapi.responses import JSONResponse from gondulf.config import Config from gondulf.database.connection import Database from gondulf.dns import DNSService from gondulf.email import EmailService from gondulf.logging_config import configure_logging from gondulf.routers import authorization, token, verification from gondulf.storage import CodeStore # Load configuration at application startup Config.load() Config.validate() # Configure logging configure_logging(log_level=Config.LOG_LEVEL, debug=Config.DEBUG) logger = logging.getLogger("gondulf.main") # Initialize FastAPI application app = FastAPI( title="Gondulf IndieAuth Server", description="Self-hosted IndieAuth authentication server", version="0.1.0-dev", ) # Register routers app.include_router(authorization.router) app.include_router(token.router) app.include_router(verification.router) # Initialize core services database: Database = None code_store: CodeStore = None email_service: EmailService = None dns_service: DNSService = None @app.on_event("startup") async def startup_event() -> None: """ Initialize application on startup. Initializes database, code storage, email service, and DNS service. """ global database, code_store, email_service, dns_service logger.info("Starting Gondulf IndieAuth Server") logger.info(f"Configuration: DATABASE_URL={Config.DATABASE_URL}") logger.info(f"Configuration: SMTP_HOST={Config.SMTP_HOST}:{Config.SMTP_PORT}") logger.info(f"Configuration: DEBUG={Config.DEBUG}") try: # Initialize database logger.info("Initializing database") database = Database(Config.DATABASE_URL) database.initialize() logger.info("Database initialized successfully") # Initialize code store logger.info("Initializing code store") code_store = CodeStore(ttl_seconds=Config.CODE_EXPIRY) logger.info(f"Code store initialized with TTL={Config.CODE_EXPIRY}s") # Initialize email service logger.info("Initializing email service") email_service = EmailService( smtp_host=Config.SMTP_HOST, smtp_port=Config.SMTP_PORT, smtp_from=Config.SMTP_FROM, smtp_username=Config.SMTP_USERNAME, smtp_password=Config.SMTP_PASSWORD, smtp_use_tls=Config.SMTP_USE_TLS, ) logger.info("Email service initialized") # Initialize DNS service logger.info("Initializing DNS service") dns_service = DNSService() logger.info("DNS service initialized") logger.info("Gondulf startup complete") except Exception as e: logger.critical(f"Failed to initialize application: {e}") raise @app.on_event("shutdown") async def shutdown_event() -> None: """Clean up resources on shutdown.""" logger.info("Shutting down Gondulf IndieAuth Server") @app.get("/health") async def health_check() -> JSONResponse: """ Health check endpoint. Verifies that the application is running and database is accessible. Does not require authentication. Returns: JSON response with health status: - 200 OK: {"status": "healthy", "database": "connected"} - 503 Service Unavailable: {"status": "unhealthy", "database": "error", "error": "..."} """ # Check database connectivity if database is None: logger.warning("Health check failed: database not initialized") return JSONResponse( status_code=503, content={ "status": "unhealthy", "database": "error", "error": "database not initialized", }, ) is_healthy = database.check_health(timeout_seconds=5) if is_healthy: logger.debug("Health check passed") return JSONResponse( status_code=200, content={"status": "healthy", "database": "connected"}, ) else: logger.warning("Health check failed: unable to connect to database") return JSONResponse( status_code=503, content={ "status": "unhealthy", "database": "error", "error": "unable to connect to database", }, ) @app.get("/") async def root() -> dict: """ Root endpoint. Returns basic server information. """ return { "service": "Gondulf IndieAuth Server", "version": "0.1.0-dev", "status": "operational", } # Entry point for uvicorn if __name__ == "__main__": import uvicorn uvicorn.run( "gondulf.main:app", host="0.0.0.0", port=8000, reload=Config.DEBUG, log_level=Config.LOG_LEVEL.lower(), )