approval/app/main.py

97 lines
2.8 KiB
Python

from __future__ import annotations
import logging
import os
import time
import uuid
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from app.api.feishu_events import router as feishu_events_router
from app.api.feishu_external import router as feishu_external_router
from app.api.logs import router as logs_router
from app.api.projects import router as projects_router
from app.clients.feishu_ws_client import FeishuWsClient
from app.config.logging import setup_logging
from app.services.approval_sync_service import ApprovalSyncService
LOG_DIR = "logs"
app = FastAPI()
logger = logging.getLogger(__name__)
access_logger = logging.getLogger("access")
@app.on_event("startup")
async def on_startup() -> None:
os.makedirs(LOG_DIR, exist_ok=True)
setup_logging(LOG_DIR)
approval_service = ApprovalSyncService()
async def handler(payload: dict) -> None:
event_payload = payload.get("event", payload)
await approval_service.handle_event(event_payload)
ws_client = FeishuWsClient(handler)
ws_client.start()
app.state.ws_client = ws_client
@app.on_event("shutdown")
async def on_shutdown() -> None:
ws_client = getattr(app.state, "ws_client", None)
if ws_client:
await ws_client.stop()
@app.middleware("http")
async def request_logging(request: Request, call_next):
request_id = str(uuid.uuid4())
start = time.time()
try:
raw_body = await request.body()
body_text = raw_body.decode("utf-8") if raw_body else ""
except Exception:
body_text = ""
logger.info(
"request_id=%s client=%s method=%s path=%s query=%s body=%s",
request_id,
request.client.host if request.client else "-",
request.method,
request.url.path,
request.url.query,
body_text,
)
try:
response = await call_next(request)
except Exception as exc:
logger.exception("请求异常: %s", exc)
response = JSONResponse(status_code=500, content={"detail": "internal error"})
duration = int((time.time() - start) * 1000)
access_logger.info(
"request_id=%s method=%s path=%s status=%s cost_ms=%s",
request_id,
request.method,
request.url.path,
response.status_code,
duration,
)
return response
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
logger.exception("未处理异常: %s", exc)
return JSONResponse(status_code=500, content={"detail": "internal error"})
app.include_router(feishu_external_router)
app.include_router(feishu_events_router)
app.include_router(logs_router)
app.include_router(projects_router)
app.mount("/logs", StaticFiles(directory="app/static/logs", html=True), name="logs")