bep40 commited on
Commit
86050f8
·
verified ·
1 Parent(s): 02f2f18

Upload auto_update_sse.py

Browse files
Files changed (1) hide show
  1. auto_update_sse.py +55 -0
auto_update_sse.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Auto-update SSE endpoint for VNEWS - pushes updates when new posts/shorts published."""
2
+ import asyncio
3
+ import json
4
+ import time
5
+ from fastapi import Request
6
+ from fastapi.responses import StreamingResponse
7
+
8
+ # Connected clients queue
9
+ _clients = []
10
+ _lock = asyncio.Lock()
11
+
12
+ async def _notify_clients(event_type: str, data: dict):
13
+ """Send notification to all SSE clients."""
14
+ if not _clients:
15
+ return
16
+ msg = f"data: {json.dumps({'type': event_type, 'data': data, 'ts': int(time.time())})}\n\n"
17
+ async with _lock:
18
+ dead = []
19
+ for q in _clients:
20
+ try:
21
+ await q.put_nowait(msg)
22
+ except asyncio.QueueFull:
23
+ pass
24
+ except:
25
+ dead.append(q)
26
+ for q in dead:
27
+ if q in _clients:
28
+ _clients.remove(q)
29
+
30
+ # Public functions to call from other modules
31
+ notify_new_post = lambda post: asyncio.create_task(_notify_clients("new_post", post)) if post else None
32
+ notify_new_short = lambda post: asyncio.create_task(_notify_clients("new_short", post)) if post else None
33
+
34
+ async def sse_events(request: Request):
35
+ """SSE endpoint for real-time updates on homepage."""
36
+ q = asyncio.Queue(maxsize=10)
37
+ _clients.append(q)
38
+
39
+ async def event_generator():
40
+ try:
41
+ # Send initial connection message
42
+ yield "data: {\"type\":\"connected\",\"ts\":null}\n\n"
43
+ while not await request.is_disconnected():
44
+ try:
45
+ msg = await asyncio.wait_for(q.get(), timeout=25.0)
46
+ yield msg
47
+ except asyncio.TimeoutError:
48
+ yield ":keepalive\n\n"
49
+ except:
50
+ pass
51
+ finally:
52
+ if q in _clients:
53
+ _clients.remove(q)
54
+
55
+ return StreamingResponse(event_generator(), media_type="text/event-stream")