diff --git a/securedrop_client/api_jobs/base.py b/securedrop_client/api_jobs/base.py index 851e903479..e872e490fc 100644 --- a/securedrop_client/api_jobs/base.py +++ b/securedrop_client/api_jobs/base.py @@ -25,7 +25,7 @@ def __init__(self, message: Optional[str] = None) -> None: class PauseQueueJob(QObject): def __init__(self): super().__init__() - self.order_number = 1 + self.order_number = None class ApiJob(QObject): diff --git a/securedrop_client/gui/widgets.py b/securedrop_client/gui/widgets.py index af80fd90bc..343a842f95 100644 --- a/securedrop_client/gui/widgets.py +++ b/securedrop_client/gui/widgets.py @@ -363,10 +363,12 @@ def _on_status_timeout(self): def update_message(self, message: str, duration: int): """ - Display a status message to the user for a given duration. + Display a status message to the user for a given duration. If the duration is zero, + continuously show message. """ self.status_bar.showMessage(message, duration) - self.status_timer.start(duration) + if duration != 0: + self.status_timer.start(duration) self._show() def clear_message(self): diff --git a/securedrop_client/logic.py b/securedrop_client/logic.py index 05c625393d..e98d1f00b4 100644 --- a/securedrop_client/logic.py +++ b/securedrop_client/logic.py @@ -33,6 +33,7 @@ from securedrop_client import db from securedrop_client.api_jobs.downloads import FileDownloadJob, MessageDownloadJob, \ ReplyDownloadJob, DownloadChecksumMismatchException +from securedrop_client.api_jobs.base import PauseQueueJob from securedrop_client.api_jobs.uploads import SendReplyJob, SendReplyJobException from securedrop_client.api_jobs.updatestar import UpdateStarJob, UpdateStarJobException from securedrop_client.crypto import GpgHelper, CryptoError @@ -170,6 +171,7 @@ def __init__(self, hostname: str, gui, session_maker: sessionmaker, # Queue that handles running API job self.api_job_queue = ApiJobQueue(self.api, self.session_maker) + self.api_job_queue.paused.connect(self.on_queue_paused) # Contains active threads calling the API. self.api_threads = {} # type: Dict[str, Dict] @@ -259,6 +261,9 @@ def call_api(self, # Start the thread and related activity. new_api_thread.start() + def on_queue_paused(self) -> None: + self.gui.update_error_status(_('The SecureDrop server cannot be reached.'), duration=0) + def on_api_timeout(self) -> None: self.gui.update_error_status(_('The connection to the SecureDrop server timed out. ' 'Please try again.')) @@ -438,6 +443,7 @@ def on_update_star_success(self, result) -> None: """ self.sync_api() # Syncing the API also updates the source list UI self.gui.clear_error_status() + self.api_job_queue.enqueue(PauseQueueJob()) def on_update_star_failure(self, result: UpdateStarJobException) -> None: """ @@ -480,6 +486,7 @@ def logout(self): self.gui.logout() self.is_authenticated = False + def set_status(self, message, duration=5000): """ Set a textual status message to be displayed to the user for a certain diff --git a/securedrop_client/queue.py b/securedrop_client/queue.py index 9d0a001e62..f5dad5f444 100644 --- a/securedrop_client/queue.py +++ b/securedrop_client/queue.py @@ -1,7 +1,7 @@ import itertools import logging -from PyQt5.QtCore import QObject, QThread, pyqtSlot +from PyQt5.QtCore import QObject, QThread, pyqtSlot, pyqtSignal from queue import PriorityQueue from sdclientapi import API, RequestTimeoutError from sqlalchemy.orm import scoped_session @@ -52,7 +52,7 @@ def process(self) -> None: # pragma: nocover session = self.session_maker() priority, job = self.queue.get(block=True) - if job is PauseQueueJob: + if isinstance(job, PauseQueueJob): logger.info('Paused queue') return @@ -85,8 +85,8 @@ class ApiJobQueue(QObject): # These are the priorities for processing jobs. # Lower numbers corresponds to a higher priority. JOB_PRIORITIES = { + # TokenInvalidationJob: 10, # Not yet implemented PauseQueueJob: 11, - # LogoutJob: 11, # Not yet implemented # MetadataSyncJob: 12, # Not yet implemented FileDownloadJob: 13, # File downloads processed in separate queue MessageDownloadJob: 13, @@ -97,6 +97,11 @@ class ApiJobQueue(QObject): # FlagJob: 16, # Not yet implemented } + ''' + Signal that is emitted if a queue is paused + ''' + paused = pyqtSignal() + def __init__(self, api_client: API, session_maker: scoped_session) -> None: super().__init__(None) self.api_client = api_client @@ -148,7 +153,11 @@ def enqueue(self, job: ApiJob) -> None: priority = self.JOB_PRIORITIES[type(job)] - if isinstance(job, FileDownloadJob): + if isinstance(job, PauseQueueJob): + self.main_queue.add_job(priority, job) + self.download_file_queue.add_job(priority, job) + self.paused.emit() + elif isinstance(job, FileDownloadJob): logger.debug('Adding job to download queue') self.download_file_queue.add_job(priority, job) else: