Save partial downloads on disk, not on RAM

This commit is contained in:
Alex Spataru 2016-11-13 17:56:10 -06:00
parent 62573c21bc
commit 1cbf20f156
4 changed files with 81 additions and 41 deletions

View File

@ -39,6 +39,9 @@
#include "Downloader.h"
static const QString PARTIAL_DOWN (".part");
static const QDir DOWNLOAD_DIR (QDir::homePath() + "/Downloads/");
Downloader::Downloader (QWidget* parent) : QWidget (parent) {
m_ui = new Ui::Downloader;
m_ui->setupUi (this);
@ -47,7 +50,8 @@ Downloader::Downloader (QWidget* parent) : QWidget (parent) {
m_manager = new QNetworkAccessManager();
/* Initialize internal values */
m_filePath = "";
m_url = "";
m_fileName = "";
m_startTime = 0;
m_useCustomProcedures = false;
@ -82,6 +86,17 @@ bool Downloader::useCustomInstallProcedures() const {
return m_useCustomProcedures;
}
/**
* Changes the URL, which is used to indentify the downloader dialog
* with an \c Updater instance
*
* \note the \a url parameter is not the download URL, it is the URL of
* the AppCast file
*/
void Downloader::setUrlId (const QString& url) {
m_url = url;
}
/**
* Begins downloading the file at the given \a url
*/
@ -96,25 +111,42 @@ void Downloader::startDownload (const QUrl& url) {
m_startTime = QDateTime::currentDateTime().toTime_t();
m_reply = m_manager->get (QNetworkRequest (url));
/* Ensure that downloads directory exists */
if (!DOWNLOAD_DIR.exists())
DOWNLOAD_DIR.mkpath (".");
/* Remove old downloads */
QFile::remove (DOWNLOAD_DIR.filePath (m_fileName));
QFile::remove (DOWNLOAD_DIR.filePath (m_fileName + PARTIAL_DOWN));
/* Update UI when download progress changes or download finishes */
connect (m_reply, SIGNAL (downloadProgress (qint64, qint64)),
this, SLOT (updateProgress (qint64, qint64)));
connect (m_reply, SIGNAL (redirected (QUrl)),
this, SLOT (startDownload (QUrl)));
connect (m_reply, SIGNAL (finished()),
this, SLOT (onDownloadFinished()));
showNormal();
}
/**
* Changes the name of the downloaded file
*/
void Downloader::setFileName (const QString& file) {
m_fileName = file;
if (m_fileName.isEmpty())
m_fileName = "QSU_Update.bin";
}
/**
* Opens the downloaded file.
* \note If the downloaded file is not found, then the function will alert the
* user about the error.
*/
void Downloader::openDownload() {
if (!m_filePath.isEmpty())
QDesktopServices::openUrl (QUrl::fromLocalFile (m_filePath));
if (!m_fileName.isEmpty())
QDesktopServices::openUrl (QUrl::fromLocalFile (DOWNLOAD_DIR.filePath (
m_fileName)));
else {
QMessageBox::critical (this,
@ -136,6 +168,13 @@ void Downloader::installUpdate() {
if (useCustomInstallProcedures())
return;
/* Update labels */
m_ui->stopButton->setText (tr ("Close"));
m_ui->downloadLabel->setText (tr ("Download complete!"));
m_ui->timeLabel->setText (tr ("The installer will open separately")
+ "...");
/* Ask the user to install the download */
QMessageBox box;
box.setIcon (QMessageBox::Question);
box.setDefaultButton (QMessageBox::Ok);
@ -146,11 +185,13 @@ void Downloader::installUpdate() {
"quit the application.")
+ "</h3>");
/* User wants to install the download */
if (box.exec() == QMessageBox::Ok) {
if (!useCustomInstallProcedures())
openDownload();
}
/* Wait */
else {
m_ui->openButton->setEnabled (true);
m_ui->openButton->setVisible (true);
@ -182,24 +223,9 @@ void Downloader::cancelDownload() {
}
/**
* Writes the downloaded data to a temp. directory and updates the UI controls.
* \note If the function detects that the downloaded data is an HTML file
* (e.g. a redirection notice from the server), the function will add the
* *.html extension to the downloaded file. This ensures that the download
* will be resumed when the OS opens a web-browser with the redirection
* notice.
* Writes the downloaded data to the disk
*/
void Downloader::onDownloadFinished() {
m_ui->stopButton->setText (tr ("Close"));
m_ui->downloadLabel->setText (tr ("Download complete!"));
m_ui->timeLabel->setText (tr ("The installer will open separately")
+ "...");
QByteArray data = m_reply->readAll();
if (!data.isEmpty()) {
QString name = m_reply->url().toString().split ("/").last();
void Downloader::saveFile (qint64 received, qint64 total) {
/* Check if we need to redirect */
QUrl url = m_reply->attribute (
QNetworkRequest::RedirectionTargetAttribute).toUrl();
@ -209,21 +235,28 @@ void Downloader::onDownloadFinished() {
}
/* Save downloaded data to disk */
QFile file (QDir::tempPath() + "/" + name);
if (file.open (QIODevice::WriteOnly)) {
file.write (data);
QFile file (DOWNLOAD_DIR.filePath (m_fileName + PARTIAL_DOWN));
if (file.open (QIODevice::WriteOnly | QIODevice::Append)) {
file.write (m_reply->readAll());
file.close();
m_filePath = file.fileName();
emit downloadFinished (m_reply->url().toString(), m_filePath);
}
/* Open downloaded update */
if (received >= total && total > 0) {
/* Rename file */
QFile::rename (DOWNLOAD_DIR.filePath (m_fileName + PARTIAL_DOWN),
DOWNLOAD_DIR.filePath (m_fileName));
/* Notify application */
emit downloadFinished (m_url, DOWNLOAD_DIR.filePath (m_fileName));
/* Install the update */
m_reply->close();
installUpdate();
}
}
/**
* Calculates the appropiate size units (bytes, KB or MB) for the received
* data and the total download size. Then, this function proceeds to update the
@ -268,6 +301,7 @@ void Downloader::updateProgress (qint64 received, qint64 total) {
calculateSizes (received, total);
calculateTimeRemaining (received, total);
saveFile (received, total);
}
else {

View File

@ -56,14 +56,16 @@ class Downloader : public QWidget {
bool useCustomInstallProcedures() const;
public slots:
void setUrlId (const QString& url);
void startDownload (const QUrl& url);
void setFileName (const QString& file);
void setUseCustomInstallProcedures (const bool custom);
private slots:
void openDownload();
void installUpdate();
void cancelDownload();
void onDownloadFinished();
void saveFile (qint64 received, qint64 total);
void calculateSizes (qint64 received, qint64 total);
void updateProgress (qint64 received, qint64 total);
void calculateTimeRemaining (qint64 received, qint64 total);
@ -72,8 +74,9 @@ class Downloader : public QWidget {
qreal round (const qreal& input);
private:
QString m_url;
uint m_startTime;
QString m_filePath;
QString m_fileName;
Ui::Downloader* m_ui;
QNetworkReply* m_reply;
bool m_useCustomProcedures;

View File

@ -362,8 +362,11 @@ void Updater::setUpdateAvailable (const bool available) {
if (!openUrl().isEmpty())
QDesktopServices::openUrl (QUrl (openUrl()));
else if (downloaderEnabled())
else if (downloaderEnabled()) {
m_downloader->setUrlId (url());
m_downloader->setFileName (downloadUrl().split ("/").last());
m_downloader->startDownload (QUrl (downloadUrl()));
}
else
QDesktopServices::openUrl (QUrl (downloadUrl()));