File size: 1,076 Bytes
ccad007
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
"""SSE generator 辅助. 提供 ping / retry / error 处理."""
from __future__ import annotations

import asyncio
import json
import logging
from collections.abc import AsyncIterator

from app.streaming.events import sse_format, sse_heartbeat

logger = logging.getLogger(__name__)


async def heartbeat_pinger(interval: float = 15.0) -> AsyncIterator[str]:
    """无限流式发送 SSE 注释保活. 配合 `asyncio.Queue` 一起使用."""
    try:
        while True:
            await asyncio.sleep(interval)
            yield sse_heartbeat()
    except asyncio.CancelledError:
        return


async def event_stream(
    queue: asyncio.Queue[tuple[str, dict] | None],
) -> AsyncIterator[str]:
    """从 asyncio.Queue 读取事件并序列化为 SSE. 收到 None 表示结束."""
    while True:
        item = await queue.get()
        if item is None:
            break
        event, data = item
        yield sse_format(event, data)


def safe_json(data: dict) -> str:
    """防御性 JSON 序列化."""
    return json.dumps(data, ensure_ascii=False, default=str)