import os from http import HTTPStatus from logging import Logger from time import sleep from typing import List, Union import requests from apollo_notifications.user_data import exceptions from apollo_notifications.user_data.config import UserDataConfig class BaseUserDataClient: def __init__(self, config: UserDataConfig, logger: Logger): self._inner_api_prefix = "api" self._outer_api_prefix = "user-data-api" self._http_session = None self._logger = logger self._api_key = os.environ.get("USER_DATA_APIKEY", config.USER_DATA_APIKEY) schema = os.environ.get("USER_DATA_SCHEMA", config.USER_DATA_SCHEMA) host = os.environ.get("USER_DATA_HOST", config.USER_DATA_HOST) self._base_url = f"{schema}://{host}" self._app_slug = os.environ.get("USER_DATA_APP_HEADER", config.USER_DATA_APP_HEADER) self._retry_count = int(os.environ.get("USER_DATA_RETRY_COUNT", config.USER_DATA_RETRY_COUNT)) self._retry_delay = int(os.environ.get("USER_DATA_RETRY_DELAY", config.USER_DATA_RETRY_DELAY)) self._timeout = int(os.environ.get("USER_DATA_TIMEOUT", config.USER_DATA_TIMEOUT)) self._batch_size = int(os.environ.get("USER_DATA_BATCH_SIZE", config.USER_DATA_BATCH_SIZE)) @property def http_session(self): if not self._http_session: self._http_session = requests.Session() self._http_session.headers.update({"Authorization": self._api_key}) return self._http_session def _send_request(self, request: requests.Request) -> Union[List[dict], dict]: retry_counter = 0 while True: try: session = self.http_session response = session.send(session.prepare_request(request), timeout=self._timeout) except (ConnectionError, requests.Timeout) as exc: if retry_counter >= self._retry_count: raise exceptions.UserDataUnavailable from exc self._logger.info( f"{retry_counter}/{self._retry_count} Got exception {exc} on request to {request.url}." ) retry_counter += 1 sleep(self._retry_delay * retry_counter) continue try: result = response.json() except ValueError: raise exceptions.UserDataInvalidResponse(status_code=response.status_code) if response.status_code != HTTPStatus.OK: raise exceptions.UserDataInvalidResponse(response_data=result, status_code=response.status_code) return result