Skip to content

Commit

Permalink
Improve error handling upon API errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkwouter committed Jun 22, 2022
1 parent 8bc638e commit 5ab2fe5
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- Fix changing installation path causing crashes in rare cases (thanks to makson96)
- Fall back to English when locale cannot be determined (thanks to flagrama)
- Add gettext to build dependencies (thanks to larslindq)
- Improve error handling upon API errors

- Add Greek translation (thanks to Pyrofanis)
- Add Spanish (Spain) translation (thanks to mbarrio)
Expand Down
65 changes: 41 additions & 24 deletions minigalaxy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,14 @@ def get_download_file_md5(self, url):
:return: the md5 sum as string
"""
result = ""
checksum_data = self.__request(url)
if 'checksum' in checksum_data.keys() and len(checksum_data['checksum']) > 0:
xml_data = self.__get_xml_checksum(checksum_data['checksum'])
if "md5" in xml_data.keys() and len(xml_data["md5"]) > 0:
result = xml_data["md5"]

try:
checksum_data = self.__request(url)
if 'checksum' in checksum_data.keys() and len(checksum_data['checksum']) > 0:
xml_data = self.__get_xml_checksum(checksum_data['checksum'])
if "md5" in xml_data.keys() and len(xml_data["md5"]) > 0:
result = xml_data["md5"]
except requests.exceptions.RequestException as e:
print("Couldn't retrieve md5. Encountered HTTP exception: {}".format(e))
if not result:
print("Couldn't find md5 in xml checksum data")

Expand All @@ -204,26 +206,32 @@ def get_file_size(self, url):

return result

def __get_xml_checksum(self, url):
@staticmethod
def __get_xml_checksum(url):
result = {}
response = SESSION.get(url)
if response.status_code == http.HTTPStatus.OK and len(response.text) > 0:
response_object = ET.fromstring(response.text)
if response_object and response_object.attrib:
result = response_object.attrib
else:
print("Couldn't read xml data. Response with code {} received with the following content: {}".format(
response.status_code, response.text
))
return result
try:
response = SESSION.get(url)
if response.status_code == http.HTTPStatus.OK and len(response.text) > 0:
response_object = ET.fromstring(response.text)
if response_object and response_object.attrib:
result = response_object.attrib
else:
print("Couldn't read xml data. Response with code {} received with the following content: {}".format(
response.status_code, response.text
))
except requests.exceptions.RequestException as e:
print("Couldn't read xml data. Received RequestException : {}".format(e))
finally:
return result

def get_user_info(self) -> str:
username = Config.get("username")
if not username:
url = "https://embed.gog.com/userData.json"
response = self.__request(url)
username = response["username"]
Config.set("username", username)
if "username" in response.keys():
username = response["username"]
Config.set("username", username)
return username

def get_version(self, game: Game, gameinfo=None, dlc_name="") -> str:
Expand Down Expand Up @@ -269,13 +277,22 @@ def __request(self, url: str = None, params: dict = None) -> dict:
headers = {
'Authorization': "Bearer {}".format(str(self.active_token)),
}
response = SESSION.get(url, headers=headers, params=params)
if self.debug:
result = {}
try:
response = SESSION.get(url, headers=headers, params=params)
if self.debug:
print("Request: {}".format(url))
print("Return code: {}".format(response.status_code))
print("Response body: {}".format(response.text))
print("")
if response.status_code < 300:
result = response.json()
except requests.exceptions.RequestException as e:
print("Encountered exception while making HTTP request.")
print("Request: {}".format(url))
print("Return code: {}".format(response.status_code))
print("Response body: {}".format(response.text))
print("Exception: {}".format(e))
print("")
return response.json()
return result

@staticmethod
def __request_gamesdb(game: Game):
Expand Down
4 changes: 2 additions & 2 deletions minigalaxy/download_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import threading
import queue

from requests.exceptions import ConnectionError
from requests.exceptions import RequestException
from minigalaxy.config import Config
from minigalaxy.constants import DOWNLOAD_CHUNK_SIZE, MINIMUM_RESUME_SIZE, SESSION
from minigalaxy.download import Download
Expand Down Expand Up @@ -85,7 +85,7 @@ def __download_file(self, download):
start_point, download_mode = self.get_start_point_and_download_mode(download)
result = self.download_operation(download, start_point, download_mode)
break
except ConnectionError as e:
except RequestException as e:
print(e)
download_attempt += 1
# Successful downloads
Expand Down
1 change: 1 addition & 0 deletions minigalaxy/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def check_diskspace(required_size, location):
def install_game(game, installer): # noqa: C901
error_message = ""
tmp_dir = ""
print("Installing {}".format(game.name))
if not error_message:
error_message = verify_installer_integrity(game, installer)
if not error_message:
Expand Down
2 changes: 1 addition & 1 deletion minigalaxy/ui/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def __init__(self, name="Minigalaxy"):
self.__authenticate()
self.HeaderBar.set_subtitle(self.api.get_user_info())
except Exception as e:
print(e)
print("Starting in offline mode, after receiving exception: {}".format(e))
self.offline = True
self.sync_library()

Expand Down
53 changes: 53 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def test1_get_library(self):
response_mock = MagicMock()
response_mock.json.return_value = response_dict
m_constants.SESSION.get.return_value = response_mock
m_constants.SESSION.get().status_code = http.HTTPStatus.OK
exp = "Neverwinter Nights: Enhanced Edition"
retrieved_games, err_msg = api.get_library()
obs = retrieved_games[0].name
Expand Down Expand Up @@ -232,6 +233,26 @@ def test_get_file_size_returns_zero_on_response_error(self):
obs = api.get_file_size("url")
self.assertEqual(exp, obs)

def test_get_file_size_returns_zero_on_request_exception(self):
api = Api()
api._Api__request = MagicMock()
api._Api__request.return_value = {"checksum": "url"}
m_constants.SESSION.get.side_effect = requests.exceptions.RequestException("test")

exp = 0
obs = api.get_file_size("url")
self.assertEqual(exp, obs)

def test_get_file_size_returns_zero_on_request_timeout_exception(self):
api = Api()
api._Api__request = MagicMock()
api._Api__request.return_value = {"checksum": "url"}
m_constants.SESSION.get.side_effect = requests.exceptions.ReadTimeout("test")

exp = 0
obs = api.get_file_size("url")
self.assertEqual(exp, obs)

def test_get_file_size_returns_zero_on_missing_total_size(self):
api = Api()
api._Api__request = MagicMock()
Expand Down Expand Up @@ -281,6 +302,38 @@ def test3_get_gamesdb_info_no_genre(self):
obs = api.get_gamesdb_info(test_game)
self.assertEqual(exp, obs)

def test_get_user_info_from_api(self):
username = "test"
api = Api()
api._Api__request = MagicMock()
api._Api__request.return_value = {"username": username}
m_config.Config.get.return_value = ""
m_constants.SESSION.get.side_effect = MagicMock()
m_constants.SESSION.get().status_code = http.HTTPStatus.OK

obs = api.get_user_info()
self.assertEqual(username, obs)

def test_get_user_info_from_config(self):
username = "test"
api = Api()
api._Api__request = MagicMock()
api._Api__request.return_value = {"username": "wrong"}
m_config.Config.get.return_value = username

obs = api.get_user_info()
self.assertEqual(username, obs)

def test_get_user_info_return_empty_string_when_nothing_is_returned(self):
api = Api()
api._Api__request = MagicMock()
api._Api__request.return_value = {}
m_config.Config.get.return_value = ""

exp = ""
obs = api.get_user_info()
self.assertEqual(exp, obs)


del sys.modules['minigalaxy.constants']
del sys.modules['minigalaxy.config']
Expand Down

0 comments on commit 5ab2fe5

Please sign in to comment.