104 lines
3.1 KiB
Python
104 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
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()
|
|
await approval_service.ensure_approval_subscription()
|
|
|
|
async def handler(payload: dict) -> None:
|
|
logger.info("开始处理飞书事件")
|
|
try:
|
|
event_payload = payload.get("event", payload)
|
|
await approval_service.handle_event(event_payload)
|
|
logger.info("完成处理飞书事件")
|
|
except Exception as exc:
|
|
logger.exception("处理飞书事件异常: %s", exc)
|
|
|
|
ws_client = FeishuWsClient(handler, asyncio.get_running_loop())
|
|
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")
|