Some fixes and cleanup for the network plugin

This commit is contained in:
ChrisTerBeke 2019-08-05 19:37:35 +02:00
parent 91d582622f
commit a1b986fd3a
No known key found for this signature in database
GPG key ID: A49F1AB9D7E0C263
10 changed files with 94 additions and 55 deletions

View file

@ -16,6 +16,9 @@ from UM.Version import Version
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
from plugins.UM3NetworkPrinting.src.Messages.PrintJobUploadBlockedMessage import PrintJobUploadBlockedMessage
from plugins.UM3NetworkPrinting.src.Messages.PrintJobUploadErrorMessage import PrintJobUploadErrorMessage
from plugins.UM3NetworkPrinting.src.Messages.PrintJobUploadSuccessMessage import PrintJobUploadSuccessMessage
from .CloudApiClient import CloudApiClient from .CloudApiClient import CloudApiClient
from ..ExportFileJob import ExportFileJob from ..ExportFileJob import ExportFileJob
@ -134,7 +137,6 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
## Set all the interface elements and texts for this output device. ## Set all the interface elements and texts for this output device.
def _setInterfaceElements(self) -> None: def _setInterfaceElements(self) -> None:
self.setPriority(2) # Make sure we end up below the local networking and above 'save to file'. self.setPriority(2) # Make sure we end up below the local networking and above 'save to file'.
self.setName(self._id)
self.setShortDescription(I18N_CATALOG.i18nc("@action:button", "Print via Cloud")) self.setShortDescription(I18N_CATALOG.i18nc("@action:button", "Print via Cloud"))
self.setDescription(I18N_CATALOG.i18nc("@properties:tooltip", "Print via Cloud")) self.setDescription(I18N_CATALOG.i18nc("@properties:tooltip", "Print via Cloud"))
self.setConnectionText(I18N_CATALOG.i18nc("@info:status", "Connected via Cloud")) self.setConnectionText(I18N_CATALOG.i18nc("@info:status", "Connected via Cloud"))
@ -169,20 +171,18 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
# Show an error message if we're already sending a job. # Show an error message if we're already sending a job.
if self._progress.visible: if self._progress.visible:
return Message( PrintJobUploadBlockedMessage().show()
text=I18N_CATALOG.i18nc("@info:status", "Please wait until the current job has been sent."),
title=I18N_CATALOG.i18nc("@info:title", "Print error"),
lifetime=10
).show()
if self._uploaded_print_job:
# The mesh didn't change, let's not upload it again
self._api.requestPrint(self.key, self._uploaded_print_job.job_id, self._onPrintUploadCompleted)
return return
# Indicate we have started sending a job. # Indicate we have started sending a job.
self.writeStarted.emit(self) self.writeStarted.emit(self)
# The mesh didn't change, let's not upload it to the cloud again.
# Note that self.writeFinished is called in _onPrintUploadCompleted as well.
if self._uploaded_print_job:
self._api.requestPrint(self.key, self._uploaded_print_job.job_id, self._onPrintUploadCompleted)
return
# Export the scene to the correct file type. # Export the scene to the correct file type.
job = ExportFileJob(file_handler=file_handler, nodes=nodes, firmware_version=self.firmwareVersion) job = ExportFileJob(file_handler=file_handler, nodes=nodes, firmware_version=self.firmwareVersion)
job.finished.connect(self._onPrintJobCreated) job.finished.connect(self._onPrintJobCreated)
@ -216,29 +216,21 @@ class CloudOutputDevice(UltimakerNetworkedPrinterOutputDevice):
print_job = cast(CloudPrintJobResponse, self._uploaded_print_job) print_job = cast(CloudPrintJobResponse, self._uploaded_print_job)
self._api.requestPrint(self.key, print_job.job_id, self._onPrintUploadCompleted) self._api.requestPrint(self.key, print_job.job_id, self._onPrintUploadCompleted)
## Shows a message when the upload has succeeded
# \param response: The response from the cloud API.
def _onPrintUploadCompleted(self, response: CloudPrintResponse) -> None:
self._progress.hide()
PrintJobUploadSuccessMessage().show()
self.writeFinished.emit()
## Displays the given message if uploading the mesh has failed ## Displays the given message if uploading the mesh has failed
# \param message: The message to display. # \param message: The message to display.
def _onUploadError(self, message: str = None) -> None: def _onUploadError(self, message: str = None) -> None:
self._progress.hide() self._progress.hide()
self._uploaded_print_job = None self._uploaded_print_job = None
Message( PrintJobUploadErrorMessage(message).show()
text=message or I18N_CATALOG.i18nc("@info:text", "Could not upload the data to the printer."),
title=I18N_CATALOG.i18nc("@info:title", "Cloud error"),
lifetime=10
).show()
self.writeError.emit() self.writeError.emit()
## Shows a message when the upload has succeeded
# \param response: The response from the cloud API.
def _onPrintUploadCompleted(self, response: CloudPrintResponse) -> None:
self._progress.hide()
Message(
text=I18N_CATALOG.i18nc("@info:status", "Print job was successfully sent to the printer."),
title=I18N_CATALOG.i18nc("@info:title", "Data Sent"),
lifetime=5
).show()
self.writeFinished.emit()
## Whether the printer that this output device represents supports print job actions via the cloud. ## Whether the printer that this output device represents supports print job actions via the cloud.
@pyqtProperty(bool, notify=_clusterPrintersChanged) @pyqtProperty(bool, notify=_clusterPrintersChanged)
def supportsPrintJobActions(self) -> bool: def supportsPrintJobActions(self) -> bool:

View file

@ -0,0 +1,16 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM import i18nCatalog
from UM.Message import Message
I18N_CATALOG = i18nCatalog("cura")
class PrintJobUploadBlockedMessage(Message):
def __init__(self) -> None:
super().__init__(
text = I18N_CATALOG.i18nc("@info:status", "Please wait until the current job has been sent."),
title = I18N_CATALOG.i18nc("@info:title", "Print error"),
lifetime = 10
)

View file

@ -0,0 +1,16 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM import i18nCatalog
from UM.Message import Message
I18N_CATALOG = i18nCatalog("cura")
class PrintJobUploadErrorMessage(Message):
def __init__(self, message: str) -> None:
super().__init__(
text = message or I18N_CATALOG.i18nc("@info:text", "Could not upload the data to the printer."),
title = I18N_CATALOG.i18nc("@info:title", "Network error"),
lifetime = 10
)

View file

@ -0,0 +1,17 @@
# Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM import i18nCatalog
from UM.Message import Message
I18N_CATALOG = i18nCatalog("cura")
class PrintJobUploadSuccessMessage(Message):
def __init__(self) -> None:
super().__init__(
text = I18N_CATALOG.i18nc("@info:status", "Print job was successfully sent to the printer."),
title = I18N_CATALOG.i18nc("@info:title", "Data Sent"),
lifetime = 5
)

View file

@ -39,7 +39,7 @@ class ClusterApiClient:
## Get printer system information. ## Get printer system information.
# \param on_finished: The callback in case the response is successful. # \param on_finished: The callback in case the response is successful.
def getSystem(self, on_finished: Callable) -> None: def getSystem(self, on_finished: Callable) -> None:
url = "{}/system/".format(self.PRINTER_API_PREFIX) url = "{}/system".format(self.PRINTER_API_PREFIX)
reply = self._manager.get(self._createEmptyRequest(url)) reply = self._manager.get(self._createEmptyRequest(url))
self._addCallback(reply, on_finished, PrinterSystemStatus) self._addCallback(reply, on_finished, PrinterSystemStatus)
@ -59,17 +59,17 @@ class ClusterApiClient:
## Move a print job to the top of the queue. ## Move a print job to the top of the queue.
def movePrintJobToTop(self, print_job_uuid: str) -> None: def movePrintJobToTop(self, print_job_uuid: str) -> None:
url = "{}/print_jobs/{}/action/move".format(self.CLUSTER_API_PREFIX, print_job_uuid) url = "{}/print_jobs/{}/action/move/".format(self.CLUSTER_API_PREFIX, print_job_uuid)
self._manager.post(self._createEmptyRequest(url), json.dumps({"to_position": 0, "list": "queued"}).encode()) self._manager.post(self._createEmptyRequest(url), json.dumps({"to_position": 0, "list": "queued"}).encode())
## Delete a print job from the queue. ## Delete a print job from the queue.
def deletePrintJob(self, print_job_uuid: str) -> None: def deletePrintJob(self, print_job_uuid: str) -> None:
url = "{}/print_jobs/{}".format(self.CLUSTER_API_PREFIX, print_job_uuid) url = "{}/print_jobs/{}/".format(self.CLUSTER_API_PREFIX, print_job_uuid)
self._manager.deleteResource(self._createEmptyRequest(url)) self._manager.deleteResource(self._createEmptyRequest(url))
## Set the state of a print job. ## Set the state of a print job.
def setPrintJobState(self, print_job_uuid: str, state: str) -> None: def setPrintJobState(self, print_job_uuid: str, state: str) -> None:
url = "{}/print_jobs/{}/action".format(self.CLUSTER_API_PREFIX, print_job_uuid) url = "{}/print_jobs/{}/action/".format(self.CLUSTER_API_PREFIX, print_job_uuid)
# We rewrite 'resume' to 'print' here because we are using the old print job action endpoints. # We rewrite 'resume' to 'print' here because we are using the old print job action endpoints.
action = "print" if state == "resume" else state action = "print" if state == "resume" else state
self._manager.put(self._createEmptyRequest(url), json.dumps({"action": action}).encode()) self._manager.put(self._createEmptyRequest(url), json.dumps({"action": action}).encode())
@ -111,14 +111,17 @@ class ClusterApiClient:
on_finished: Union[Callable[[ClusterApiClientModel], Any], on_finished: Union[Callable[[ClusterApiClientModel], Any],
Callable[[List[ClusterApiClientModel]], Any]], Callable[[List[ClusterApiClientModel]], Any]],
model_class: Type[ClusterApiClientModel]) -> None: model_class: Type[ClusterApiClientModel]) -> None:
if isinstance(response, list): try:
results = [model_class(**c) for c in response] # type: List[ClusterApiClientModel] if isinstance(response, list):
on_finished_list = cast(Callable[[List[ClusterApiClientModel]], Any], on_finished) results = [model_class(**c) for c in response] # type: List[ClusterApiClientModel]
on_finished_list(results) on_finished_list = cast(Callable[[List[ClusterApiClientModel]], Any], on_finished)
else: on_finished_list(results)
result = model_class(**response) # type: ClusterApiClientModel else:
on_finished_item = cast(Callable[[ClusterApiClientModel], Any], on_finished) result = model_class(**response) # type: ClusterApiClientModel
on_finished_item(result) on_finished_item = cast(Callable[[ClusterApiClientModel], Any], on_finished)
on_finished_item(result)
except JSONDecodeError:
Logger.log("e", "Could not parse response from network: %s", str(response))
## Creates a callback function so that it includes the parsing of the response into the correct model. ## Creates a callback function so that it includes the parsing of the response into the correct model.
# The callback is added to the 'finished' signal of the reply. # The callback is added to the 'finished' signal of the reply.

View file

@ -12,6 +12,9 @@ from UM.i18n import i18nCatalog
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState
from cura.PrinterOutput.PrinterOutputDevice import ConnectionType from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
from plugins.UM3NetworkPrinting.src.Messages.PrintJobUploadBlockedMessage import PrintJobUploadBlockedMessage
from plugins.UM3NetworkPrinting.src.Messages.PrintJobUploadErrorMessage import PrintJobUploadErrorMessage
from plugins.UM3NetworkPrinting.src.Messages.PrintJobUploadSuccessMessage import PrintJobUploadSuccessMessage
from .ClusterApiClient import ClusterApiClient from .ClusterApiClient import ClusterApiClient
from ..ExportFileJob import ExportFileJob from ..ExportFileJob import ExportFileJob
@ -46,7 +49,6 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice):
## Set all the interface elements and texts for this output device. ## Set all the interface elements and texts for this output device.
def _setInterfaceElements(self) -> None: def _setInterfaceElements(self) -> None:
self.setPriority(3) # Make sure the output device gets selected above local file output self.setPriority(3) # Make sure the output device gets selected above local file output
self.setName(self._id)
self.setShortDescription(I18N_CATALOG.i18nc("@action:button Preceded by 'Ready to'.", "Print over network")) self.setShortDescription(I18N_CATALOG.i18nc("@action:button Preceded by 'Ready to'.", "Print over network"))
self.setDescription(I18N_CATALOG.i18nc("@properties:tooltip", "Print over network")) self.setDescription(I18N_CATALOG.i18nc("@properties:tooltip", "Print over network"))
self.setConnectionText(I18N_CATALOG.i18nc("@info:status", "Connected over the network")) self.setConnectionText(I18N_CATALOG.i18nc("@info:status", "Connected over the network"))
@ -111,11 +113,8 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice):
# Show an error message if we're already sending a job. # Show an error message if we're already sending a job.
if self._progress.visible: if self._progress.visible:
return Message( PrintJobUploadBlockedMessage().show()
text=I18N_CATALOG.i18nc("@info:status", "Please wait until the current job has been sent."), return
title=I18N_CATALOG.i18nc("@info:title", "Print error"),
lifetime=10
).show()
self.writeStarted.emit(self) self.writeStarted.emit(self)
@ -147,22 +146,14 @@ class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice):
## Handler for when the print job was fully uploaded to the cluster. ## Handler for when the print job was fully uploaded to the cluster.
def _onPrintUploadCompleted(self, _: QNetworkReply) -> None: def _onPrintUploadCompleted(self, _: QNetworkReply) -> None:
self._progress.hide() self._progress.hide()
Message( PrintJobUploadSuccessMessage().show()
text=I18N_CATALOG.i18nc("@info:status", "Print job was successfully sent to the printer."),
title=I18N_CATALOG.i18nc("@info:title", "Data Sent"),
lifetime=5
).show()
self.writeFinished.emit() self.writeFinished.emit()
## Displays the given message if uploading the mesh has failed ## Displays the given message if uploading the mesh has failed
# \param message: The message to display. # \param message: The message to display.
def _onUploadError(self, message: str = None) -> None: def _onUploadError(self, message: str = None) -> None:
self._progress.hide() self._progress.hide()
Message( PrintJobUploadErrorMessage(message).show()
text=message or I18N_CATALOG.i18nc("@info:text", "Could not upload the data to the printer."),
title=I18N_CATALOG.i18nc("@info:title", "Network error"),
lifetime=10
).show()
self.writeError.emit() self.writeError.emit()
## Download all the images from the cluster and load their data in the print job models. ## Download all the images from the cluster and load their data in the print job models.

View file

@ -110,6 +110,7 @@ class LocalClusterOutputDeviceManager:
## Callback for when a manual device check request was responded to. ## Callback for when a manual device check request was responded to.
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus) -> None: def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus) -> None:
callback = self._manual_instances.get(address, None) callback = self._manual_instances.get(address, None)
print("status", status)
if callback is None: if callback is None:
return return
self._onDeviceDiscovered("manual:{}".format(address), address, { self._onDeviceDiscovered("manual:{}".format(address), address, {

View file

@ -14,7 +14,7 @@ from cura.PrinterOutput.PrinterOutputDevice import ConnectionType
from .Utils import formatTimeCompleted, formatDateCompleted from .Utils import formatTimeCompleted, formatDateCompleted
from .ClusterOutputController import ClusterOutputController from .ClusterOutputController import ClusterOutputController
from .PrintJobUploadProgressMessage import PrintJobUploadProgressMessage from plugins.UM3NetworkPrinting.src.Messages.PrintJobUploadProgressMessage import PrintJobUploadProgressMessage
from .Models.UM3PrintJobOutputModel import UM3PrintJobOutputModel from .Models.UM3PrintJobOutputModel import UM3PrintJobOutputModel
from .Models.Http.ClusterPrinterStatus import ClusterPrinterStatus from .Models.Http.ClusterPrinterStatus import ClusterPrinterStatus
from .Models.Http.ClusterPrintJobStatus import ClusterPrintJobStatus from .Models.Http.ClusterPrintJobStatus import ClusterPrintJobStatus
@ -45,6 +45,9 @@ class UltimakerNetworkedPrinterOutputDevice(NetworkedPrinterOutputDevice):
# Trigger the printersChanged signal when the private signal is triggered. # Trigger the printersChanged signal when the private signal is triggered.
self.printersChanged.connect(self._clusterPrintersChanged) self.printersChanged.connect(self._clusterPrintersChanged)
# Set the display name from the properties
self.setName(self.getProperty("name"))
# Keeps track of all printers in the cluster. # Keeps track of all printers in the cluster.
self._printers = [] # type: List[PrinterOutputModel] self._printers = [] # type: List[PrinterOutputModel]