from __future__ import annotations import httpx from .config import ServerConfig class TuxDmxMidiClient: def __init__(self, server: ServerConfig, timeout: float = 5.0) -> None: self._server = server self._timeout = timeout @property def headers(self) -> dict[str, str]: return { "Authorization": f"Bearer {self._server.api_token}", "Content-Type": "application/json", } @property def heartbeat_url(self) -> str: return f"{self._server.url}/heartbeat" @property def events_url(self) -> str: return f"{self._server.url}/events" async def send_heartbeat(self, payload: dict[str, object]) -> dict[str, object]: async with httpx.AsyncClient(timeout=self._timeout, verify=self._server.verify_tls) as client: response = await client.post(self.heartbeat_url, headers=self.headers, json=payload) response.raise_for_status() return response.json() async def send_event(self, payload: dict[str, object]) -> dict[str, object]: async with httpx.AsyncClient(timeout=self._timeout, verify=self._server.verify_tls) as client: response = await client.post(self.events_url, headers=self.headers, json=payload) response.raise_for_status() return response.json() async def test_connection(self, bridge_id: str, device_name: str) -> dict[str, object]: return await self.send_heartbeat( { "type": "heartbeat", "protocol_version": 1, "bridge_id": bridge_id, "device": device_name, } ) def reconnect_delay(attempt: int, base_seconds: float) -> float: return min(base_seconds * max(1, attempt), 30.0)