Beispiel #1
0
    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)
Beispiel #3
0
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))
Beispiel #4
0
    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
Beispiel #6
0
 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
Beispiel #7
0
    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
Beispiel #8
0
    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)
Beispiel #9
0
    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)
Beispiel #11
0
        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)