Просмотр исходного кода

Refactor the create backup implementation to CreateBackupJob

Nino van Hooff 5 лет назад
Родитель
Сommit
ed5c2b3f43

+ 122 - 0
plugins/CuraDrive/src/CreateBackupJob.py

@@ -0,0 +1,122 @@
+# Copyright (c) 2018 Ultimaker B.V.
+# Cura is released under the terms of the LGPLv3 or higher.
+import json
+import threading
+from typing import Any, Dict, Optional
+
+from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
+from datetime import datetime
+
+from UM.Job import Job
+from UM.Logger import Logger
+from UM.Message import Message
+from UM.TaskManagement.HttpRequestManager import HttpRequestManager
+from UM.TaskManagement.HttpRequestScope import JsonDecoratorScope
+
+from UM.i18n import i18nCatalog
+from cura.CuraApplication import CuraApplication
+from plugins.Toolbox.src.UltimakerCloudScope import UltimakerCloudScope
+
+catalog = i18nCatalog("cura")
+
+
+class CreateBackupJob(Job):
+    """Creates backup zip, requests upload url and uploads the backup file to cloud storage."""
+
+    MESSAGE_TITLE = catalog.i18nc("@info:title", "Backups")
+
+    def __init__(self, api_backup_url: str) -> None:
+        """ Create a new backup Job. start the job by calling start()
+
+        :param api_backup_url: The url of the 'backups' endpoint of the Cura Drive Api
+        """
+
+        super().__init__()
+
+        self._api_backup_url = api_backup_url
+        self._jsonCloudScope = JsonDecoratorScope(UltimakerCloudScope(CuraApplication.getInstance()))
+
+
+        self._backup_zip = None
+        self._upload_success = False
+        self._upload_success_available = threading.Event()
+        self.backup_upload_error_message = ""
+
+    def run(self) -> None:
+        upload_message = Message(catalog.i18nc("@info:backup_status", "Creating your backup..."), title = self.MESSAGE_TITLE, progress = -1)
+        upload_message.show()
+        CuraApplication.getInstance().processEvents()
+        cura_api = CuraApplication.getInstance().getCuraAPI()
+        self._backup_zip, backup_meta_data = cura_api.backups.createBackup()
+
+        if not self._backup_zip or not backup_meta_data:
+            self.backup_upload_error_message = "Could not create backup."
+            upload_message.hide()
+            return
+
+        upload_message.setText(catalog.i18nc("@info:backup_status", "Uploading your backup..."))
+        CuraApplication.getInstance().processEvents()
+
+        # Create an upload entry for the backup.
+        timestamp = datetime.now().isoformat()
+        backup_meta_data["description"] = "{}.backup.{}.cura.zip".format(timestamp, backup_meta_data["cura_release"])
+        self._requestUploadSlot(backup_meta_data, len(self._backup_zip))
+
+        self._upload_success_available.wait()
+        upload_message.hide()
+
+    def _requestUploadSlot(self, backup_metadata: Dict[str, Any], backup_size: int) -> None:
+        """Request a backup upload slot from the API.
+
+        :param backup_metadata: A dict containing some meta data about the backup.
+        :param backup_size: The size of the backup file in bytes.
+        :return: The upload URL for the actual backup file if successful, otherwise None.
+        """
+
+        payload = json.dumps({"data": {"backup_size": backup_size,
+                                       "metadata": backup_metadata
+                                       }
+                              }).encode()
+
+        HttpRequestManager.getInstance().put(
+            self._api_backup_url,
+            data = payload,
+            callback = self._onUploadSlotCompleted,
+            error_callback = self._onUploadSlotCompleted,
+            scope = self._jsonCloudScope)
+
+    def _onUploadSlotCompleted(self, reply: QNetworkReply, error: Optional["QNetworkReply.NetworkError"] = None) -> None:
+        if error is not None:
+            Logger.warning(str(error))
+            self.backup_upload_error_message = "Could not upload backup."
+            self._upload_success_available.set()
+            return
+        if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) >= 300:
+            Logger.warning("Could not request backup upload: %s", HttpRequestManager.readText(reply))
+            self.backup_upload_error_message = "Could not upload backup."
+            self._upload_success_available.set()
+            return
+
+        backup_upload_url = HttpRequestManager.readJSON(reply)["data"]["upload_url"]
+
+        # Upload the backup to storage.
+        HttpRequestManager.getInstance().put(
+            backup_upload_url,
+            data=self._backup_zip,
+            callback=self._uploadFinishedCallback,
+            error_callback=self._uploadFinishedCallback
+        )
+
+    def _uploadFinishedCallback(self, reply: QNetworkReply, error: QNetworkReply.NetworkError = None):
+        self.backup_upload_error_text = HttpRequestManager.readText(reply)
+
+        if HttpRequestManager.replyIndicatesSuccess(reply, error):
+            self._upload_success = True
+            Message(catalog.i18nc("@info:backup_status", "Your backup has finished uploading."), title = self.MESSAGE_TITLE).show()
+        else:
+            self.backup_upload_error_text = self.backup_upload_error_text
+            Logger.log("w", "Could not upload backup file: %s", self.backup_upload_error_text)
+            Message(catalog.i18nc("@info:backup_status", "There was an error while uploading your backup."),
+                    title=self.MESSAGE_TITLE).show()
+
+        self._upload_success_available.set()

