Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Ultimaker/Cura.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNino van Hooff <ninovanhooff@gmail.com>2020-03-10 15:34:18 +0300
committerNino van Hooff <ninovanhooff@gmail.com>2020-03-10 15:35:37 +0300
commited5c2b3f43c281ca10b9f6f57ae8120b9c57aada (patch)
tree8980c409e96f55d2942a65a4a911ba234ae93922 /plugins/CuraDrive
parent244d018a2eedb41d92339c6c3d46a60424fc30fe (diff)
Refactor the create backup implementation to CreateBackupJob
Diffstat (limited to 'plugins/CuraDrive')
-rw-r--r--plugins/CuraDrive/src/CreateBackupJob.py122
-rw-r--r--plugins/CuraDrive/src/DriveApiService.py69
-rw-r--r--plugins/CuraDrive/src/UploadBackupJob.py39
3 files changed, 129 insertions, 101 deletions
diff --git a/plugins/CuraDrive/src/CreateBackupJob.py b/plugins/CuraDrive/src/CreateBackupJob.py
new file mode 100644
index 0000000000..603733137b
--- /dev/null
+++ b/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()
diff --git a/plugins/CuraDrive/src/DriveApiService.py b/plugins/CuraDrive/src/DriveApiService.py
index 922ca8afa7..04f935268b 100644
--- a/plugins/CuraDrive/src/DriveApiService.py
+++ b/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
diff --git a/plugins/CuraDrive/src/UploadBackupJob.py b/plugins/CuraDrive/src/UploadBackupJob.py
deleted file mode 100644
index 8ade697cb3..0000000000
--- a/plugins/CuraDrive/src/UploadBackupJob.py
+++ /dev/null
@@ -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()