closed TG-1; git was inited;

This commit is contained in:
2026-05-04 08:13:38 +03:00
commit bcf20fcb04
105 changed files with 6592 additions and 0 deletions
+73
View File
@@ -0,0 +1,73 @@
"""UDP JSON event publisher on ``127.0.0.1:7001`` (configurable).
Contract: one serialized ``Event`` per UDP datagram. Events larger than
``max_datagram_bytes`` are dropped and counted in
``stats.udp_events_oversize`` (no fragmentation).
"""
from __future__ import annotations
import asyncio
import json
import logging
from typing import Any
from ..config import UdpEventsCfg
from ..core.bus import EventBus
from ..core.models import Event
from ..core.stats import Stats
log = logging.getLogger(__name__)
class UdpEventsPublisher:
def __init__(self, cfg: UdpEventsCfg, bus: EventBus, stats: Stats) -> None:
self._cfg = cfg
self._bus = bus
self._stats = stats
self._transport: asyncio.DatagramTransport | None = None
self._sub: asyncio.Queue[Event] | None = None
async def run(self) -> None:
loop = asyncio.get_running_loop()
# Ephemeral sender socket; we only *send* to a fixed target.
transport, _ = await loop.create_datagram_endpoint(
lambda: asyncio.DatagramProtocol(),
remote_addr=(self._cfg.host, self._cfg.port),
)
self._transport = transport
self._sub = self._bus.subscribe(maxsize=1024)
log.info("udp_events publisher -> %s:%d", self._cfg.host, self._cfg.port)
try:
while True:
ev = await self._sub.get()
self._send(ev)
except asyncio.CancelledError:
raise
finally:
if self._sub is not None:
self._bus.unsubscribe(self._sub)
self._sub = None
if self._transport is not None:
self._transport.close()
self._transport = None
def _send(self, ev: Event) -> None:
try:
blob = json.dumps(ev.to_dict(), ensure_ascii=False, separators=(",", ":")).encode("utf-8")
except Exception:
self._stats.incr("udp_events_serialize_errors")
return
if len(blob) > self._cfg.max_datagram_bytes:
self._stats.incr("udp_events_oversize")
return
try:
assert self._transport is not None
self._transport.sendto(blob)
self._stats.incr("udp_events_sent")
except Exception:
self._stats.incr("udp_events_send_errors")
log.debug("udp_events send failed", exc_info=True)
__all__ = ["UdpEventsPublisher"]