Browse Source

Added sending material profiles to LegacyUM3

CL-541
Jaime van Kessel 7 years ago
parent
commit
96d5c7152b

+ 48 - 9
cura/PrinterOutput/NetworkedPrinterOutputDevice.py

@@ -7,7 +7,7 @@ from PyQt5.QtNetwork import QHttpMultiPart, QHttpPart, QNetworkRequest, QNetwork
 from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QTimer, pyqtSignal, QUrl
 
 from time import time
-from typing import Callable, Any
+from typing import Callable, Any, Optional
 from enum import IntEnum
 
 
@@ -39,6 +39,8 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
         self._onFinishedCallbacks = {}
         self._authentication_state = AuthState.NotAuthenticated
 
+        self._cached_multiparts = {}
+
     def setAuthenticationState(self, authentication_state):
         if self._authentication_state != authentication_state:
             self._authentication_state = authentication_state
@@ -79,29 +81,35 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
         request.setHeader(QNetworkRequest.UserAgentHeader, self._user_agent)
         return request
 
-    def _put(self, target: str, data: str, onFinished: Callable[[Any, QNetworkReply], None]):
+    def _clearCachedMultiPart(self, reply):
+        if id(reply) in self._cached_multiparts:
+            del self._cached_multiparts[id(reply)]
+
+    def _put(self, target: str, data: str, onFinished: Optional[Callable[[Any, QNetworkReply], None]]):
         if self._manager is None:
             self._createNetworkManager()
         request = self._createEmptyRequest(target)
         self._last_request_time = time()
         reply = self._manager.put(request, data.encode())
-        self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
+        if onFinished is not None:
+            self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
 
-    def _get(self, target: str, onFinished: Callable[[Any, QNetworkReply], None]):
+    def _get(self, target: str, onFinished: Optional[Callable[[Any, QNetworkReply], None]]):
         if self._manager is None:
             self._createNetworkManager()
         request = self._createEmptyRequest(target)
         self._last_request_time = time()
         reply = self._manager.get(request)
-        self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
+        if onFinished is not None:
+            self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
 
-    def _delete(self, target: str, onFinished: Callable[[Any, QNetworkReply], None]):
+    def _delete(self, target: str, onFinished: Optional[Callable[[Any, QNetworkReply], None]]):
         if self._manager is None:
             self._createNetworkManager()
         self._last_request_time = time()
         pass
 
-    def _post(self, target: str, data: str, onFinished: Callable[[Any, QNetworkReply], None], onProgress: Callable = None):
+    def _post(self, target: str, data: str, onFinished: Optional[Callable[[Any, QNetworkReply], None]], onProgress: Callable = None):
         if self._manager is None:
             self._createNetworkManager()
         request = self._createEmptyRequest(target)
@@ -109,7 +117,31 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
         reply = self._manager.post(request, data)
         if onProgress is not None:
             reply.uploadProgress.connect(onProgress)
-        self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
+        if onFinished is not None:
+            self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
+
+    def _postForm(self, target: str, header_data: str, body_data: bytes, onFinished: Optional[Callable[[Any, QNetworkReply], None]], onProgress: Callable = None):
+        if self._manager is None:
+            self._createNetworkManager()
+        request = self._createEmptyRequest(target)
+
+        multi_post_part = QHttpMultiPart()
+        post_part = QHttpPart()
+        post_part.setHeader(QNetworkRequest.ContentDispositionHeader, header_data)
+        post_part.setBody(body_data)
+        multi_post_part.append(post_part)
+
+        self._last_request_time = time()
+
+        reply = self._manager.post(request, multi_post_part)
+
+        # Due to garbage collection on python doing some weird stuff, we need to keep hold of a reference
+        self._cached_multiparts[id(reply)] = (post_part, multi_post_part, reply)
+
+        if onProgress is not None:
+            reply.uploadProgress.connect(onProgress)
+        if onFinished is not None:
+            self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())] = onFinished
 
     def _onAuthenticationRequired(self, reply, authenticator):
         Logger.log("w", "Request to {url} required authentication, which was not implemented".format(url = reply.url().toString()))
@@ -128,6 +160,11 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
         #self._manager.networkAccessibleChanged.connect(self._onNetworkAccesibleChanged)  # for debug purposes
 
     def __handleOnFinished(self, reply: QNetworkReply):
+        # Due to garbage collection, we need to cache certain bits of post operations.
+        # As we don't want to keep them around forever, delete them if we get a reply.
+        if reply.operation() == QNetworkAccessManager.PostOperation:
+            self._clearCachedMultiPart(reply)
+
         if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) is None:
             # No status code means it never even reached remote.
             return
@@ -137,8 +174,10 @@ class NetworkedPrinterOutputDevice(PrinterOutputDevice):
         if self._connection_state == ConnectionState.connecting:
             self.setConnectionState(ConnectionState.connected)
 
+        callback_key = reply.url().toString() + str(reply.operation())
         try:
-            self._onFinishedCallbacks[reply.url().toString() + str(reply.operation())](reply)
+            if callback_key in self._onFinishedCallbacks:
+                self._onFinishedCallbacks[callback_key](reply)
         except Exception:
             Logger.logException("w", "something went wrong with callback")
 

+ 25 - 0
plugins/UM3NetworkPrinting/LegacyUM3OutputDevice.py

@@ -3,6 +3,8 @@ from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
 from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
 from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
 
+from cura.Settings.ContainerManager import ContainerManager
+
 from UM.Logger import Logger
 from UM.Settings.ContainerRegistry import ContainerRegistry
 from UM.Application import Application
@@ -97,6 +99,29 @@ class LegacyUM3OutputDevice(NetworkedPrinterOutputDevice):
 
     ##  Send all material profiles to the printer.
     def sendMaterialProfiles(self):
+        Logger.log("i", "Sending material profiles to printer")
+
+        # TODO: Might want to move this to a job...
+        for container in ContainerRegistry.getInstance().findInstanceContainers(type="material"):
+            try:
+                xml_data = container.serialize()
+                if xml_data == "" or xml_data is None:
+                    continue
+
+                names = ContainerManager.getInstance().getLinkedMaterials(container.getId())
+                if names:
+                    # There are other materials that share this GUID.
+                    if not container.isReadOnly():
+                        continue  # If it's not readonly, it's created by user, so skip it.
+
+                file_name = "none.xml"
+                self._postForm("materials", "form-data; name=\"file\";filename=\"%s\"" % file_name, xml_data.encode(), onFinished=None)
+
+            except NotImplementedError:
+                # If the material container is not the most "generic" one it can't be serialized an will raise a
+                # NotImplementedError. We can simply ignore these.
+                pass
+
         # TODO
         pass