import exceptions import time from http import HTTPStatus from typing import Any, Dict, List, Union import requests import config from consts import DEFAULT_COUNTRY_CODE, PLAYLIST_PREFIX from logger import logger class DspClient: def __init__(self, dsp_config: config.Dsp): self._session = None self._api_key = dsp_config.DSPAPI_APPKEY self.retry_count = dsp_config.DSP_RETRY_COUNT self.retry_delay = dsp_config.DSP_RETRY_DELAY self.timeout = dsp_config.DSP_TIMEOUT self.base_url = dsp_config.BASE_URL self.headers = {"Client-Service": config.SERVICE, "Client-Environment": config.ENVIRONMENT} @property def session(self): if not self._session: self._session = requests.Session() self._session.headers.update({"Authorization": self._api_key}) return self._session def _send_request(self, request: requests.Request) -> Union[List[dict], dict]: request_method = request.method retry_counter = 0 result = None while True: try: session = self.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.DspUnavailable retry_counter += 1 logger.info(f"Got exception {exc} on request to {request.url}. Request retry #{retry_counter}.") continue if response.status_code == HTTPStatus.UNAUTHORIZED: if retry_counter >= self.retry_count: raise exceptions.DspUnauthorized retry_counter += 1 logger.info(f"Got unauthorized on request to {request.url}. Request retry #{retry_counter}.") continue if response.status_code == HTTPStatus.TOO_MANY_REQUESTS: if retry_counter >= self.retry_count: raise exceptions.DspInvalidResponse(status_code=response.status_code) retry_counter += 1 logger.info( f"Too many requests from {request.url}. " f"Request retry #{retry_counter} after waiting for { self.retry_delay}." ) time.sleep(self.retry_delay) continue if request_method == "GET": try: result = response.json() except ValueError: raise exceptions.DspInvalidResponse(status_code=response.status_code) if response.status_code != HTTPStatus.OK: raise exceptions.DspInvalidResponse(response_data=result, status_code=response.status_code) return result def get_streams_list( self, playlist_id: str, start_date, end_date, country_code=DEFAULT_COUNTRY_CODE, sort_order="asc", sort_by="date", group_by="date", agg_by="isrc", ) -> List[Dict[str, Any]]: """Returns list of track streams data aggregated by isrc for particular playlist in specific date range.""" url = self.base_url + "/api/delphi/streams" params = { "playlist_id": PLAYLIST_PREFIX + playlist_id, "start_date": start_date, "end_date": end_date, "country_code": country_code, "sort_order": sort_order, "sort_by": sort_by, "group_by": group_by, "agg_by": agg_by, } request = requests.Request("GET", url, params=params) response = self._send_request(request) return response