async def _api_request(self, method: str, endpoint: str, params: Optional[Dict[str, Any]] = None, is_auth_required: bool = False, try_count: int = 0) -> Dict[str, Any]: """ Sends an aiohttp request and waits for a response. :param method: The HTTP method, e.g. get or post :param endpoint: The path url or the API end point :param params: Additional get/post parameters :param is_auth_required: Whether an authentication is required, when True the function will add encrypted signature to the request. :returns A response in json format. """ url = f"{Constants.REST_URL}/{endpoint}" shared_client = await self._http_client() # Turn `params` into either GET params or POST body data qs_params: dict = params if method.upper() == "GET" else None req_form = aiohttp.FormData(params) if method.upper( ) == "POST" and params is not None else None # Generate auth headers if needed. headers: dict = {"Content-Type": "application/x-www-form-urlencoded"} if is_auth_required: headers: dict = self._hitbtc_auth.get_headers( method, f"{Constants.REST_URL_AUTH}/{endpoint}", params) # Build request coro response_coro = shared_client.request( method=method.upper(), url=url, headers=headers, params=qs_params, data=req_form, timeout=Constants.API_CALL_TIMEOUT) http_status, parsed_response, request_errors = await aiohttp_response_with_errors( response_coro) if request_errors or parsed_response is None: if try_count < Constants.API_MAX_RETRIES: try_count += 1 time_sleep = retry_sleep_time(try_count) self.logger().info( f"Error fetching data from {url}. HTTP status is {http_status}. " f"Retrying in {time_sleep:.0f}s.") await asyncio.sleep(time_sleep) return await self._api_request( method=method, endpoint=endpoint, params=params, is_auth_required=is_auth_required, try_count=try_count) else: raise HitbtcAPIError({ "error": parsed_response, "status": http_status }) if "error" in parsed_response: raise HitbtcAPIError(parsed_response) return parsed_response
async def connect(self): self._client = await websockets.connect(self._WS_URL) # if auth class was passed into websocket class # we need to emit authenticated requests if self._isPrivate: auth_params = self._auth.generate_auth_dict_ws(self.generate_request_id()) await self._emit("login", auth_params, no_id=True) raw_msg_str: str = await asyncio.wait_for(self._client.recv(), timeout=Constants.MESSAGE_TIMEOUT) json_msg = json.loads(raw_msg_str) if json_msg.get("result") is not True: err_msg = json_msg.get('error', {}).get('message') raise HitbtcAPIError({"error": f"Failed to authenticate to websocket - {err_msg}."}) return self._client