|
@@ -18,13 +18,14 @@ from UM.Signal import Signal
|
|
from UM.TaskManagement.HttpRequestManager import HttpRequestManager # To call the API.
|
|
from UM.TaskManagement.HttpRequestManager import HttpRequestManager # To call the API.
|
|
from UM.TaskManagement.HttpRequestScope import JsonDecoratorScope
|
|
from UM.TaskManagement.HttpRequestScope import JsonDecoratorScope
|
|
|
|
|
|
-catalog = i18nCatalog("cura")
|
|
|
|
-
|
|
|
|
from typing import Optional, TYPE_CHECKING
|
|
from typing import Optional, TYPE_CHECKING
|
|
if TYPE_CHECKING:
|
|
if TYPE_CHECKING:
|
|
from PyQt5.QtNetwork import QNetworkReply
|
|
from PyQt5.QtNetwork import QNetworkReply
|
|
from cura.UltimakerCloud.CloudMaterialSync import CloudMaterialSync
|
|
from cura.UltimakerCloud.CloudMaterialSync import CloudMaterialSync
|
|
|
|
|
|
|
|
+catalog = i18nCatalog("cura")
|
|
|
|
+
|
|
|
|
+
|
|
class UploadMaterialsJob(Job):
|
|
class UploadMaterialsJob(Job):
|
|
"""
|
|
"""
|
|
Job that uploads a set of materials to the Digital Factory.
|
|
Job that uploads a set of materials to the Digital Factory.
|
|
@@ -43,6 +44,9 @@ class UploadMaterialsJob(Job):
|
|
self._scope = JsonDecoratorScope(UltimakerCloudScope(cura.CuraApplication.CuraApplication.getInstance())) # type: JsonDecoratorScope
|
|
self._scope = JsonDecoratorScope(UltimakerCloudScope(cura.CuraApplication.CuraApplication.getInstance())) # type: JsonDecoratorScope
|
|
self._archive_filename = None # type: Optional[str]
|
|
self._archive_filename = None # type: Optional[str]
|
|
self._archive_remote_id = None # type: Optional[str] # ID that the server gives to this archive. Used to communicate about the archive to the server.
|
|
self._archive_remote_id = None # type: Optional[str] # ID that the server gives to this archive. Used to communicate about the archive to the server.
|
|
|
|
+ self._num_synced_printers = 0
|
|
|
|
+ self._completed_printers = set() # The printers that have successfully completed the upload.
|
|
|
|
+ self._failed_printers = set()
|
|
|
|
|
|
uploadCompleted = Signal()
|
|
uploadCompleted = Signal()
|
|
uploadProgressChanged = Signal()
|
|
uploadProgressChanged = Signal()
|
|
@@ -111,13 +115,15 @@ class UploadMaterialsJob(Job):
|
|
self.uploadCompleted.emit(self.getResult(), self.getError())
|
|
self.uploadCompleted.emit(self.getResult(), self.getError())
|
|
return
|
|
return
|
|
|
|
|
|
- for container_stack in CuraContainerRegistry.getInstance().findContainerStacksMetadata(type = "machine"):
|
|
|
|
- if container_stack.get("connection_type", -1) != 3: # Not a cloud printer.
|
|
|
|
- continue # Only upload to cloud printers.
|
|
|
|
- if not container_stack.get("is_online", False): # Not online.
|
|
|
|
- continue # Only upload to online printers.
|
|
|
|
- if "host_guid" not in container_stack or "um_cloud_cluster_id" not in container_stack:
|
|
|
|
- continue # Incomplete information about cloud printer.
|
|
|
|
|
|
+ online_cloud_printers = CuraContainerRegistry.getInstance().findContainerStacksMetadata(
|
|
|
|
+ type = "machine",
|
|
|
|
+ connection_type = 3, # Only cloud printers.
|
|
|
|
+ is_online = True, # Only online printers. Otherwise the server gives an error.
|
|
|
|
+ host_guid = "*", # Required metadata field. Otherwise we get a KeyError.
|
|
|
|
+ um_cloud_cluster_id = "*" # Required metadata field. Otherwise we get a KeyError.
|
|
|
|
+ )
|
|
|
|
+ self._num_synced_printers = len(online_cloud_printers)
|
|
|
|
+ for container_stack in online_cloud_printers:
|
|
cluster_id = container_stack["um_cloud_cluster_id"]
|
|
cluster_id = container_stack["um_cloud_cluster_id"]
|
|
printer_id = container_stack["host_guid"]
|
|
printer_id = container_stack["host_guid"]
|
|
|
|
|
|
@@ -125,20 +131,24 @@ class UploadMaterialsJob(Job):
|
|
http.get(
|
|
http.get(
|
|
url = self.UPLOAD_CONFIRM_URL.format(cluster_id = cluster_id, cluster_printer_id = printer_id),
|
|
url = self.UPLOAD_CONFIRM_URL.format(cluster_id = cluster_id, cluster_printer_id = printer_id),
|
|
callback = functools.partialmethod(self.onUploadConfirmed, printer_id),
|
|
callback = functools.partialmethod(self.onUploadConfirmed, printer_id),
|
|
- error_callback = self.onError,
|
|
|
|
|
|
+ error_callback = functools.partialmethod(self.onUploadConfirmed, printer_id), # Let this same function handle the error too.
|
|
scope = self._scope
|
|
scope = self._scope
|
|
)
|
|
)
|
|
|
|
|
|
def onUploadConfirmed(self, printer_id: str, reply: "QNetworkReply", error: Optional["QNetworkReply.NetworkError"]) -> None:
|
|
def onUploadConfirmed(self, printer_id: str, reply: "QNetworkReply", error: Optional["QNetworkReply.NetworkError"]) -> None:
|
|
if error is not None:
|
|
if error is not None:
|
|
Logger.error(f"Failed to confirm uploading material archive to printer {printer_id}: {error}")
|
|
Logger.error(f"Failed to confirm uploading material archive to printer {printer_id}: {error}")
|
|
- self.setError(UploadMaterialsError(catalog.i18nc("@text:error", "Failed to connect to Digital Factory.")))
|
|
|
|
- self.setResult(self.Result.FAILED)
|
|
|
|
|
|
+ self._failed_printers.add(printer_id)
|
|
|
|
+ else:
|
|
|
|
+ self._completed_printers.add(printer_id)
|
|
|
|
+
|
|
|
|
+ if len(self._completed_printers) + len(self._failed_printers) >= self._num_synced_printers: # This is the last response to be processed.
|
|
|
|
+ if self._failed_printers:
|
|
|
|
+ self.setResult(self.Result.FAILED)
|
|
|
|
+ self.setError(UploadMaterialsError(catalog.i18nc("@text:error", "Failed to connect to Digital Factory to sync materials with some of the printers.")))
|
|
|
|
+ else:
|
|
|
|
+ self.setResult(self.Result.SUCCESS)
|
|
self.uploadCompleted.emit(self.getResult(), self.getError())
|
|
self.uploadCompleted.emit(self.getResult(), self.getError())
|
|
- return
|
|
|
|
-
|
|
|
|
- self.setResult(self.Result.SUCCCESS)
|
|
|
|
- self.uploadCompleted.emit(self.getResult(), self.getError())
|
|
|
|
|
|
|
|
def onError(self, reply: "QNetworkReply", error: Optional["QNetworkReply.NetworkError"]):
|
|
def onError(self, reply: "QNetworkReply", error: Optional["QNetworkReply.NetworkError"]):
|
|
Logger.error(f"Failed to upload material archive: {error}")
|
|
Logger.error(f"Failed to upload material archive: {error}")
|
|
@@ -146,8 +156,9 @@ class UploadMaterialsJob(Job):
|
|
self.setError(UploadMaterialsError(catalog.i18nc("@text:error", "Failed to connect to Digital Factory.")))
|
|
self.setError(UploadMaterialsError(catalog.i18nc("@text:error", "Failed to connect to Digital Factory.")))
|
|
self.uploadCompleted.emit(self.getResult(), self.getError())
|
|
self.uploadCompleted.emit(self.getResult(), self.getError())
|
|
|
|
|
|
|
|
+
|
|
class UploadMaterialsError(Exception):
|
|
class UploadMaterialsError(Exception):
|
|
"""
|
|
"""
|
|
Marker class to indicate something went wrong while uploading.
|
|
Marker class to indicate something went wrong while uploading.
|
|
"""
|
|
"""
|
|
- pass
|
|
|
|
|
|
+ pass
|