File size request from HTTP header, handled the indeterminate size case

This commit is contained in:
Marco Dalla Tiezza
2024-06-13 01:54:59 +02:00
parent 52c4fbcce9
commit 1d795b688e
4 changed files with 136 additions and 88 deletions

View File

@@ -6635,7 +6635,7 @@ G@\x11\x10HG\x93Hp\xec\x0au\xe3\xcd\x1e\xf4\
>k\xd0\xd3b\x1eG\xb5_d\xde\xb6{\x8f\x95\xc5\ >k\xd0\xd3b\x1eG\xb5_d\xde\xb6{\x8f\x95\xc5\
U\xaf\xbc\xfd\xe9\xb5\x9f\xe5\xe3}r\xba?\xbbI\x06\ U\xaf\xbc\xfd\xe9\xb5\x9f\xe5\xe3}r\xba?\xbbI\x06\
\xfe\xfc\x0f\xf4\xcd*2\ \xfe\xfc\x0f\xf4\xcd*2\
\x00\x00\x06\x95\ \x00\x00\x070\
i\ i\
mport QtQuick\x0d\x0ai\ mport QtQuick\x0d\x0ai\
mport QtQuick.Wi\ mport QtQuick.Wi\
@@ -6674,75 +6674,84 @@ ceived\x0d\x0a \
progressBar.to =\ progressBar.to =\
bytesTotal\x0d\x0a \ bytesTotal\x0d\x0a \
}\x0d\x0a\x0d\x0a functi\ }\x0d\x0a\x0d\x0a functi\
on updateStatus(\ on setIndetermin\
arg) {\x0d\x0a \ ateBar() {\x0d\x0a \
progressLabel.te\ progressBar.\
xt = arg\x0d\x0a }\x0d\ indeterminate = \
\x0a\x0d\x0a Page {\x0d\x0a \ true\x0d\x0a }\x0d\x0a\x0d\x0a \
id: page\x0d\ function upda\
\x0a anchors\ teStatus(arg) {\x0d\
.fill: parent\x0d\x0a\x0d\ \x0a progres\
\x0a ColumnL\ sLabel.text = ar\
ayout {\x0d\x0a \ g\x0d\x0a }\x0d\x0a\x0d\x0a \
id: columnL\ Page {\x0d\x0a \
ayout\x0d\x0a \ id: page\x0d\x0a \
anchors.fill:\ anchors.fill: \
parent\x0d\x0a\x0d\x0a \ parent\x0d\x0a\x0d\x0a \
Label {\x0d\x0a\ ColumnLayout {\
\ \x0d\x0a id\
text: qsTr(\x22Down\ : columnLayout\x0d\x0a\
loading in progr\ anch\
ess...\x22)\x0d\x0a \ ors.fill: parent\
Layout\ \x0d\x0a\x0d\x0a \
.alignment: Qt.A\ Label {\x0d\x0a \
lignHCenter | Qt\
.AlignVCenter\x0d\x0a \
}\x0d\x0a\x0d\x0a\
Prog\
ressBar {\x0d\x0a \
id: p\
rogressBar\x0d\x0a \
Layo\
ut.rightMargin: \
20\x0d\x0a \
Layout.leftM\
argin: 20\x0d\x0a \
Layou\
t.fillWidth: tru\
e\x0d\x0a \
value: 0\x0d\x0a \
to:\
0\x0d\x0a \
}\x0d\x0a\x0d\x0a \
Label {\x0d\x0a \
id: pr\
ogressLabel\x0d\x0a \
Lay\
out.alignment: Q\
t.AlignHCenter |\
Qt.AlignVCenter\
\x0d\x0a }\x0d\
\x0a\x0d\x0a B\
utton {\x0d\x0a \
text: q\ text: q\
sTr(\x22Abort\x22)\x0d\x0a \ sTr(\x22Downloading\
ic\ in progress...\x22\
on.source: \x22qrc:\ )\x0d\x0a \
/images/icons/ab\ Layout.alignm\
ort.svg\x22\x0d\x0a \ ent: Qt.AlignHCe\
displa\ nter | Qt.AlignV\
y: AbstractButto\ Center\x0d\x0a \
n.TextBesideIcon\ }\x0d\x0a\x0d\x0a \
ProgressBar\
{\x0d\x0a \
id: progress\
Bar\x0d\x0a \
Layout.righ\
tMargin: 20\x0d\x0a \
Lay\
out.leftMargin: \
20\x0d\x0a \
Layout.fillW\
idth: true\x0d\x0a \
inde\
terminate: false\
\x0d\x0a \ \x0d\x0a \
Layout.alignme\ value: 0\x0d\x0a \
nt: Qt.AlignHCen\ to: \
ter | Qt.AlignBo\ 0\x0d\x0a }\
ttom\x0d\x0a \ \x0d\x0a\x0d\x0a \
onClicked:\ Label {\x0d\x0a \
{ onAbort() }\x0d\x0a\ id: pro\
gressLabel\x0d\x0a \
Layo\
ut.alignment: Qt\
.AlignHCenter | \
Qt.AlignVCenter\x0d\
\x0a }\x0d\x0a\
\x0d\x0a Bu\
tton {\x0d\x0a \
Layout.a\
lignment: Qt.Ali\
gnHCenter | Qt.A\
lignBottom\x0d\x0a \
text\
: qsTr(\x22Abort\x22)\x0d\
\x0a \
icon.source: \x22q\
rc:/images/icons\
/abort.svg\x22\x0d\x0a \
dis\
play: AbstractBu\
tton.TextBesideI\
con\x0d\x0a \
flat: true\x0d\
\x0a \
onClicked: { on\
Abort() }\x0d\x0a \
}\x0d\x0a \ }\x0d\x0a \
}\x0d\x0a }\x0d\ }\x0d\x0a }\x0d\x0a}\x0d\x0a\
\x0a}\x0d\x0a\
\x00\x00\x05\xac\ \x00\x00\x05\xac\
i\ i\
mport QtQuick\x0d\x0ai\ mport QtQuick\x0d\x0ai\
@@ -7293,12 +7302,12 @@ qt_resource_struct = b"\
\x00\x00\x01\x8f\xff^8P\ \x00\x00\x01\x8f\xff^8P\
\x00\x00\x03<\x00\x01\x00\x00\x00\x01\x00\x01>\xe2\ \x00\x00\x03<\x00\x01\x00\x00\x00\x01\x00\x01>\xe2\
\x00\x00\x01\x8f\xff^8P\ \x00\x00\x01\x8f\xff^8P\
\x00\x00\x05\xa8\x00\x00\x00\x00\x00\x01\x00\x01\x9f\xdf\ \x00\x00\x05\xa8\x00\x00\x00\x00\x00\x01\x00\x01\xa0z\
\x00\x00\x01\x8f\xff^8P\ \x00\x00\x01\x8f\xff^8P\
\x00\x00\x03r\x00\x01\x00\x00\x00\x01\x00\x01I\x0c\ \x00\x00\x03r\x00\x01\x00\x00\x00\x01\x00\x01I\x0c\
\x00\x00\x01\x8f\xff^8_\ \x00\x00\x01\x8f\xff^8_\
\x00\x00\x05\x86\x00\x00\x00\x00\x00\x01\x00\x01\x99F\ \x00\x00\x05\x86\x00\x00\x00\x00\x00\x01\x00\x01\x99F\
\x00\x00\x01\x90\x03\xb0\x82B\ \x00\x00\x01\x90\x0e\xde\xeeO\
\x00\x00\x03X\x00\x02\x00\x00\x00\x04\x00\x00\x00+\ \x00\x00\x03X\x00\x02\x00\x00\x00\x04\x00\x00\x00+\
\x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x04\xc4\x00\x01\x00\x00\x00\x01\x00\x01v\x14\ \x00\x00\x04\xc4\x00\x01\x00\x00\x00\x01\x00\x01v\x14\
@@ -7317,13 +7326,13 @@ qt_resource_struct = b"\
\x00\x00\x01\x8f\xff^8P\ \x00\x00\x01\x8f\xff^8P\
\x00\x00\x05\x06\x00\x00\x00\x00\x00\x01\x00\x01\x85\xad\ \x00\x00\x05\x06\x00\x00\x00\x00\x00\x01\x00\x01\x85\xad\
\x00\x00\x01\x8f\xff^8P\ \x00\x00\x01\x8f\xff^8P\
\x00\x00\x05\xdc\x00\x01\x00\x00\x00\x01\x00\x01\xa8\x92\ \x00\x00\x05\xdc\x00\x01\x00\x00\x00\x01\x00\x01\xa9-\
\x00\x00\x01\x8f\xff^8_\ \x00\x00\x01\x8f\xff^8_\
\x00\x00\x06$\x00\x01\x00\x00\x00\x01\x00\x01\xae\xd7\ \x00\x00\x06$\x00\x01\x00\x00\x00\x01\x00\x01\xafr\
\x00\x00\x01\x8f\xff^8_\ \x00\x00\x01\x8f\xff^8_\
\x00\x00\x05\xc0\x00\x01\x00\x00\x00\x01\x00\x01\xa5\x8f\ \x00\x00\x05\xc0\x00\x01\x00\x00\x00\x01\x00\x01\xa6*\
\x00\x00\x01\x8f\xff^8_\ \x00\x00\x01\x8f\xff^8_\
\x00\x00\x06\x00\x00\x01\x00\x00\x00\x01\x00\x01\xabU\ \x00\x00\x06\x00\x00\x01\x00\x00\x00\x01\x00\x01\xab\xf0\
\x00\x00\x01\x8f\xff^8_\ \x00\x00\x01\x8f\xff^8_\
" "

