Spaces:
Paused
Paused
| from fastapi import FastAPI, Request, WebSocket | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import RedirectResponse | |
| from app.core.config import settings | |
| from app.db.database import async_engine as engine, Base | |
| from app.api import auth, products, orders, users, analytics, files, notifications, calendar, scheduler, maintenance, branches, staff_analytics, sessions | |
| from app.utils.rate_limiter import rate_limiter | |
| from app.utils.logger import log_api_request | |
| from app.utils.tasks import run_periodic_tasks, sync_pos_metrics_task | |
| from app.services.websocket import connect, disconnect | |
| from app.realtime.subscriber import subscribe_order_events | |
| from app.routes.websocket import websocket_endpoint, manager, router as websocket_router, staff_metrics_websocket | |
| import socketio | |
| import time | |
| import logging | |
| import asyncio | |
| from typing import List, Dict, Optional | |
| from app.db.models import ensure_tables | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Create Socket.IO server | |
| sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*') | |
| socket_app = socketio.ASGIApp(sio) | |
| app = FastAPI(title=settings.PROJECT_NAME, version=settings.VERSION, openapi_url=f"{settings.API_V1_STR}/openapi.json") | |
| # Store background tasks | |
| background_tasks = set() | |
| # Configure CORS | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["http://localhost:5173", "http://localhost:3000"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Socket.IO event handlers | |
| async def connect(sid: str, environ: dict, auth: Optional[dict] = None): | |
| logger.info(f"Client connected: {sid}") | |
| return True | |
| async def disconnect(sid: str): | |
| logger.info(f"Client disconnected: {sid}") | |
| async def message(sid: str, data: dict): | |
| logger.info(f"Message from {sid}: {data}") | |
| await sio.emit('message', {'response': 'Message received'}, room=sid) | |
| # Mount Socket.IO app | |
| app.mount("/socket.io", socket_app) | |
| async def health_check() -> Dict[str, str]: | |
| """Public health check endpoint that doesn't require authentication""" | |
| return { | |
| "status": "healthy", | |
| "version": settings.VERSION, | |
| "service": settings.PROJECT_NAME | |
| } | |
| # WebSocket endpoint | |
| async def websocket_handler(websocket: WebSocket): | |
| await websocket_endpoint(websocket) | |
| async def orders_websocket_handler(websocket: WebSocket): | |
| await websocket_endpoint(websocket) | |
| # Request logging and rate limiting middleware | |
| async def middleware(request: Request, call_next): | |
| await rate_limiter.check_rate_limit(request) | |
| start_time = time.time() | |
| response = await call_next(request) | |
| end_time = time.time() | |
| duration = end_time - start_time | |
| log_api_request( | |
| method=request.method, | |
| path=request.url.path, | |
| status_code=response.status_code, | |
| duration=duration | |
| ) | |
| return response | |
| # Application startup and shutdown events | |
| async def startup_event(): | |
| # Create all database tables | |
| await ensure_tables() | |
| # Start Redis subscriber in background | |
| task = asyncio.create_task(subscribe_order_events(manager)) | |
| background_tasks.add(task) | |
| task.add_done_callback(background_tasks.discard) | |
| # Start periodic tasks | |
| task = asyncio.create_task(run_periodic_tasks()) | |
| background_tasks.add(task) | |
| task.add_done_callback(background_tasks.discard) | |
| # Start POS metrics sync task | |
| task = asyncio.create_task(sync_pos_metrics_task()) | |
| background_tasks.add(task) | |
| task.add_done_callback(background_tasks.discard) | |
| async def shutdown_event(): | |
| # Cancel background tasks | |
| for task in background_tasks: | |
| task.cancel() | |
| # Dashboard compatibility routes | |
| async def sales_redirect(): | |
| return RedirectResponse(url=f"{settings.API_V1_STR}/analytics/sales") | |
| async def customers_redirect(): | |
| return RedirectResponse(url=f"{settings.API_V1_STR}/analytics/customers") | |
| async def brands_redirect(): | |
| return RedirectResponse(url=f"{settings.API_V1_STR}/analytics/brands") | |
| async def products_redirect(): | |
| return RedirectResponse(url=f"{settings.API_V1_STR}/analytics/products") | |
| # Include routers | |
| app.include_router(auth.router, prefix=f"{settings.API_V1_STR}/auth", tags=["auth"]) | |
| app.include_router(users.router, prefix=f"{settings.API_V1_STR}/users", tags=["users"]) | |
| app.include_router(products.router, prefix=f"{settings.API_V1_STR}/products", tags=["products"]) | |
| app.include_router(orders.router, prefix=f"{settings.API_V1_STR}/orders", tags=["orders"]) | |
| app.include_router(analytics.router, prefix=f"{settings.API_V1_STR}/analytics", tags=["analytics"]) | |
| app.include_router(files.router, prefix=f"{settings.API_V1_STR}/files", tags=["files"]) | |
| app.include_router(notifications.router, prefix=f"{settings.API_V1_STR}/notifications", tags=["notifications"]) | |
| app.include_router(calendar.router, prefix=f"{settings.API_V1_STR}/calendar", tags=["calendar"]) | |
| app.include_router(scheduler.router, prefix=f"{settings.API_V1_STR}/scheduler", tags=["scheduler"]) | |
| app.include_router(maintenance.router, prefix=f"{settings.API_V1_STR}/maintenance", tags=["maintenance"]) | |
| app.include_router(branches.router, prefix=f"{settings.API_V1_STR}/branches", tags=["branches"]) | |
| app.include_router(staff_analytics.router, prefix=f"{settings.API_V1_STR}/staff", tags=["staff"]) | |
| app.include_router(sessions.router, prefix=f"{settings.API_V1_STR}/sessions", tags=["sessions"]) | |
| app.include_router(websocket_router) | |
| async def root(): | |
| return { | |
| "message": f"Welcome to {settings.PROJECT_NAME} v{settings.VERSION}", | |
| "docs_url": "/docs", | |
| "openapi_url": "/openapi.json" | |
| } |