Files
dzentra_bot/app/src/integrations/exchange/rest_client.py

63 lines
2.1 KiB
Python

from __future__ import annotations
import json
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
from src.core.config import load_settings
from src.integrations.exchange.exceptions import (
ExchangeConnectionError,
ExchangeResponseError,
)
class ExchangeRestClient:
def __init__(self) -> None:
self.settings = load_settings()
if not self.settings.exchange_base_url:
raise ExchangeConnectionError("EXCHANGE_BASE_URL is empty.")
self.base_url = self.settings.exchange_base_url.rstrip("/")
self.timeout = self.settings.exchange_timeout_sec
def get_json(self, path: str, params: dict[str, str] | None = None) -> dict:
query = f"?{urlencode(params)}" if params else ""
url = f"{self.base_url}{path}{query}"
request = Request(
url=url,
method="GET",
headers={
"Accept": "application/json",
"User-Agent": "dzentra-bot/2.0.0",
},
)
try:
with urlopen(request, timeout=self.timeout) as response:
status = getattr(response, "status", 200)
body = response.read().decode("utf-8")
except HTTPError as exc:
raise ExchangeResponseError(
f"HTTP {exc.code} from exchange: {exc.reason}"
) from exc
except URLError as exc:
raise ExchangeConnectionError(
f"Network error while calling exchange: {exc.reason}"
) from exc
except TimeoutError as exc:
raise ExchangeConnectionError("Timeout while calling exchange.") from exc
if status != 200:
raise ExchangeResponseError(f"Unexpected HTTP status: {status}")
try:
payload = json.loads(body)
except json.JSONDecodeError as exc:
raise ExchangeResponseError("Exchange returned non-JSON response.") from exc
if not isinstance(payload, dict):
raise ExchangeResponseError("Exchange response is not a JSON object.")
return payload