View File

@@ -226,7 +226,6 @@ class UIArtemis(QObject):
self.downloader.finished.connect(self.update_manager.post_download_db) self.downloader.finished.connect(self.update_manager.post_download_db)
self.downloader.on_start( self.downloader.on_start(
self.update_manager.remote_db_url, self.update_manager.remote_db_url,
self.update_manager.remote_db_size,
DATA_DIR DATA_DIR
) )

View File

@@ -1,3 +1,5 @@
import requests
from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtCore import QObject, Slot, Signal, QUrl, QSaveFile, QDir, QIODevice from PySide6.QtCore import QObject, Slot, Signal, QUrl, QSaveFile, QDir, QIODevice
from PySide6.QtNetwork import QNetworkReply, QNetworkRequest, QNetworkAccessManager from PySide6.QtNetwork import QNetworkReply, QNetworkRequest, QNetworkAccessManager
@@ -7,11 +9,12 @@ from artemis.utils.constants import Messages
class UIDownloader(QObject): class UIDownloader(QObject):
# Python > QML Signals # Python > QML Signals
finished = Signal()
show_ui = Signal() show_ui = Signal()
close_ui = Signal() close_ui = Signal()
update_progress_bar = Signal(int, int) update_progress_bar = Signal(int, int)
set_indeterminate_bar = Signal()
update_status = Signal(str) update_status = Signal(str)
finished = Signal()
def __init__(self, parent): def __init__(self, parent):
@@ -25,6 +28,10 @@ class UIDownloader(QObject):
self.file_url = None self.file_url = None
self.file_size = None self.file_size = None
self.dest_file = None
self.file = None
self.manager = None
self.reply = None
self._connect() self._connect()
@@ -37,17 +44,22 @@ class UIDownloader(QObject):
self.show_ui.connect(self._window.show) self.show_ui.connect(self._window.show)
self.close_ui.connect(self._window.close) self.close_ui.connect(self._window.close)
self.update_progress_bar.connect(self._window.updateProgressBar) self.update_progress_bar.connect(self._window.updateProgressBar)
self.set_indeterminate_bar.connect(self._window.setIndeterminateBar)
self.update_status.connect(self._window.updateStatus) self.update_status.connect(self._window.updateStatus)
def on_start(self, url, filesize, save_path): def on_start(self, url, save_path):
""" Start the download of the DB taking the needed url and size from """ Start the download process using the specified URL
the attributes of the UpdatesController class
Args:
url (str): url from where download the file
save_path (str): path where to save the downloaded file
""" """
self.show_ui.emit() self.show_ui.emit()
self.file_url = QUrl(url) self.file_url = QUrl(url)
self.file_size = filesize self.file_size = self._get_filesize(url)
dest_path = QDir(save_path) dest_path = QDir(save_path)
self.dest_file = dest_path.filePath(self.file_url.fileName()) self.dest_file = dest_path.filePath(self.file_url.fileName())
self.file = QSaveFile(self.dest_file) self.file = QSaveFile(self.dest_file)
@@ -69,7 +81,8 @@ class UIDownloader(QObject):
@Slot() @Slot()
def on_abort(self): def on_abort(self):
""" Stop the download when user press abort button """ """ Stop the download when user presses the abort button
"""
if self.reply: if self.reply:
self.reply.abort() self.reply.abort()
self.update_progress_bar.emit(0, 0) self.update_progress_bar.emit(0, 0)
@@ -80,7 +93,8 @@ class UIDownloader(QObject):
@Slot() @Slot()
def on_ready_read(self): def on_ready_read(self):
""" Get available bytes and store them into the file """ """ Write available bytes to the file
"""
if self.reply: if self.reply:
if self.reply.error() == QNetworkReply.NoError: if self.reply.error() == QNetworkReply.NoError:
self.file.write(self.reply.readAll()) self.file.write(self.reply.readAll())
@@ -88,8 +102,9 @@ class UIDownloader(QObject):
@Slot() @Slot()
def on_finished(self): def on_finished(self):
""" Delete reply, close the file, check the hash for integrity, """ Finalize the download process and if no errors
extract the database and delete the downloaded zip occurrs emits the finished signal usefulle for
a callback
""" """
if self.reply: if self.reply:
self.reply.deleteLater() self.reply.deleteLater()
@@ -105,10 +120,13 @@ class UIDownloader(QObject):
@Slot(int, int) @Slot(int, int)
def on_progress(self, bytesReceived: int): def on_progress(self, bytesReceived: int):
""" Update progress bar and label """ Update progress bar and status label
""" """
if self.file_size is not None:
self.update_status.emit("{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, self.file_size/10**6)) self.update_status.emit("{:.1f} Mb / {:.1f} Mb".format(bytesReceived/10**6, self.file_size/10**6))
self.update_progress_bar.emit(bytesReceived, self.file_size) self.update_progress_bar.emit(bytesReceived, self.file_size)
else:
self.update_status.emit("{:.1f} Mb".format(bytesReceived/10**6))
@Slot(QNetworkReply.NetworkError) @Slot(QNetworkReply.NetworkError)
@@ -122,6 +140,22 @@ class UIDownloader(QObject):
) )
def _get_filesize(self, url):
""" Get the file size by sending a HEAD request to the URL.
If the Content-Length in HTTP headers is missing, returns None
Args:
url (str): URL to check the file size
"""
try:
response = requests.get(url, stream=True)
size = int(response.headers.get('content-length'))
return size
except:
self.set_indeterminate_bar.emit()
return None
def show_popup_error(self, error_msg): def show_popup_error(self, error_msg):
self._parent.dialog_popup( self._parent.dialog_popup(
Messages.DIALOG_TYPE_ERROR, Messages.DIALOG_TYPE_ERROR,

View File

@@ -29,6 +29,10 @@ Window {
progressBar.to = bytesTotal progressBar.to = bytesTotal
} }
function setIndeterminateBar() {
progressBar.indeterminate = true
}
function updateStatus(arg) { function updateStatus(arg) {
progressLabel.text = arg progressLabel.text = arg
} }
@@ -51,6 +55,7 @@ Window {
Layout.rightMargin: 20 Layout.rightMargin: 20
Layout.leftMargin: 20 Layout.leftMargin: 20
Layout.fillWidth: true Layout.fillWidth: true
indeterminate: false
value: 0 value: 0
to: 0 to: 0
} }
@@ -61,10 +66,11 @@ Window {
} }
Button { Button {
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
text: qsTr("Abort") text: qsTr("Abort")
icon.source: "qrc:/images/icons/abort.svg" icon.source: "qrc:/images/icons/abort.svg"
display: AbstractButton.TextBesideIcon display: AbstractButton.TextBesideIcon
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom flat: true
onClicked: { onAbort() } onClicked: { onAbort() }
} }
} }