We don't depend on requests lib anymore

Intead we use qt network stuff for everything.
CURA-49
This commit is contained in:
Jaime van Kessel 2016-06-14 11:49:28 +02:00
parent 486fc7f176
commit 1acf155e19

View file

@ -1,7 +1,3 @@
import threading
import time
import requests
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from UM.Application import Application from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
@ -12,7 +8,9 @@ from UM.Message import Message
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
from PyQt5.QtNetwork import QHttpMultiPart, QHttpPart, QNetworkRequest, QNetworkAccessManager from PyQt5.QtNetwork import QHttpMultiPart, QHttpPart, QNetworkRequest, QNetworkAccessManager
from PyQt5.QtCore import QUrl from PyQt5.QtCore import QUrl, QTimer
import json
i18n_catalog = i18nCatalog("cura") i18n_catalog = i18nCatalog("cura")
@ -27,7 +25,6 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._info = info self._info = info
self._gcode = None self._gcode = None
self._update_thread = None
# This holds the full JSON file that was received from the last request. # This holds the full JSON file that was received from the last request.
self._json_printer_state = None self._json_printer_state = None
@ -49,50 +46,40 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._manager.finished.connect(self._onFinished) self._manager.finished.connect(self._onFinished)
## Hack to ensure that the qt networking stuff isn't garbage collected (unless we want it to) ## Hack to ensure that the qt networking stuff isn't garbage collected (unless we want it to)
self._qt_request = None self._printer_request = None
self._qt_reply = None self._printer_reply = None
self._qt_multi_part = None
self._qt_part = None self._print_job_request = None
self._print_job_reply = None
self._post_request = None
self._post_reply = None
self._post_multi_part = None
self._post_part = None
self._progress_message = None self._progress_message = None
self._error_message = None self._error_message = None
self._update_timer = QTimer()
self._update_timer.setInterval(5000) # TODO; Add preference for update interval
self._update_timer.setSingleShot(False)
self._update_timer.timeout.connect(self._update)
## Get the unique key of this machine ## Get the unique key of this machine
# \return key String containing the key of the machine. # \return key String containing the key of the machine.
def getKey(self): def getKey(self):
return self._key return self._key
def _update(self): def _update(self):
Logger.log("d", "Update thread of printer with key %s and ip %s started", self._key, self._address) ## Request 'general' printer data
while self.isConnected(): url = QUrl("http://" + self._address + self._api_prefix + "printer")
try: self._printer_request = QNetworkRequest(url)
printer_reply = self._httpGet("printer") self._printer_reply = self._manager.get(self._printer_request)
if printer_reply.status_code == 200:
self._json_printer_state = printer_reply.json()
try:
self._spliceJSONData()
except:
# issues with json parsing should not break by definition
# TODO: Check in what cases it should fail.
pass
if self._connection_state == ConnectionState.connecting:
# First successful response, so we are now "connected"
self.setConnectionState(ConnectionState.connected)
else:
Logger.log("w", "Got http status code %s while trying to request data.", printer_reply.status_code)
self.setConnectionState(ConnectionState.error)
print_job_reply = self._httpGet("print_job") ## Request print_job data
if print_job_reply.status_code != 404: url = QUrl("http://" + self._address + self._api_prefix + "print_job")
self.setProgress(print_job_reply.json()["progress"]) self._print_job_request = QNetworkRequest(url)
else: self._print_job_reply = self._manager.get(self._print_job_request)
self.setProgress(0)
except Exception as e:
self.setConnectionState(ConnectionState.error)
Logger.log("w", "Exception occured while connecting; %s", str(e))
time.sleep(2) # Poll every 2 seconds for printer state.
Logger.log("d", "Update thread of printer with key %s and ip %s stopped with state: %s", self._key, self._address, self._connection_state)
## Convenience function that gets information from the received json data and converts it to the right internal ## Convenience function that gets information from the received json data and converts it to the right internal
# values / variables # values / variables
@ -112,9 +99,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
def close(self): def close(self):
self._connection_state == ConnectionState.closed self._connection_state == ConnectionState.closed
if self._update_thread is not None: self._update_timer.stop()
self._update_thread.join()
self._update_thread = None
def requestWrite(self, node, file_name = None, filter_by_machine = False): def requestWrite(self, node, file_name = None, filter_by_machine = False):
self._gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list") self._gcode = getattr(Application.getInstance().getController().getScene(), "gcode_list")
@ -123,13 +108,12 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
def isConnected(self): def isConnected(self):
return self._connection_state != ConnectionState.closed and self._connection_state != ConnectionState.error return self._connection_state != ConnectionState.closed and self._connection_state != ConnectionState.error
## Start the polling thread. ## Start requesting data from printer
def connect(self): def connect(self):
if self._update_thread is None: self.setConnectionState(ConnectionState.connecting)
self.setConnectionState(ConnectionState.connecting) self._update() # Manually trigger the first update, as we don't want to wait a few secs before it starts.
self._update_thread = threading.Thread(target = self._update) Logger.log("d", "Connection with printer %s with ip %s started", self._key, self._address)
self._update_thread.daemon = True self._update_timer.start()
self._update_thread.start()
def getCameraImage(self): def getCameraImage(self):
pass # TODO: This still needs to be implemented (we don't have a place to show it now anyway) pass # TODO: This still needs to be implemented (we don't have a place to show it now anyway)
@ -143,6 +127,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), 0, False, -1) self._progress_message = Message(i18n_catalog.i18nc("@info:status", "Sending data to printer"), 0, False, -1)
self._progress_message.show() self._progress_message.show()
## Mash the data into single string
single_string_file_data = "" single_string_file_data = ""
for line in self._gcode: for line in self._gcode:
single_string_file_data += line single_string_file_data += line
@ -151,23 +136,23 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
file_name = "test.gcode" file_name = "test.gcode"
## Create multi_part request ## Create multi_part request
self._qt_multi_part = QHttpMultiPart(QHttpMultiPart.FormDataType) self._post_multi_part = QHttpMultiPart(QHttpMultiPart.FormDataType)
## Create part (to be placed inside multipart) ## Create part (to be placed inside multipart)
self._qt_part = QHttpPart() self._post_part = QHttpPart()
self._qt_part.setHeader(QNetworkRequest.ContentDispositionHeader, self._post_part.setHeader(QNetworkRequest.ContentDispositionHeader,
"form-data; name=\"file\"; filename=\"%s\"" % file_name) "form-data; name=\"file\"; filename=\"%s\"" % file_name)
self._qt_part.setBody(single_string_file_data) self._post_part.setBody(single_string_file_data.encode())
self._qt_multi_part.append(self._qt_part) self._post_multi_part.append(self._post_part)
url = QUrl("http://" + self._address + self._api_prefix + "print_job") url = QUrl("http://" + self._address + self._api_prefix + "print_job")
## Create the QT request ## Create the QT request
self._qt_request = QNetworkRequest(url) self._post_request = QNetworkRequest(url)
## Post request + data ## Post request + data
self._qt_reply = self._manager.post(self._qt_request, self._qt_multi_part) self._post_reply = self._manager.post(self._post_request, self._post_multi_part)
self._qt_reply.uploadProgress.connect(self._onUploadProgress) self._post_reply.uploadProgress.connect(self._onUploadProgress)
except IOError: except IOError:
self._progress_message.hide() self._progress_message.hide()
@ -177,15 +162,32 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._progress_message.hide() self._progress_message.hide()
Logger.log("e" , "An exception occured in network connection: %s" % str(e)) Logger.log("e" , "An exception occured in network connection: %s" % str(e))
## Handler for all requests that have finshed.
def _onFinished(self, reply): def _onFinished(self, reply):
reply.uploadProgress.disconnect(self._onUploadProgress) if reply.operation() == QNetworkAccessManager.GetOperation:
self._progress_message.hide() if "printer" in reply.url().toString(): # Status update from printer.
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200:
if self._connection_state == ConnectionState.connecting:
self.setConnectionState(ConnectionState.connected)
self._json_printer_state = json.loads(bytes(reply.readAll()).decode("utf-8"))
self._spliceJSONData()
else:
pass # TODO: Handle errors
elif "print_job" in reply.url().toString(): # Status update from print_job:
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200:
self.setProgress(json.loads(bytes(reply.readAll()).decode("utf-8"))["progress"])
elif reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 404:
self.setProgress(0) # No print job found, so there can't be progress!
elif reply.operation() == QNetworkAccessManager.PostOperation:
reply.uploadProgress.disconnect(self._onUploadProgress)
self._progress_message.hide()
else:
print("got unhandled operation:", reply.operation())
def _onUploadProgress(self, bytes_sent, bytes_total): def _onUploadProgress(self, bytes_sent, bytes_total):
if bytes_total > 0: if bytes_total > 0:
self._progress_message.setProgress(bytes_sent / bytes_total * 100) self._progress_message.setProgress(bytes_sent / bytes_total * 100)
else: else:
self._progress_message.setProgress(0) self._progress_message.setProgress(0)
def _httpGet(self, path):
return requests.get("http://" + self._address + self._api_prefix + path, timeout = 5)