mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-12 09:17:50 -06:00
Don't send print job in chunks
Previously the print job was sent with multiple PUT requests. This was necessary since the request was made with the Python Requests library, which freezes the interface while it's running. By breaking the upload up in chunks, it would at least periodically keep updating the interface (4 times per second or so, depending on your internet speed and Ultimaker's). Later on, this was replaced by a QNetworkRequest which doesn't freeze the interface in a refactor, but it was still broken up in chunks. Recently that was again refactored to use Uranium's HttpRequestManager, which under the covers also uses QNetworkRequest. This also doesn't freeze while uploading, which is good. However for some reason the second chunk would always give a QNetworkReply::ProtocolUnknownError, which is a bit of a catch-all error for any HTTP status codes not supported by Qt. I was not able to figure out what was really going wrong there, but it has something to do with the content-range header and making multiple requests. Instead of fixing that, I've removed the chunking. This simplifies the code a lot and doesn't have any implications for the user, since it still doesn't freeze the interface while the network request is ongoing. It should be slightly faster to upload, and reduce load on the server too. However the disadvantage is that the original bug is probably still there if it was a bug in the HttpRequestManager. If it was a bug in the ToolPathUploader I probably deleted the bug here. Contributes to issue CURA-7488.
This commit is contained in:
parent
d9c768e0d3
commit
7e10e74e9e
1 changed files with 12 additions and 44 deletions
|
@ -20,9 +20,6 @@ class ToolPathUploader:
|
|||
# The HTTP codes that should trigger a retry.
|
||||
RETRY_HTTP_CODES = {500, 502, 503, 504}
|
||||
|
||||
# The amount of bytes to send per request
|
||||
BYTES_PER_REQUEST = 256 * 1024
|
||||
|
||||
def __init__(self, http: HttpRequestManager, print_job: CloudPrintJobResponse, data: bytes,
|
||||
on_finished: Callable[[], Any], on_progress: Callable[[int], Any], on_error: Callable[[], Any]
|
||||
) -> None:
|
||||
|
@ -44,7 +41,6 @@ class ToolPathUploader:
|
|||
self._on_progress = on_progress
|
||||
self._on_error = on_error
|
||||
|
||||
self._sent_bytes = 0
|
||||
self._retries = 0
|
||||
self._finished = False
|
||||
|
||||
|
@ -54,23 +50,14 @@ class ToolPathUploader:
|
|||
|
||||
return self._print_job
|
||||
|
||||
def _chunkRange(self) -> Tuple[int, int]:
|
||||
"""Determines the bytes that should be uploaded next.
|
||||
|
||||
:return: A tuple with the first and the last byte to upload.
|
||||
"""
|
||||
last_byte = min(len(self._data), self._sent_bytes + self.BYTES_PER_REQUEST)
|
||||
return self._sent_bytes, last_byte
|
||||
|
||||
def start(self) -> None:
|
||||
"""Starts uploading the mesh."""
|
||||
|
||||
if self._finished:
|
||||
# reset state.
|
||||
self._sent_bytes = 0
|
||||
self._retries = 0
|
||||
self._finished = False
|
||||
self._uploadChunk()
|
||||
self._upload()
|
||||
|
||||
def stop(self):
|
||||
"""Stops uploading the mesh, marking it as finished."""
|
||||
|
@ -78,26 +65,18 @@ class ToolPathUploader:
|
|||
Logger.log("i", "Stopped uploading")
|
||||
self._finished = True
|
||||
|
||||
def _uploadChunk(self) -> None:
|
||||
"""Uploads a chunk of the mesh to the cloud."""
|
||||
|
||||
def _upload(self) -> None:
|
||||
"""
|
||||
Uploads the print job to the cloud printer.
|
||||
"""
|
||||
if self._finished:
|
||||
raise ValueError("The upload is already finished")
|
||||
|
||||
first_byte, last_byte = self._chunkRange()
|
||||
content_range = "bytes {}-{}/{}".format(first_byte, last_byte - 1, len(self._data))
|
||||
|
||||
headers = {
|
||||
"Content-Type": cast(str, self._print_job.content_type),
|
||||
"Content-Range": content_range
|
||||
} # type: Dict[str, str]
|
||||
|
||||
Logger.log("i", "Uploading %s to %s", content_range, self._print_job.upload_url)
|
||||
|
||||
Logger.log("i", "Uploading print to {upload_url}".format(upload_url = self._print_job.upload_url))
|
||||
self._http.put(
|
||||
url = cast(str, self._print_job.upload_url),
|
||||
headers_dict = headers,
|
||||
data = self._data[first_byte:last_byte],
|
||||
headers_dict = {"Content-Type": cast(str, self._print_job.content_type)},
|
||||
data = self._data,
|
||||
callback = self._finishedCallback,
|
||||
error_callback = self._errorCallback,
|
||||
upload_progress_callback = self._progressCallback
|
||||
|
@ -111,8 +90,7 @@ class ToolPathUploader:
|
|||
"""
|
||||
Logger.log("i", "Progress callback %s / %s", bytes_sent, bytes_total)
|
||||
if bytes_total:
|
||||
total_sent = self._sent_bytes + bytes_sent
|
||||
self._on_progress(int(total_sent / len(self._data) * 100))
|
||||
self._on_progress(int(bytes_sent / len(self._data) * 100))
|
||||
|
||||
## Handles an error uploading.
|
||||
def _errorCallback(self, reply: QNetworkReply, error: QNetworkReply.NetworkError) -> None:
|
||||
|
@ -136,7 +114,7 @@ class ToolPathUploader:
|
|||
self._retries += 1
|
||||
Logger.log("i", "Retrying %s/%s request %s", self._retries, self.MAX_RETRIES, reply.url().toString())
|
||||
try:
|
||||
self._uploadChunk()
|
||||
self._upload()
|
||||
except ValueError: # Asynchronously it could have completed in the meanwhile.
|
||||
pass
|
||||
return
|
||||
|
@ -148,16 +126,6 @@ class ToolPathUploader:
|
|||
|
||||
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 _chunkUploaded(self) -> None:
|
||||
"""Handles a chunk of data being uploaded, starting the next chunk if needed."""
|
||||
|
||||
# We got a successful response. Let's start the next chunk or report the upload is finished.
|
||||
first_byte, last_byte = self._chunkRange()
|
||||
self._sent_bytes += last_byte - first_byte
|
||||
if self._sent_bytes >= len(self._data):
|
||||
self.stop()
|
||||
self._on_finished()
|
||||
else:
|
||||
self._uploadChunk()
|
||||
self.stop()
|
||||
self._on_finished()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue