from contextlib import asynccontextmanager from datetime import datetime from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from pathlib import Path import logging import os from .config import settings from .database import ensure_oracle_pool, close_oracle, init_sqlite # Configure logging with both stream and file handlers _log_level = getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO) _log_format = '%(asctime)s | %(levelname)s | %(name)s | %(message)s' _formatter = logging.Formatter(_log_format) _stream_handler = logging.StreamHandler() _stream_handler.setFormatter(_formatter) _log_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'logs') os.makedirs(_log_dir, exist_ok=True) _log_filename = f"sync_comenzi_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" _file_handler = logging.FileHandler(os.path.join(_log_dir, _log_filename), encoding='utf-8') _file_handler.setFormatter(_formatter) _root_logger = logging.getLogger() _root_logger.setLevel(_log_level) _root_logger.addHandler(_stream_handler) _root_logger.addHandler(_file_handler) logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): """Startup and shutdown events.""" logger.info("Starting GoMag Import Manager...") # Initialize Oracle pool (non-fatal: app still starts if Oracle is down; # each sync cycle calls ensure_oracle_pool() and self-heals when it returns) if not ensure_oracle_pool(): logger.error("Oracle pool not ready at startup — will retry on each sync cycle") # Initialize SQLite init_sqlite() # Initialize scheduler (restore saved config) from .services import scheduler_service, sqlite_service scheduler_service.init_scheduler() try: config = await sqlite_service.get_scheduler_config() if config.get("enabled") == "True": interval = int(config.get("interval_minutes", "10")) scheduler_service.start_scheduler(interval) except Exception: pass logger.info("GoMag Import Manager started") yield # Shutdown scheduler_service.shutdown_scheduler() close_oracle() logger.info("GoMag Import Manager stopped") app = FastAPI( title="GoMag Import Manager", description="Import comenzi web GoMag → ROA Oracle", version="1.0.0", lifespan=lifespan ) # Static files and templates static_dir = Path(__file__).parent / "static" templates_dir = Path(__file__).parent / "templates" static_dir.mkdir(parents=True, exist_ok=True) (static_dir / "css").mkdir(exist_ok=True) (static_dir / "js").mkdir(exist_ok=True) templates_dir.mkdir(parents=True, exist_ok=True) app.mount("/static", StaticFiles(directory=str(static_dir)), name="static") # Include routers from .routers import health, dashboard, mappings, articles, validation, sync app.include_router(health.router) app.include_router(dashboard.router) app.include_router(mappings.router) app.include_router(articles.router) app.include_router(validation.router) app.include_router(sync.router)