mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-20 05:07:50 -06:00
Refactor CloudApiClient (and ToolpathUploader) to use HttpRequestManager
Has the benefit of a more unified Http request management + timeouts CURA-7290
This commit is contained in:
parent
15f813a4ff
commit
f3c66c3189
3 changed files with 74 additions and 58 deletions
|
@ -1,11 +1,11 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# !/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtCore import QUrl
|
||||
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager
|
||||
from typing import Optional, Callable, Any, Tuple, cast
|
||||
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
|
||||
from typing import Callable, Any, Tuple
|
||||
|
||||
from UM.Logger import Logger
|
||||
from UM.TaskManagement.HttpRequestManager import HttpRequestManager
|
||||
|
||||
from ..Models.Http.CloudPrintJobResponse import CloudPrintJobResponse
|
||||
|
||||
|
@ -23,16 +23,16 @@ class ToolPathUploader:
|
|||
BYTES_PER_REQUEST = 256 * 1024
|
||||
|
||||
## Creates a mesh upload object.
|
||||
# \param manager: The network access manager that will handle the HTTP requests.
|
||||
# \param http: The HttpRequestManager that will handle the HTTP requests.
|
||||
# \param print_job: The print job response that was returned by the cloud after registering the upload.
|
||||
# \param data: The mesh bytes to be uploaded.
|
||||
# \param on_finished: The method to be called when done.
|
||||
# \param on_progress: The method to be called when the progress changes (receives a percentage 0-100).
|
||||
# \param on_error: The method to be called when an error occurs.
|
||||
def __init__(self, manager: QNetworkAccessManager, print_job: CloudPrintJobResponse, data: bytes,
|
||||
def __init__(self, http: HttpRequestManager, print_job: CloudPrintJobResponse, data: bytes,
|
||||
on_finished: Callable[[], Any], on_progress: Callable[[int], Any], on_error: Callable[[], Any]
|
||||
) -> None:
|
||||
self._manager = manager
|
||||
self._http = http
|
||||
self._print_job = print_job
|
||||
self._data = data
|
||||
|
||||
|
@ -43,25 +43,12 @@ class ToolPathUploader:
|
|||
self._sent_bytes = 0
|
||||
self._retries = 0
|
||||
self._finished = False
|
||||
self._reply = None # type: Optional[QNetworkReply]
|
||||
|
||||
## Returns the print job for which this object was created.
|
||||
@property
|
||||
def printJob(self):
|
||||
return self._print_job
|
||||
|
||||
## Creates a network request to the print job upload URL, adding the needed content range header.
|
||||
def _createRequest(self) -> QNetworkRequest:
|
||||
request = QNetworkRequest(QUrl(self._print_job.upload_url))
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, self._print_job.content_type)
|
||||
|
||||
first_byte, last_byte = self._chunkRange()
|
||||
content_range = "bytes {}-{}/{}".format(first_byte, last_byte - 1, len(self._data))
|
||||
request.setRawHeader(b"Content-Range", content_range.encode())
|
||||
Logger.log("i", "Uploading %s to %s", content_range, self._print_job.upload_url)
|
||||
|
||||
return request
|
||||
|
||||
## Determines the bytes that should be uploaded next.
|
||||
# \return: A tuple with the first and the last byte to upload.
|
||||
def _chunkRange(self) -> Tuple[int, int]:
|
||||
|
@ -88,13 +75,23 @@ class ToolPathUploader:
|
|||
raise ValueError("The upload is already finished")
|
||||
|
||||
first_byte, last_byte = self._chunkRange()
|
||||
request = self._createRequest()
|
||||
content_range = "bytes {}-{}/{}".format(first_byte, last_byte - 1, len(self._data))
|
||||
|
||||
# now send the reply and subscribe to the results
|
||||
self._reply = self._manager.put(request, self._data[first_byte:last_byte])
|
||||
self._reply.finished.connect(self._finishedCallback)
|
||||
self._reply.uploadProgress.connect(self._progressCallback)
|
||||
self._reply.error.connect(self._errorCallback)
|
||||
headers = {
|
||||
"Content-Type": self._print_job.content_type,
|
||||
"Content-Range": content_range
|
||||
}
|
||||
|
||||
Logger.log("i", "Uploading %s to %s", content_range, self._print_job.upload_url)
|
||||
|
||||
self._http.put(
|
||||
url = self._print_job.upload_url,
|
||||
headers_dict = headers,
|
||||
data = self._data[first_byte:last_byte],
|
||||
callback = self._finishedCallback,
|
||||
error_callback = self._errorCallback,
|
||||
upload_progress_callback = self._progressCallback
|
||||
)
|
||||
|
||||
## Handles an update to the upload progress
|
||||
# \param bytes_sent: The amount of bytes sent in the current request.
|
||||
|
@ -106,16 +103,14 @@ class ToolPathUploader:
|
|||
self._on_progress(int(total_sent / len(self._data) * 100))
|
||||
|
||||
## Handles an error uploading.
|
||||
def _errorCallback(self) -> None:
|
||||
reply = cast(QNetworkReply, self._reply)
|
||||
def _errorCallback(self, reply: QNetworkReply, error: QNetworkReply.NetworkError) -> None:
|
||||
body = bytes(reply.readAll()).decode()
|
||||
Logger.log("e", "Received error while uploading: %s", body)
|
||||
self.stop()
|
||||
self._on_error()
|
||||
|
||||
## Checks whether a chunk of data was uploaded successfully, starting the next chunk if needed.
|
||||
def _finishedCallback(self) -> None:
|
||||
reply = cast(QNetworkReply, self._reply)
|
||||
def _finishedCallback(self, reply: QNetworkReply) -> None:
|
||||
Logger.log("i", "Finished callback %s %s",
|
||||
reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), reply.url().toString())
|
||||
|
||||
|
@ -133,7 +128,7 @@ class ToolPathUploader:
|
|||
|
||||
# Http codes that are not to be retried are assumed to be errors.
|
||||
if status_code > 308:
|
||||
self._errorCallback()
|
||||
self._errorCallback(reply, None)
|
||||
return
|
||||
|
||||
Logger.log("d", "status_code: %s, Headers: %s, body: %s", status_code,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue