async def do_request(self, method, url, data=None, json=True, headers=None, ignore_failure=False): loop = asyncio.get_event_loop() if not headers: headers = self._authentication_client.session.headers try: if data is None: data = {} params = { "method": method, "url": url, "data": data, "timeout": self._authentication_client.timeout, "headers": headers } try: response = await loop.run_in_executor(None, functools.partial(self._authentication_client.session.request, **params)) except (requests.Timeout, requests.ConnectTimeout, requests.ReadTimeout): logging.debug(f'Request to {url} timed out') raise BackendTimeout() except requests.ConnectionError: raise NetworkError if not ignore_failure: logging.debug(f'Request to {url} responsed with status code {response.status_code}') self.handle_status_code(response.status_code) if json: return response.json() else: return response except Exception as e: raise e
async def authenticate(self, stored_credentials=None): if not stored_credentials: self.create_task(self._steam_client.run(), "Run WebSocketClient") return next_step_response(START_URI.LOGIN, END_URI.LOGIN_FINISHED) # TODO remove at some point, old refresh flow cookies = stored_credentials.get("cookies", []) if cookies: morsels = parse_stored_cookies(cookies) return await self._do_steamcommunity_auth(morsels) self._user_info_cache.from_dict(stored_credentials) if 'games' in self.persistent_cache: self._games_cache.loads(self.persistent_cache['games']) self.create_task(self._steam_client.run(), "Run WebSocketClient") try: await asyncio.wait_for(self._user_info_cache.initialized.wait(), 60) except asyncio.TimeoutError: self.check_for_websocket_errors() raise BackendTimeout() self.store_credentials(self._user_info_cache.to_dict()) return Authentication(self._user_info_cache.steam_id, self._user_info_cache.persona_name)
def handle_exception(): """ Context manager translating network related exceptions to custom :mod:`~galaxy.api.errors`. """ try: yield except asyncio.TimeoutError: raise BackendTimeout() except aiohttp.ServerDisconnectedError: raise BackendNotAvailable() except aiohttp.ClientConnectionError: raise NetworkError() except aiohttp.ContentTypeError as error: raise UnknownBackendResponse(error.message) except aiohttp.ClientResponseError as error: if error.status == HTTPStatus.UNAUTHORIZED: raise AuthenticationRequired(error.message) if error.status == HTTPStatus.FORBIDDEN: raise AccessDenied(error.message) if error.status == HTTPStatus.SERVICE_UNAVAILABLE: raise BackendNotAvailable(error.message) if error.status == HTTPStatus.TOO_MANY_REQUESTS: raise TooManyRequests(error.message) if error.status >= 500: raise BackendError(error.message) if error.status >= 400: logger.warning("Got status %d while performing %s request for %s", error.status, error.request_info.method, str(error.request_info.url)) raise UnknownError(error.message) except aiohttp.ClientError as e: logger.exception("Caught exception while performing request") raise UnknownError(repr(e))
async def authenticate(self, stored_credentials=None): if not stored_credentials: self.create_task(self._steam_client.run(), "Run WebSocketClient") return next_step_response(START_URI.LOGIN, END_URI.LOGIN_FINISHED) # TODO remove at some point, old refresh flow cookies = stored_credentials.get("cookies", []) if cookies: morsels = parse_stored_cookies(cookies) return await self._do_steamcommunity_auth(morsels) self._user_info_cache.from_dict(stored_credentials) if 'games' in self.persistent_cache: self._games_cache.loads(self.persistent_cache['games']) steam_run_task = self.create_task(self._steam_client.run(), "Run WebSocketClient") connection_timeout = 30 try: await asyncio.wait_for(self._user_info_cache.initialized.wait(), connection_timeout) except asyncio.TimeoutError: try: self.raise_websocket_errors() except BackendError as e: logging.info(f"Unable to keep connection with steam backend {repr(e)}") except Exception as e: logging.info(f"Internal websocket exception caught during auth {repr(e)}") await self.cancel_task(steam_run_task) raise logging.info(f"Failed to initialize connection with steam client within {connection_timeout} seconds") await self.cancel_task(steam_run_task) raise BackendTimeout() self.store_credentials(self._user_info_cache.to_dict()) return Authentication(self._user_info_cache.steam_id, self._user_info_cache.persona_name)
async def request(self, method, url, *args, **kwargs): try: response = await self._session.request(method, url, *args, **kwargs) except asyncio.TimeoutError: raise BackendTimeout() except aiohttp.ServerDisconnectedError: raise BackendNotAvailable() except aiohttp.ClientConnectionError: raise NetworkError() except aiohttp.ContentTypeError: raise UnknownBackendResponse() except aiohttp.ClientError: logging.exception( "Caught exception while running {} request for {}".format( method, url)) raise UnknownError() if response.status == HTTPStatus.UNAUTHORIZED: raise AuthenticationRequired() if response.status == HTTPStatus.FORBIDDEN: raise AccessDenied() if response.status == HTTPStatus.SERVICE_UNAVAILABLE: raise BackendNotAvailable() if response.status == HTTPStatus.TOO_MANY_REQUESTS: raise TooManyRequests() if response.status >= 500: raise BackendError() if response.status >= 400: logging.warning( "Got status {} while running {} request for {}".format( response.status, method, url)) raise UnknownError() return response
async def _get_websocket_auth_step(self): try: result = await asyncio.wait_for(self._steam_client.communication_queues['plugin'].get(), 60) result = result['auth_result'] except asyncio.TimeoutError: self.raise_websocket_errors() raise BackendTimeout() return result
async def do_request(self, method, url, data=None, json=True, headers=None, ignore_failure=False): loop = asyncio.get_event_loop() if not headers: headers = self._authentication_client.session.headers try: if data is None: data = {} params = { "method": method, "url": url, "data": data, "timeout": self._authentication_client.timeout, "headers": headers } try: response = await loop.run_in_executor( None, functools.partial( self._authentication_client.session.request, **params)) except requests.Timeout: raise BackendTimeout() if not ignore_failure: if response.status_code == HTTPStatus.UNAUTHORIZED: raise AuthenticationRequired() if response.status_code == HTTPStatus.FORBIDDEN: raise AccessDenied() if response.status_code == HTTPStatus.SERVICE_UNAVAILABLE: raise BackendNotAvailable() if response.status_code >= 500: raise BackendError() if response.status_code >= 400: raise UnknownError() if json: return response.json() else: return response except Exception as e: log.exception( f"Request exception: {str(e)}; url: {url}, method: {method}, data: {data}, headers: {headers}" ) raise
async def authenticate(self, stored_credentials=None): if not stored_credentials: self.create_task(self._steam_client.run(), "Run WebSocketClient") return next_step_response(START_URI.LOGIN, END_URI.LOGIN_FINISHED) if stored_credentials.get("cookies", []): logger.error( 'Old http login flow is not unsupported. Please reconnect the plugin' ) raise AccessDenied() self._user_info_cache.from_dict(stored_credentials) if 'games' in self.persistent_cache: self._games_cache.loads(self.persistent_cache['games']) steam_run_task = self.create_task(self._steam_client.run(), "Run WebSocketClient") connection_timeout = 30 try: await asyncio.wait_for(self._user_info_cache.initialized.wait(), connection_timeout) except asyncio.TimeoutError: try: self.raise_websocket_errors() except BackendError as e: logging.info( f"Unable to keep connection with steam backend {repr(e)}") raise except InvalidCredentials: logging.info("Invalid credentials during authentication") raise except Exception as e: logging.info( f"Internal websocket exception caught during auth {repr(e)}" ) raise else: logging.info( f"Failed to initialize connection with steam client within {connection_timeout} seconds" ) raise BackendTimeout() finally: await self.cancel_task(steam_run_task) self.store_credentials(self._user_info_cache.to_dict()) return Authentication(self._user_info_cache.steam_id, self._user_info_cache.persona_name)
async def _request(self, method, *args, **kwargs): try: response = await self._session.request(method, *args, **kwargs) except asyncio.TimeoutError: raise BackendTimeout() except aiohttp.ClientConnectionError: raise NetworkError() logging.debug(f"Request response status: {response.status}") if response.status == HTTPStatus.UNAUTHORIZED: raise AuthenticationRequired() if response.status == HTTPStatus.FORBIDDEN: raise AccessDenied() if response.status == HTTPStatus.SERVICE_UNAVAILABLE: raise BackendNotAvailable() if response.status >= 500: raise BackendError() if response.status >= 400: raise UnknownError() return response
] protocol_client.close.return_value = async_return_value(None) protocol_client.wait_closed.return_value = async_return_value(None) websocket.close.return_value = async_return_value(None) websocket.wait_closed.return_value = async_return_value(None) await client.run() assert servers_cache.get.call_count == 2 assert protocol_client.authenticate.call_count == 2 assert protocol_client.run.call_count == 2 @pytest.mark.asyncio @pytest.mark.parametrize( "exception", [BackendNotAvailable(), BackendTimeout(), BackendError(), NetworkError()]) async def test_servers_cache_retry(client, protocol_client, backend_client, servers_cache, websocket, mocker, exception): servers_cache.get.side_effect = [ async_raise(exception), async_return_value(["wss://abc.com/websocket"]) ] sleep = mocker.patch("protocol.websocket_client.asyncio.sleep", side_effect=lambda x: async_return_value(None)) backend_client.get_authentication_data.return_value = STEAM_ID, ACCOUNT_NAME, TOKEN protocol_client.authenticate.return_value = async_return_value(None) protocol_client.run.return_value = async_raise( websockets.ConnectionClosedOK(1000, ""), 10)
async_raise(websockets.ConnectionClosedError(1002, ""), 10), async_raise(websockets.ConnectionClosedOK(1000, ""), 10) ] protocol_client.close.return_value = async_return_value(None) protocol_client.wait_closed.return_value = async_return_value(None) websocket.close.return_value = async_return_value(None) websocket.wait_closed.return_value = async_return_value(None) await client.run() assert servers_cache.get.call_count == 2 assert protocol_client.authenticate.call_count == 2 assert protocol_client.run.call_count == 2 @pytest.mark.asyncio @pytest.mark.parametrize("exception", [ BackendNotAvailable(), BackendTimeout(), BackendError(), NetworkError() ]) async def test_servers_cache_retry( client, protocol_client, backend_client, servers_cache, websocket, mocker, exception ): servers_cache.get.side_effect = [ async_raise(exception), async_return_value(["wss://abc.com/websocket"]) ] sleep = mocker.patch("protocol.websocket_client.asyncio.sleep", side_effect=lambda x: async_return_value(None)) backend_client.get_authentication_data.return_value = STEAM_ID, ACCOUNT_NAME, TOKEN protocol_client.authenticate.return_value = async_return_value(None) protocol_client.run.return_value = async_raise(websockets.ConnectionClosedOK(1000, ""), 10) await client.run() sleep.assert_any_call(RECONNECT_INTERVAL_SECONDS)