fa45d8aa5f
- health_checklist.json: 192.168.1.122→node122
- ocr_client.py: docstring IP→node122
- docs/market-data-requirements.md: IP→node122
- 所有API调用通过ProxyHandler({})绕过系统代理
Privoxy对node122:18003返回500,直连正常
91 lines
3.0 KiB
Python
91 lines
3.0 KiB
Python
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
|
|
from __future__ import annotations
|
|
|
|
import typing
|
|
import threading
|
|
|
|
from ._exceptions import WebSocketQueueFullError
|
|
|
|
|
|
class SendQueue:
|
|
"""Bounded byte-size queue for outgoing WebSocket messages.
|
|
|
|
Messages are stored as pre-serialized strings. The queue enforces a
|
|
maximum byte budget so that unbounded buffering cannot occur during
|
|
reconnection windows.
|
|
"""
|
|
|
|
def __init__(self, max_bytes: int = 1_048_576) -> None:
|
|
self._queue: list[tuple[str, int]] = [] # (data, byte_length)
|
|
self._bytes: int = 0
|
|
self._max_bytes = max_bytes
|
|
self._lock = threading.Lock()
|
|
|
|
def enqueue(self, data: str) -> None:
|
|
"""Append *data* to the queue.
|
|
|
|
Raises :class:`WebSocketQueueFullError` if the message would
|
|
exceed the byte-size limit.
|
|
"""
|
|
byte_length = len(data.encode("utf-8"))
|
|
with self._lock:
|
|
if self._bytes + byte_length > self._max_bytes:
|
|
raise WebSocketQueueFullError("send queue is full, message discarded")
|
|
self._queue.append((data, byte_length))
|
|
self._bytes += byte_length
|
|
|
|
def flush_sync(self, send: typing.Callable[[str], object]) -> None:
|
|
"""Send every queued message via *send*.
|
|
|
|
If *send* raises, the failing message and all subsequent messages
|
|
are re-queued and the error is re-raised.
|
|
"""
|
|
with self._lock:
|
|
pending = list(self._queue)
|
|
self._queue.clear()
|
|
self._bytes = 0
|
|
|
|
for i, (data, _byte_length) in enumerate(pending):
|
|
try:
|
|
send(data)
|
|
except Exception:
|
|
with self._lock:
|
|
remaining = pending[i:]
|
|
self._queue = remaining + self._queue
|
|
self._bytes = sum(bl for _, bl in self._queue)
|
|
raise
|
|
|
|
async def flush_async(self, send: typing.Callable[[str], typing.Awaitable[object]]) -> None:
|
|
"""Async variant of :meth:`flush_sync`."""
|
|
with self._lock:
|
|
pending = list(self._queue)
|
|
self._queue.clear()
|
|
self._bytes = 0
|
|
|
|
for i, (data, _byte_length) in enumerate(pending):
|
|
try:
|
|
await send(data)
|
|
except Exception:
|
|
with self._lock:
|
|
remaining = pending[i:]
|
|
self._queue = remaining + self._queue
|
|
self._bytes = sum(bl for _, bl in self._queue)
|
|
raise
|
|
|
|
def drain(self) -> list[str]:
|
|
"""Remove and return all queued messages."""
|
|
with self._lock:
|
|
items = [data for data, _ in self._queue]
|
|
self._queue.clear()
|
|
self._bytes = 0
|
|
return items
|
|
|
|
def __len__(self) -> int:
|
|
with self._lock:
|
|
return len(self._queue)
|
|
|
|
def __bool__(self) -> bool:
|
|
with self._lock:
|
|
return len(self._queue) > 0
|