+ 7 - 62
plugins/CuraDrive/src/DriveApiService.py

@@ -3,8 +3,6 @@
 
 import base64
 import hashlib
-import json
-from datetime import datetime
 from tempfile import NamedTemporaryFile
 from typing import Any, Optional, List, Dict, Callable
 
@@ -17,7 +15,7 @@ from plugins.Toolbox.src.UltimakerCloudScope import UltimakerCloudScope
 
 from PyQt5.QtNetwork import QNetworkReply, QNetworkRequest
 
-from .UploadBackupJob import UploadBackupJob
+from .CreateBackupJob import CreateBackupJob
 from .Settings import Settings
 
 from UM.i18n import i18nCatalog
@@ -40,21 +38,20 @@ class DriveApiService:
     def __init__(self) -> None:
         self._cura_api = CuraApplication.getInstance().getCuraAPI()
         self._jsonCloudScope = JsonDecoratorScope(UltimakerCloudScope(CuraApplication.getInstance()))
-        self._current_backup_zip_file = None
-
-        self.creatingStateChanged.connect(self._creatingStateChanged)
 
     def getBackups(self, changed: Callable[[List], None]):
         def callback(reply: QNetworkReply, error: Optional["QNetworkReply.NetworkError"] = None):
             if error is not None:
                 Logger.log("w", "Could not get backups: " + str(error))
                 changed([])
+                return
 
             backup_list_response = HttpRequestManager.readJSON(reply)
             if "data" not in backup_list_response:
                 Logger.log("w", "Could not get backups from remote, actual response body was: %s",
                            str(backup_list_response))
                 changed([])  # empty list of backups
+                return
 
             changed(backup_list_response["data"])
 
@@ -67,20 +64,11 @@ class DriveApiService:
 
     def createBackup(self) -> None:
         self.creatingStateChanged.emit(is_creating = True)
+        upload_backup_job = CreateBackupJob(self.BACKUP_URL)
+        upload_backup_job.finished.connect(self._onUploadFinished)
+        upload_backup_job.start()
 
-        # Create the backup.
-        backup_zip_file, backup_meta_data = self._cura_api.backups.createBackup()
-        if not backup_zip_file or not backup_meta_data:
-            self.creatingStateChanged.emit(is_creating = False, error_message ="Could not create backup.")
-            return
-
-        # Create an upload entry for the backup.
-        timestamp = datetime.now().isoformat()
-        backup_meta_data["description"] = "{}.backup.{}.cura.zip".format(timestamp, backup_meta_data["cura_release"])
-        self._requestBackupUpload(backup_meta_data, len(backup_zip_file))
-        self._current_backup_zip_file = backup_zip_file
-
-    def _onUploadFinished(self, job: "UploadBackupJob") -> None:
+    def _onUploadFinished(self, job: "CreateBackupJob") -> None:
         if job.backup_upload_error_message != "":
             # If the job contains an error message we pass it along so the UI can display it.
             self.creatingStateChanged.emit(is_creating = False, error_message = job.backup_upload_error_message)
