SSE Patch 增量推送架构全链路实现
- web/sse_manager.py: asyncio.Queue 连接池 + broadcast + event_stream - web/routers/sse_router.py: GET /api/events + POST /api/internal/collector-patch - weather_sources.py: 采集后 POST patch 给 web - Nginx polyweather.conf: /api/events proxy_buffering off - frontend/api/events/route.ts: Next.js SSE 代理 - frontend/hooks/use-sse-patches.ts: EventSource + useLatestPatch + 重连 - LiveTemperatureThresholdChart: mergePatchIntoHourly 增量合并 - scan-terminal-query: 接入 SSE patch 更新行数据 - 新增 ssePatchArchitecture.test.ts 架构测试
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
"""SSE endpoints for live terminal patch delivery."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from fastapi.responses import StreamingResponse
|
||||
|
||||
from web.sse_manager import sse_manager
|
||||
|
||||
|
||||
router = APIRouter(tags=["events"])
|
||||
|
||||
|
||||
@router.get("/api/events")
|
||||
async def sse_events(request: Request):
|
||||
user_id = getattr(request.state, "auth_user_id", None) or "anon"
|
||||
return StreamingResponse(
|
||||
sse_manager.event_stream(user_id),
|
||||
media_type="text/event-stream",
|
||||
headers={
|
||||
"Cache-Control": "no-cache, no-transform",
|
||||
"Connection": "keep-alive",
|
||||
"X-Accel-Buffering": "no",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.post("/api/internal/collector-patch")
|
||||
async def ingest_patch(patch: dict[str, Any]):
|
||||
city = str(patch.get("city") or "").strip().lower()
|
||||
changes = patch.get("changes")
|
||||
if not city:
|
||||
raise HTTPException(status_code=400, detail="city is required")
|
||||
if not isinstance(changes, dict):
|
||||
raise HTTPException(status_code=400, detail="changes must be an object")
|
||||
event = sse_manager.broadcast(city, changes)
|
||||
return {"ok": True, "revision": event["revision"]}
|
||||
Reference in New Issue
Block a user