diff --git a/securedrop_client/gui/widgets.py b/securedrop_client/gui/widgets.py index 3cf1b06a63..659c45068b 100644 --- a/securedrop_client/gui/widgets.py +++ b/securedrop_client/gui/widgets.py @@ -230,7 +230,7 @@ def setup(self, controller): self.controller.sync_events.connect(self._on_refresh_complete) def _on_clicked(self): - self.controller.sync_api() + self.controller.sync_api(manual_retry=True) # This is a temporary solution for showing the icon as active for the entire duration of a # refresh, rather than for just the duration of a click. The icon image will be replaced # when the controller tells us the refresh has finished. A cleaner solution would be to diff --git a/securedrop_client/logic.py b/securedrop_client/logic.py index b6dd34491f..5d2b3916fc 100644 --- a/securedrop_client/logic.py +++ b/securedrop_client/logic.py @@ -305,10 +305,12 @@ def completed_api_call(self, thread_id, user_callback): def login(self, username, password, totp): """ - Given a username, password and time based one-time-passcode (TOTP), - create a new instance representing the SecureDrop api and authenticate. + Given a username, password and time based one-time-passcode (TOTP), create a new instance + representing the SecureDrop api and authenticate. - Default to 60 seconds until we implement a better request timeout strategy. + Default to 60 seconds until we implement a better request timeout strategy. We lower the + default_request_timeout for Queue API requests in ApiJobQueue in order to display errors + faster. """ storage.mark_all_pending_drafts_as_failed(self.session) self.api = sdclientapi.API( @@ -377,7 +379,7 @@ def authenticated(self): """ return bool(self.api and self.api.token is not None) - def sync_api(self): + def sync_api(self, manual_retry: bool = False): """ Grab data from the remote SecureDrop API in a non-blocking manner. """ @@ -386,7 +388,13 @@ def sync_api(self): if self.authenticated(): logger.debug("You are authenticated, going to make your call") - self.call_api(storage.get_remote_data, + if manual_retry: + self.call_api(storage.get_remote_data, + self.on_sync_success, + self.on_refresh_failure, + self.api) + else: + self.call_api(storage.get_remote_data, self.on_sync_success, self.on_sync_failure, self.api) @@ -443,8 +451,17 @@ def on_sync_success(self, result) -> None: def on_sync_failure(self, result: Exception) -> None: """ - Called when syncronisation of data via the API fails. + Called when syncronisation of data via the API fails. Just log and try again since this is + a background task. + """ + logger.debug('The SecureDrop server cannot be reached due to Error: {}'.format(result)) + self.sync_api() + + def on_refresh_failure(self, result: Exception) -> None: + """ + Called when syncronisation of data via the API fails after a user manual clicks refresh. """ + logger.debug('The SecureDrop server cannot be reached due to Error: {}'.format(result)) self.gui.update_error_status( _('The SecureDrop server cannot be reached.'), duration=0, diff --git a/securedrop_client/queue.py b/securedrop_client/queue.py index 58aec7f2aa..861a06f76c 100644 --- a/securedrop_client/queue.py +++ b/securedrop_client/queue.py @@ -158,6 +158,16 @@ def logout(self) -> None: def login(self, api_client: API) -> None: logger.debug('Passing API token to queues') + + # Setting realistic (shorter) timeout for general requests so that user feedback is faster. + # General requests includes: + # FileDownloadJob + # MessageDownloadJob + # ReplyDownloadJo + # SendReplyJob + # UpdateStarJob + api_client.default_request_timeout = 5 + self.main_queue.api_client = api_client self.download_file_queue.api_client = api_client self.start_queues()