@@ -167,46 +155,3 @@ class DriveApiService:
 
     def _onDeleteRequestCompleted(self, reply: QNetworkReply, error: Optional["QNetworkReply.NetworkError"] = None, callable = None):
         callable(HttpRequestManager.replyIndicatesSuccess(reply, error))
-
-    def _requestBackupUpload(self, backup_metadata: Dict[str, Any], backup_size: int) -> None:
-        """Request a backup upload slot from the API.
-
-        :param backup_metadata: A dict containing some meta data about the backup.
-        :param backup_size: The size of the backup file in bytes.
-        :return: The upload URL for the actual backup file if successful, otherwise None.
-        """
-
-        payload = json.dumps({"data": {"backup_size": backup_size,
-                                       "metadata": backup_metadata
-                                       }
-                              }).encode()
-
-        HttpRequestManager.getInstance().put(
-            self.BACKUP_URL,
-            data = payload,
-            callback = self._onBackupUploadSlotCompleted,
-            error_callback = self._onBackupUploadSlotCompleted,
-            scope = self._jsonCloudScope)
-
-    def _onBackupUploadSlotCompleted(self, reply: QNetworkReply, error: Optional["QNetworkReply.NetworkError"] = None) -> None:
-        if error is not None:
-            Logger.warning(str(error))
-            self.creatingStateChanged.emit(is_creating=False, error_message="Could not upload backup.")
-            return
-        if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) >= 300:
-            Logger.warning("Could not request backup upload: %s", HttpRequestManager.readText(reply))
-            self.creatingStateChanged.emit(is_creating=False, error_message="Could not upload backup.")
-            return
-
-        backup_upload_url = HttpRequestManager.readJSON(reply)["data"]["upload_url"]
-
-        # Upload the backup to storage.
-        upload_backup_job = UploadBackupJob(backup_upload_url, self._current_backup_zip_file)
-        upload_backup_job.finished.connect(self._onUploadFinished)
-        upload_backup_job.start()
-
-    def _creatingStateChanged(self, is_creating: bool = False, error_message: str = None) -> None:
-        """Cleanup after a backup is not needed anymore"""
-
-        if not is_creating:
-            self._current_backup_zip_file = None

+ 0 - 39
plugins/CuraDrive/src/UploadBackupJob.py

@@ -1,39 +0,0 @@
-# Copyright (c) 2018 Ultimaker B.V.
-# Cura is released under the terms of the LGPLv3 or higher.
-
-import requests
-
-from UM.Job import Job
-from UM.Logger import Logger
-from UM.Message import Message
-
-from UM.i18n import i18nCatalog
-catalog = i18nCatalog("cura")
-
-
-class UploadBackupJob(Job):
-    MESSAGE_TITLE = catalog.i18nc("@info:title", "Backups")
-
-    # This job is responsible for uploading the backup file to cloud storage.
-    # As it can take longer than some other tasks, we schedule this using a Cura Job.
-    def __init__(self, signed_upload_url: str, backup_zip: bytes) -> None:
-        super().__init__()
-        self._signed_upload_url = signed_upload_url
-        self._backup_zip = backup_zip
-        self._upload_success = False
-        self.backup_upload_error_message = ""
-
-    def run(self) -> None:
-        upload_message = Message(catalog.i18nc("@info:backup_status", "Uploading your backup..."), title = self.MESSAGE_TITLE, progress = -1)
-        upload_message.show()
-
-        backup_upload = requests.put(self._signed_upload_url, data = self._backup_zip)
-        upload_message.hide()
-
-        if backup_upload.status_code >= 300:
-            self.backup_upload_error_message = backup_upload.text
-            Logger.log("w", "Could not upload backup file: %s", backup_upload.text)
-            Message(catalog.i18nc("@info:backup_status", "There was an error while uploading your backup."), title = self.MESSAGE_TITLE).show()
-        else:
-            self._upload_success = True
-            Message(catalog.i18nc("@info:backup_status", "Your backup has finished uploading."), title = self.MESSAGE_TITLE).show()