def _onUploadFinished(self, reply: QNetworkReply) -> None: """ Checks whether a chunk of data was uploaded successfully, starting the next chunk if needed. """ Logger.log("i", "Finished callback %s %s", reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url().toString()) status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) # type: Optional[int] if not status_code: Logger.log("e", "Reply contained no status code.") self._onUploadError(reply, None) return # check if we should retry the last chunk if self._retries < self.MAX_RETRIES and status_code in self.RETRY_HTTP_CODES: self._retries += 1 Logger.log("i", "Retrying %s/%s request %s", self._retries, self.MAX_RETRIES, reply.url().toString()) try: self._upload() except ValueError: # Asynchronously it could have completed in the meanwhile. pass return # Http codes that are not to be retried are assumed to be errors. if status_code > 308: self._onUploadError(reply, None) return Logger.log("d", "status_code: %s, Headers: %s, body: %s", status_code, [bytes(header).decode() for header in reply.rawHeaderList()], bytes(reply.readAll()).decode()) self._on_success(self._file_name) self.stop()
def _finishedCallback(self, reply: QNetworkReply) -> None: Logger.log("i", "Finished callback %s %s", reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url().toString()) status_code = reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) # type: int # check if we should retry the last chunk if self._retries < self.MAX_RETRIES and status_code in self.RETRY_HTTP_CODES: self._retries += 1 Logger.log("i", "Retrying %s/%s request %s", self._retries, self.MAX_RETRIES, reply.url().toString()) try: self._uploadChunk() except ValueError: # Asynchronously it could have completed in the meanwhile. pass return # Http codes that are not to be retried are assumed to be errors. if status_code > 308: self._errorCallback(reply, None) return Logger.log( "d", "status_code: %s, Headers: %s, body: %s", status_code, [bytes(header).decode() for header in reply.rawHeaderList()], bytes(reply.readAll()).decode()) self._chunkUploaded()
def sendingFinished(self, reply: QNetworkReply): if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: Logger.log( "e", "Received error code from printer when syncing material: {code}" .format(code=reply.attribute( QNetworkRequest.HttpStatusCodeAttribute))) Logger.log("e", reply.readAll().data().decode("utf-8"))
def sendingFinished(reply: QNetworkReply) -> None: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: Logger.log( "e", "Received error code from printer when syncing material: {code}, {text}" .format(code=reply.attribute( QNetworkRequest.HttpStatusCodeAttribute), text=reply.errorString()))
def log_request(self, reply: QNetworkReply) -> None: self.logger.info('request made at %s' % reply.header( QNetworkRequest.LastModifiedHeader).toString('dd-MM-yyyy hh:mm:ss') ) self.logger.info( 'response: %s (%i) type: %s' % (reply.attribute( QNetworkRequest.HttpReasonPhraseAttribute).upper(), reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.header(QNetworkRequest.ContentTypeHeader)))
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 = self.DEFAULT_UPLOAD_ERROR_MESSAGE self._job_done.set() return if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) >= 300: Logger.warning("Could not request backup upload: %s", HttpRequestManager.readText(reply)) self.backup_upload_error_message = self.DEFAULT_UPLOAD_ERROR_MESSAGE self._job_done.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 checkValidGetReply(reply: QNetworkReply) -> bool: status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) if status_code != 200: Logger.log("w", "Got status code {status_code} while trying to get data".format(status_code=status_code)) return False return True
def gotResponse(self, QNetworkReply): try: status = QNetworkReply.attribute( QNetworkRequest.HttpStatusCodeAttribute) except Exception as e: log('[e] http/yaml error: %s' % str(e)) self.updatesLabel.setText('Error') return if status != 200: self.updatesLabel.setText('Network error: ' + str(status)) return try: response = QNetworkReply.readAll() response = str(response, 'utf-8') ver = safe_load(response) except Exception as e: log('[e] http/yaml error: %s' % str(e)) self.updatesLabel.setText('error') return if ver is None: self.updatesLabel.setText('<network error>') return if 'version' in ver and 'date' in ver: verStr = 'Last published version is %s, build %s.' % ( ver['version'], ver['date']) self.updatesLabel.setText(verStr)
def parseReplyAsBytes(cls, reply: QNetworkReply) -> Tuple[int, bytes]: """ Parse the given API reply into a status code and bytes. :param reply: The reply from the server. :return: A tuple with a status code and the response body as bytes. """ status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) return status_code, reply.readAll().data()
def _parseReply(reply: QNetworkReply) -> Tuple[int, Dict[str, Any]]: status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) try: response = bytes(reply.readAll()).decode() return status_code, json.loads(response) except (UnicodeDecodeError, JSONDecodeError, ValueError) as err: Logger.logException("e", "Could not parse the cluster response: %s", err) return status_code, {"errors": [err]}
def _onRequestFinished(self, reply: QNetworkReply) -> None: if reply.error() == QNetworkReply.TimeoutError: Logger.log("w", "Got a timeout.") self.setViewPage("errored") self.resetDownload() return if reply.error() == QNetworkReply.HostNotFoundError: Logger.log("w", "Unable to reach server.") self.setViewPage("errored") self.resetDownload() return if reply.operation() == QNetworkAccessManager.GetOperation: for response_type, url in self._request_urls.items(): if reply.url() == url: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200: try: json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) # Check for errors: if "errors" in json_data: for error in json_data["errors"]: Logger.log("e", "%s", error["title"]) return # Create model and apply metadata: if not self._models[response_type]: Logger.log("e", "Could not find the %s model.", response_type) break self._server_response_data[response_type] = json_data["data"] self._models[response_type].setMetadata(self._server_response_data[response_type]) if response_type is "packages": self._models[response_type].setFilter({"type": "plugin"}) self.reBuildMaterialsModels() self.reBuildPluginsModels() self._notifyPackageManager() elif response_type is "authors": self._models[response_type].setFilter({"package_types": "material"}) self._models[response_type].setFilter({"tags": "generic"}) self.metadataChanged.emit() if self.isLoadingComplete(): self.setViewPage("overview") except json.decoder.JSONDecodeError: Logger.log("w", "Received invalid JSON for %s.", response_type) break else: Logger.log("w", "Unable to connect with the server, we got a response code %s while trying to connect to %s", reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url()) self.setViewPage("errored") self.resetDownload() elif reply.operation() == QNetworkAccessManager.PutOperation: # Ignore any operation that is not a get operation pass
def _onRequestFinished(self, reply: QNetworkReply) -> None: if reply.error() == QNetworkReply.TimeoutError: Logger.log("w", "Got a timeout.") self.setViewPage("errored") self.resetDownload() return if reply.error() == QNetworkReply.HostNotFoundError: Logger.log("w", "Unable to reach server.") self.setViewPage("errored") self.resetDownload() return if reply.operation() == QNetworkAccessManager.GetOperation: for response_type, url in self._request_urls.items(): if reply.url() == url: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200: try: json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) # Check for errors: if "errors" in json_data: for error in json_data["errors"]: Logger.log("e", "%s", error["title"]) return # Create model and apply metadata: if not self._models[response_type]: Logger.log("e", "Could not find the %s model.", response_type) break self._server_response_data[response_type] = json_data["data"] self._models[response_type].setMetadata(self._server_response_data[response_type]) if response_type is "packages": self._models[response_type].setFilter({"type": "plugin"}) self.reBuildMaterialsModels() self.reBuildPluginsModels() elif response_type is "authors": self._models[response_type].setFilter({"package_types": "material"}) self._models[response_type].setFilter({"tags": "generic"}) self.metadataChanged.emit() if self.isLoadingComplete(): self.setViewPage("overview") except json.decoder.JSONDecodeError: Logger.log("w", "Received invalid JSON for %s.", response_type) break else: Logger.log("w", "Unable to connect with the server, we got a response code %s while trying to connect to %s", reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url()) self.setViewPage("errored") self.resetDownload() elif reply.operation() == QNetworkAccessManager.PutOperation: # Ignore any operation that is not a get operation pass
def parse_qt_network_reply( reply: QtNetwork.QNetworkReply) -> ParsedNetworkReply: http_status_code = reply.attribute( QtNetwork.QNetworkRequest.HttpStatusCodeAttribute) http_status_reason = reply.attribute( QtNetwork.QNetworkRequest.HttpReasonPhraseAttribute) error = reply.error() if error == QtNetwork.QNetworkReply.NoError: qt_error = None else: qt_error = _Q_NETWORK_REPLY_ERROR_MAP[error] body = reply.readAll() return ParsedNetworkReply( http_status_code=http_status_code, http_status_reason=http_status_reason, qt_error=qt_error, response_body=body, )
def _parseReply(reply: QNetworkReply) -> Tuple[int, Dict[str, Any]]: status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) try: response = bytes(reply.readAll()).decode() return status_code, json.loads(response) except (UnicodeDecodeError, JSONDecodeError, ValueError) as err: error = CloudError(code=type(err).__name__, title=str(err), http_code=str(status_code), id=str(time()), http_status="500") Logger.logException("e", "Could not parse the stardust response: %s", error.toDict()) return status_code, {"errors": [error.toDict()]}
def _onGetRemoteMaterials(self, reply: QNetworkReply) -> None: # Got an error from the HTTP request. If we did not receive a 200 something happened. if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: Logger.log("e", "Error fetching materials from printer: %s", reply.errorString()) return # Collect materials from the printer's reply and send the missing ones if needed. remote_materials_by_guid = self._parseReply(reply) if remote_materials_by_guid: self._sendMissingMaterials(remote_materials_by_guid)
def base_handler(self, reply: QNetworkReply): try: response = json.loads(str(reply.readAll(), encoding='utf-8')) status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) except: self.parent.warn.add_warn("Http解析错误") return if reply.error() != QNetworkReply.NoError: self.handler_error(response, status_code) else: self.data.emit(response)
def _sendingFinished(self, reply: QNetworkReply) -> None: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: Logger.log("w", "Error while syncing material: %s", reply.errorString()) return body = reply.readAll().data().decode('utf8') if "not added" in body: # For some reason the cluster returns a 200 sometimes even when syncing failed. return # Inform the user that materials have been synced. This message only shows itself when not already visible. # Because of the guards above it is not shown when syncing failed (which is not always an actual problem). MaterialSyncMessage(self.device).show()
def _parseReply(reply: QNetworkReply) -> Tuple[int, Optional[Union[List[Any], Dict[str, Any]]]]: """ Parse the given JSON network reply into a status code and JSON object. :param reply: The reply from the server. :return: A tuple with a status code and a dictionary. """ status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) try: response = bytes(reply.readAll()).decode() return status_code, json.loads(response) except (UnicodeDecodeError, JSONDecodeError, ValueError) as err: Logger.logException("e", "Could not parse the API response: %s", err) return status_code, None
def _onNetworkFinished(self, reply: QNetworkReply): status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) url_string = reply.url().toString() if "modifier" in url_string: if status_code == 404: print("server was not found!") self._failed_update_modifier_timer.start() return data = bytes(reply.readAll()) try: self._modifiers = json.loads(data) except: print("Failed to get modifier data") self._failed_update_modifier_timer.start() return self.modifiersChanged.emit() elif "RFID" in url_string: if status_code != 404: self._serial_worker.setReadResult(True) self.setAuthenticationRequired(False) else: self._serial_worker.setReadResult(False) self.setAuthenticationRequired(True) else: # Yeah it's hackish, but it's faster than building a real system. For now we don't need more if status_code == 404: print("Server was not found!") self._failed_update_nodes_timer.start() return data = bytes(reply.readAll()) try: data = json.loads(data) for item in data: new_node = Node(item["node_id"]) new_node.updateServerUrl( self._zeroconf_worker.server_address) self._data.append(new_node) new_node.serverReachableChanged.connect( self.serverReachableChanged) self._data = sorted(self._data, key=lambda node: node.id) # sort by age self._data.reverse() self.nodesChanged.emit() except: print("Failed to get modifier data") self._failed_update_nodes_timer.start() return
def parseReplyAsJson(cls, reply: QNetworkReply ) -> Tuple[int, Optional[Union[Dict[str, Any], List[Dict[str, Any]]]]]: """ Parse the given API reply into a status code and JSON object. :param reply: The reply from the server. :return: A tuple with a status code and the response body as JsonObject. """ status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) try: response = reply.readAll().data().decode() return status_code, json.loads(response) except (UnicodeDecodeError, JSONDecodeError, ValueError) as err: Logger.log("e", "Could not parse the API response: %s", err) return status_code, None
def _parseReply(reply: QNetworkReply) -> Tuple[int, Dict[str, Any]]: """Parses the given JSON network reply into a status code and a dictionary, handling unexpected errors as well. :param reply: The reply from the server. :return: A tuple with a status code and a dictionary. """ status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) try: response = bytes(reply.readAll()).decode() return status_code, json.loads(response) except (UnicodeDecodeError, JSONDecodeError, ValueError) as err: Logger.logException("e", "Could not parse the cluster response: %s", err) return status_code, {"errors": [err]}
def parse(reply: QNetworkReply) -> None: self._anti_gc_callbacks.remove(parse) # Don't try to parse the reply if we didn't get one if reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) is None: if on_error is not None: on_error() return status_code, response = self._parseReply(reply) if status_code >= 300 and on_error is not None: on_error() else: self._parseModels(response, on_finished, model)
def _readData(self, reply: QNetworkReply): status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) if status_code == 404: print("Node was not found!") return # For some magical reason, it segfaults if I convert the readAll() data directly to bytes. # So, yes, the extra .data() is needed. data = bytes(reply.readAll().data()) if not data or status_code == 503: self._failed_update_timer.start() self._update_timer.stop() self._setServerReachable(False) return None self._setServerReachable(True) try: return json.loads(data) except json.decoder.JSONDecodeError: return None
def slot_reply_finished(self, data: QNetworkReply): self._reply = data self._text = data.readAll() self._string = bytes(self._text).decode() self._status_code = data.attribute( QNetworkRequest.HttpStatusCodeAttribute) self._save_header(data.rawHeaderPairs()) if self.content_type() == 'json': if len(self._string): self._json = json.loads(self._string) else: self._json = None if self._status_code >= 400: print(self._string) self.sig_ended.emit(True) data.deleteLater()
def _parseReply(reply: QNetworkReply) -> Tuple[int, Dict[str, Any]]: """Parses the given JSON network reply into a status code and a dictionary, handling unexpected errors as well. :param reply: The reply from the server. :return: A tuple with a status code and a dictionary. """ status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) try: response = bytes(reply.readAll()).decode() return status_code, json.loads(response) except (UnicodeDecodeError, JSONDecodeError, ValueError) as err: error = CloudError(code=type(err).__name__, title=str(err), http_code=str(status_code), id=str(time()), http_status="500") Logger.logException("e", "Could not parse the stardust response: %s", error.toDict()) return status_code, {"errors": [error.toDict()]}
def _handleOnFinished(self, reply: QNetworkReply) -> None: # 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 self._last_response_time = time() if self._connection_state == ConnectionState.Connecting: self.setConnectionState(ConnectionState.Connected) callback_key = reply.url().toString() + str(reply.operation()) try: if callback_key in self._onFinishedCallbacks: self._onFinishedCallbacks[callback_key](reply) except Exception: Logger.logException("w", "something went wrong with callback")
def _onRestoreRequestCompleted( self, reply: QNetworkReply, error: Optional["QNetworkReply.NetworkError"] = None) -> None: if not HttpRequestManager.replyIndicatesSuccess(reply, error): Logger.warning( "Requesting backup failed, response code %s while trying to connect to %s", reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url()) self.restore_backup_error_message = self.DEFAULT_ERROR_MESSAGE self._job_done.set() return # We store the file in a temporary path fist to ensure integrity. temporary_backup_file = NamedTemporaryFile(delete=False) with open(temporary_backup_file.name, "wb") as write_backup: app = CuraApplication.getInstance() bytes_read = reply.read(self.DISK_WRITE_BUFFER_SIZE) while bytes_read: write_backup.write(bytes_read) bytes_read = reply.read(self.DISK_WRITE_BUFFER_SIZE) app.processEvents() if not self._verifyMd5Hash(temporary_backup_file.name, self._backup.get("md5_hash", "")): # Don't restore the backup if the MD5 hashes do not match. # This can happen if the download was interrupted. Logger.log( "w", "Remote and local MD5 hashes do not match, not restoring backup." ) self.restore_backup_error_message = self.DEFAULT_ERROR_MESSAGE # Tell Cura to place the backup back in the user data folder. with open(temporary_backup_file.name, "rb") as read_backup: cura_api = CuraApplication.getInstance().getCuraAPI() cura_api.backups.restoreBackup(read_backup.read(), self._backup.get("metadata", {})) self._job_done.set()
def _onRequestFinished(self, reply: QNetworkReply) -> None: http_status_code = reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) if not http_status_code: # Received no or empty reply return if reply.operation() == QNetworkAccessManager.PostOperation: if "/plugin/appkeys/request" in reply.url().toString( ): # Initial AppKey request if http_status_code == 201 or http_status_code == 202: Logger.log("w", "Start polling for AppKeys decision") if not self._appkey_request: return self._appkey_request.setUrl( reply.header(QNetworkRequest.LocationHeader)) self._appkey_request.setRawHeader(b"Content-Type", b"") self._appkey_poll_timer.start() elif http_status_code == 404: Logger.log( "w", "This instance of OctoPrint does not support AppKeys") self._appkey_request = None # type: Optional[QNetworkRequest] else: response = bytes(reply.readAll()).decode() Logger.log( "w", "Unknown response when requesting an AppKey: %d. OctoPrint said %s" % (http_status_code, response)) self._appkey_request = None # type: Optional[QNetworkRequest] if reply.operation() == QNetworkAccessManager.GetOperation: if "/plugin/appkeys/probe" in reply.url().toString( ): # Probe for AppKey support if http_status_code == 204: self._appkeys_supported = True else: self._appkeys_supported = False self.appKeysSupportedChanged.emit() if "/plugin/appkeys/request" in reply.url().toString( ): # Periodic AppKey request poll if http_status_code == 202: self._appkey_poll_timer.start() elif http_status_code == 200: Logger.log("d", "AppKey granted") self._appkey_request = None # type: Optional[QNetworkRequest] try: json_data = json.loads( bytes(reply.readAll()).decode("utf-8")) except json.decoder.JSONDecodeError: Logger.log( "w", "Received invalid JSON from octoprint instance.") return self._keys_cache[ self._appkey_instance_id] = json_data["api_key"] self.appKeyReceived.emit() elif http_status_code == 404: Logger.log("d", "AppKey denied") self._appkey_request = None # type: Optional[QNetworkRequest] else: response = bytes(reply.readAll()).decode() Logger.log( "w", "Unknown response when waiting for an AppKey: %d. OctoPrint said %s" % (http_status_code, response)) self._appkey_request = None # type: Optional[QNetworkRequest] if "api/settings" in reply.url().toString( ): # OctoPrint settings dump from /settings: self._instance_in_error = False if http_status_code == 200: Logger.log("d", "API key accepted by OctoPrint.") self._instance_api_key_accepted = True try: json_data = json.loads( bytes(reply.readAll()).decode("utf-8")) except json.decoder.JSONDecodeError: Logger.log( "w", "Received invalid JSON from octoprint instance.") json_data = {} if "feature" in json_data and "sdSupport" in json_data[ "feature"]: self._instance_supports_sd = json_data["feature"][ "sdSupport"] if "webcam" in json_data and "streamUrl" in json_data[ "webcam"]: stream_url = json_data["webcam"]["streamUrl"] if stream_url: #not empty string or None self._instance_supports_camera = True elif http_status_code == 401: Logger.log("d", "Invalid API key for OctoPrint.") self._instance_api_key_accepted = False elif http_status_code == 502 or http_status_code == 503: Logger.log("d", "OctoPrint is not running.") self._instance_api_key_accepted = False self._instance_in_error = True self._instance_responded = True self.selectedInstanceSettingsChanged.emit()
def _onRequestFinished(self, reply: QNetworkReply) -> None: if reply.error() == QNetworkReply.TimeoutError: Logger.log("w", "Got a timeout.") self.setViewPage("errored") self.resetDownload() return if reply.error() == QNetworkReply.HostNotFoundError: Logger.log("w", "Unable to reach server.") self.setViewPage("errored") self.resetDownload() return # HACK: These request are not handled independently at this moment, but together from the "packages" call do_not_handle = [ "materials_available", "materials_showcase", "materials_generic", "plugins_available", "plugins_showcase", ] if reply.operation() == QNetworkAccessManager.GetOperation: for type, url in self._request_urls.items(): # HACK: Do nothing because we'll handle these from the "packages" call if type in do_not_handle: continue if reply.url() == url: if reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) == 200: try: json_data = json.loads( bytes(reply.readAll()).decode("utf-8")) # Check for errors: if "errors" in json_data: for error in json_data["errors"]: Logger.log("e", "%s", error["title"]) return # Create model and apply metadata: if not self._models[type]: Logger.log("e", "Could not find the %s model.", type) break self._metadata[type] = json_data["data"] self._models[type].setMetadata( self._metadata[type]) # Do some auto filtering # TODO: Make multiple API calls in the future to handle this if type is "packages": self._models[type].setFilter( {"type": "plugin"}) self.buildMaterialsModels() self.buildPluginsModels() if type is "authors": self._models[type].setFilter( {"package_types": "material"}) if type is "materials_generic": self._models[type].setFilter( {"tags": "generic"}) self.metadataChanged.emit() if self.loadingComplete() is True: self.setViewPage("overview") return except json.decoder.JSONDecodeError: Logger.log( "w", "Marketplace: Received invalid JSON for %s.", type) break else: self.setViewPage("errored") self.resetDownload() return else: # Ignore any operation that is not a get operation pass
def _onRequestFinished(self, reply: QNetworkReply) -> None: http_status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) if not http_status_code: # Received no or empty reply return if reply.operation() == QNetworkAccessManager.PostOperation: if "/plugin/appkeys/request" in reply.url().toString(): # Initial AppKey request if http_status_code == 201 or http_status_code == 202: Logger.log("w", "Start polling for AppKeys decision") if not self._appkey_request: return self._appkey_request.setUrl(reply.header(QNetworkRequest.LocationHeader)) self._appkey_request.setRawHeader(b"Content-Type", b"") self._appkey_poll_timer.start() elif http_status_code == 404: Logger.log("w", "This instance of OctoPrint does not support AppKeys") self._appkey_request = None # type: Optional[QNetworkRequest] else: response = bytes(reply.readAll()).decode() Logger.log("w", "Unknown response when requesting an AppKey: %d. OctoPrint said %s" % (http_status_code, response)) self._appkey_request = None # type: Optional[QNetworkRequest] if reply.operation() == QNetworkAccessManager.GetOperation: if "/plugin/appkeys/probe" in reply.url().toString(): # Probe for AppKey support if http_status_code == 204: self._appkeys_supported = True else: self._appkeys_supported = False self.appKeysSupportedChanged.emit() if "/plugin/appkeys/request" in reply.url().toString(): # Periodic AppKey request poll if http_status_code == 202: self._appkey_poll_timer.start() elif http_status_code == 200: Logger.log("d", "AppKey granted") self._appkey_request = None # type: Optional[QNetworkRequest] try: json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) except json.decoder.JSONDecodeError: Logger.log("w", "Received invalid JSON from octoprint instance.") return self._keys_cache[self._appkey_instance_id] = json_data["api_key"] self.appKeyReceived.emit() elif http_status_code == 404: Logger.log("d", "AppKey denied") self._appkey_request = None # type: Optional[QNetworkRequest] else: response = bytes(reply.readAll()).decode() Logger.log("w", "Unknown response when waiting for an AppKey: %d. OctoPrint said %s" % (http_status_code, response)) self._appkey_request = None # type: Optional[QNetworkRequest] if "api/settings" in reply.url().toString(): # OctoPrint settings dump from /settings: self._instance_in_error = False if http_status_code == 200: Logger.log("d", "API key accepted by OctoPrint.") self._instance_api_key_accepted = True try: json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) except json.decoder.JSONDecodeError: Logger.log("w", "Received invalid JSON from octoprint instance.") json_data = {} if "feature" in json_data and "sdSupport" in json_data["feature"]: self._instance_supports_sd = json_data["feature"]["sdSupport"] if "webcam" in json_data and "streamUrl" in json_data["webcam"]: stream_url = json_data["webcam"]["streamUrl"] if stream_url: #not empty string or None self._instance_supports_camera = True elif http_status_code == 401: Logger.log("d", "Invalid API key for OctoPrint.") self._instance_api_key_accepted = False elif http_status_code == 502 or http_status_code == 503: Logger.log("d", "OctoPrint is not running.") self._instance_api_key_accepted = False self._instance_in_error = True self._instance_responded = True self.selectedInstanceSettingsChanged.emit()
def _onRequestFinished(self, reply: QNetworkReply) -> None: if reply.error() == QNetworkReply.TimeoutError: Logger.log("w", "Got a timeout.") self.setViewPage("errored") self.resetDownload() return if reply.error() == QNetworkReply.HostNotFoundError: Logger.log("w", "Unable to reach server.") self.setViewPage("errored") self.resetDownload() return if reply.operation() == QNetworkAccessManager.GetOperation: for type, url in self._request_urls.items(): if reply.url() == url: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 200: try: json_data = json.loads(bytes(reply.readAll()).decode("utf-8")) # Check for errors: if "errors" in json_data: for error in json_data["errors"]: Logger.log("e", "%s", error["title"]) return # Create model and apply metadata: if not self._models[type]: Logger.log("e", "Could not find the %s model.", type) break # HACK: Eventually get rid of the code from here... if type is "plugins_showcase" or type is "materials_showcase": self._metadata["plugins_showcase"] = json_data["data"]["plugin"]["packages"] self._models["plugins_showcase"].setMetadata(self._metadata["plugins_showcase"]) self._metadata["materials_showcase"] = json_data["data"]["material"]["authors"] self._models["materials_showcase"].setMetadata(self._metadata["materials_showcase"]) else: # ...until here. # This hack arises for multiple reasons but the main # one is because there are not separate API calls # for different kinds of showcases. self._metadata[type] = json_data["data"] self._models[type].setMetadata(self._metadata[type]) # Do some auto filtering # TODO: Make multiple API calls in the future to handle this if type is "packages": self._models[type].setFilter({"type": "plugin"}) if type is "authors": self._models[type].setFilter({"package_types": "material"}) if type is "materials_generic": self._models[type].setFilter({"tags": "generic"}) self.metadataChanged.emit() if self.loadingComplete() is True: self.setViewPage("overview") return except json.decoder.JSONDecodeError: Logger.log("w", "Toolbox: Received invalid JSON for %s.", type) break else: self.setViewPage("errored") self.resetDownload() return else: # Ignore any operation that is not a get operation pass
def sendingFinished(reply: QNetworkReply) -> None: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200: Logger.log("e", "Received error code from printer when syncing material: {code}, {text}".format( code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), text = reply.errorString() ))
def _onRequestFinished(self, reply: QNetworkReply) -> None: http_status_code = reply.attribute( QNetworkRequest.HttpStatusCodeAttribute) if not http_status_code: # Received no or empty reply self._onRequestFailed(reply) return if reply.operation() == QNetworkAccessManager.PostOperation: if "/plugin/appkeys/request" in reply.url().toString( ): # Initial AppKey request if http_status_code == 201 or http_status_code == 202: Logger.log("w", "Start polling for AppKeys decision") if not self._appkey_request: return self._appkey_request.setUrl( reply.header(QNetworkRequest.LocationHeader)) self._appkey_request.setRawHeader(b"Content-Type", b"") self._appkey_poll_timer.start() elif http_status_code == 404: Logger.log( "w", "This instance of OctoPrint does not support AppKeys") self._appkey_request = None # type: Optional[QNetworkRequest] else: response = bytes(reply.readAll()).decode() Logger.log( "w", "Unknown response when requesting an AppKey: %d. OctoPrint said %s" % (http_status_code, response)) self._appkey_request = None # type: Optional[QNetworkRequest] if reply.operation() == QNetworkAccessManager.GetOperation: if "/plugin/appkeys/probe" in reply.url().toString( ): # Probe for AppKey support if http_status_code == 204: self._instance_supports_appkeys = True else: self._instance_supports_appkeys = False self.appKeysSupportedChanged.emit() if "/plugin/appkeys/request" in reply.url().toString( ): # Periodic AppKey request poll if http_status_code == 202: self._appkey_poll_timer.start() elif http_status_code == 200: Logger.log("d", "AppKey granted") self._appkey_request = None # type: Optional[QNetworkRequest] try: json_data = json.loads( bytes(reply.readAll()).decode("utf-8")) except json.decoder.JSONDecodeError: Logger.log( "w", "Received invalid JSON from octoprint instance.") return api_key = json_data["api_key"] self._keys_cache[self._appkey_instance_id] = api_key global_container_stack = self._application.getGlobalContainerStack( ) if global_container_stack: global_container_stack.setMetaDataEntry( "octoprint_api_key", base64.b64encode( api_key.encode("ascii")).decode("ascii")) self.appKeyReceived.emit() elif http_status_code == 404: Logger.log("d", "AppKey denied") self._appkey_request = None # type: Optional[QNetworkRequest] else: response = bytes(reply.readAll()).decode() Logger.log( "w", "Unknown response when waiting for an AppKey: %d. OctoPrint said %s" % (http_status_code, response)) self._appkey_request = None # type: Optional[QNetworkRequest] if "api/settings" in reply.url().toString( ): # OctoPrint settings dump from /settings: self._instance_in_error = False if http_status_code == 200: Logger.log("d", "API key accepted by OctoPrint.") self._instance_api_key_accepted = True try: json_data = json.loads( bytes(reply.readAll()).decode("utf-8")) except json.decoder.JSONDecodeError: Logger.log( "w", "Received invalid JSON from octoprint instance.") json_data = {} if "feature" in json_data and "sdSupport" in json_data[ "feature"]: self._instance_supports_sd = json_data["feature"][ "sdSupport"] if "webcam" in json_data and "streamUrl" in json_data[ "webcam"]: stream_url = json_data["webcam"]["streamUrl"] if stream_url: #not empty string or None self._instance_supports_camera = True if "plugins" in json_data: self._power_plugins_manager.parsePluginData( json_data["plugins"]) self._instance_installed_plugins = list( json_data["plugins"].keys()) api_key = bytes(reply.request().rawHeader( b"X-Api-Key")).decode("utf-8") self.setApiKey(api_key) # store api key in key cache if self._settings_instance: self._settings_instance.setApiKey(api_key) self._settings_instance.resetOctoPrintUserName() self._settings_instance.getAdditionalData() self._settings_instance.parseSettingsData(json_data) self._settings_instance = None elif http_status_code == 401: Logger.log("d", "Invalid API key for OctoPrint.") self._instance_api_key_accepted = False elif http_status_code == 502 or http_status_code == 503: Logger.log("d", "OctoPrint is not running.") self._instance_api_key_accepted = False self._instance_in_error = True self._instance_responded = True self.selectedInstanceSettingsChanged.emit()
def sendMissingMaterials(self, reply: QNetworkReply) -> None: if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute ) != 200: #Got an error from the HTTP request. Logger.log( "e", "Couldn't request current material storage on printer. Not syncing materials." ) return remote_materials_list = reply.readAll().data().decode("utf-8") try: remote_materials_list = json.loads(remote_materials_list) except json.JSONDecodeError: Logger.log( "e", "Current material storage on printer was a corrupted reply.") return try: remote_materials_by_guid = { material["guid"]: material for material in remote_materials_list } #Index by GUID. except KeyError: Logger.log( "e", "Current material storage on printer was an invalid reply (missing GUIDs)." ) return container_registry = ContainerRegistry.getInstance() local_materials_list = filter( lambda material: ("GUID" in material and "version" in material and "id" in material), container_registry.findContainersMetadata(type="material")) local_materials_by_guid = { material["GUID"]: material for material in local_materials_list if material["id"] == material["base_file"] } for material in local_materials_list: #For each GUID get the material with the highest version number. try: if int(material["version"]) > local_materials_by_guid[ material["GUID"]]["version"]: local_materials_by_guid[material["GUID"]] = material except ValueError: Logger.log( "e", "Material {material_id} has invalid version number {number}." .format(material_id=material["id"], number=material["version"])) continue materials_to_send = set() #type: Set[Dict[str, Any]] for guid, material in local_materials_by_guid.items(): if guid not in remote_materials_by_guid: materials_to_send.add(material["id"]) continue try: if int(material["version"] ) > remote_materials_by_guid[guid]["version"]: materials_to_send.add(material["id"]) continue except KeyError: Logger.log( "e", "Current material storage on printer was an invalid reply (missing version)." ) return for file_path in Resources.getAllResourcesOfType( CuraApplication.ResourceTypes.MaterialInstanceContainer): try: mime_type = MimeTypeDatabase.getMimeTypeForFile(file_path) except MimeTypeDatabase.MimeTypeNotFoundError: continue #Not the sort of file we'd like to send then. _, file_name = os.path.split(file_path) material_id = urllib.parse.unquote_plus( mime_type.stripExtension(file_name)) if material_id not in materials_to_send: continue parts = [] with open(file_path, "rb") as f: parts.append( self.device._createFormPart( "name=\"file\"; filename=\"{file_name}\"".format( file_name=file_name), f.read())) signature_file_path = file_path + ".sig" if os.path.exists(signature_file_path): _, signature_file_name = os.path.split(signature_file_path) with open(signature_file_path, "rb") as f: parts.append( self.device._createFormPart( "name=\"signature_file\"; filename=\"{file_name}\"" .format(file_name=signature_file_name), f.read())) Logger.log( "d", "Syncing material {material_id} with cluster.".format( material_id=material_id)) self.device.postFormWithParts(target="materials/", parts=parts, on_finished=self.sendingFinished)