Save partial downloads on disk, not on RAM
This commit is contained in:
parent
62573c21bc
commit
1cbf20f156
@ -39,6 +39,9 @@
|
|||||||
|
|
||||||
#include "Downloader.h"
|
#include "Downloader.h"
|
||||||
|
|
||||||
|
static const QString PARTIAL_DOWN (".part");
|
||||||
|
static const QDir DOWNLOAD_DIR (QDir::homePath() + "/Downloads/");
|
||||||
|
|
||||||
Downloader::Downloader (QWidget* parent) : QWidget (parent) {
|
Downloader::Downloader (QWidget* parent) : QWidget (parent) {
|
||||||
m_ui = new Ui::Downloader;
|
m_ui = new Ui::Downloader;
|
||||||
m_ui->setupUi (this);
|
m_ui->setupUi (this);
|
||||||
@ -47,7 +50,8 @@ Downloader::Downloader (QWidget* parent) : QWidget (parent) {
|
|||||||
m_manager = new QNetworkAccessManager();
|
m_manager = new QNetworkAccessManager();
|
||||||
|
|
||||||
/* Initialize internal values */
|
/* Initialize internal values */
|
||||||
m_filePath = "";
|
m_url = "";
|
||||||
|
m_fileName = "";
|
||||||
m_startTime = 0;
|
m_startTime = 0;
|
||||||
m_useCustomProcedures = false;
|
m_useCustomProcedures = false;
|
||||||
|
|
||||||
@ -82,6 +86,17 @@ bool Downloader::useCustomInstallProcedures() const {
|
|||||||
return m_useCustomProcedures;
|
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
|
* 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_startTime = QDateTime::currentDateTime().toTime_t();
|
||||||
m_reply = m_manager->get (QNetworkRequest (url));
|
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 */
|
/* Update UI when download progress changes or download finishes */
|
||||||
connect (m_reply, SIGNAL (downloadProgress (qint64, qint64)),
|
connect (m_reply, SIGNAL (downloadProgress (qint64, qint64)),
|
||||||
this, SLOT (updateProgress (qint64, qint64)));
|
this, SLOT (updateProgress (qint64, qint64)));
|
||||||
connect (m_reply, SIGNAL (redirected (QUrl)),
|
connect (m_reply, SIGNAL (redirected (QUrl)),
|
||||||
this, SLOT (startDownload (QUrl)));
|
this, SLOT (startDownload (QUrl)));
|
||||||
connect (m_reply, SIGNAL (finished()),
|
|
||||||
this, SLOT (onDownloadFinished()));
|
|
||||||
|
|
||||||
showNormal();
|
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.
|
* Opens the downloaded file.
|
||||||
* \note If the downloaded file is not found, then the function will alert the
|
* \note If the downloaded file is not found, then the function will alert the
|
||||||
* user about the error.
|
* user about the error.
|
||||||
*/
|
*/
|
||||||
void Downloader::openDownload() {
|
void Downloader::openDownload() {
|
||||||
if (!m_filePath.isEmpty())
|
if (!m_fileName.isEmpty())
|
||||||
QDesktopServices::openUrl (QUrl::fromLocalFile (m_filePath));
|
QDesktopServices::openUrl (QUrl::fromLocalFile (DOWNLOAD_DIR.filePath (
|
||||||
|
m_fileName)));
|
||||||
|
|
||||||
else {
|
else {
|
||||||
QMessageBox::critical (this,
|
QMessageBox::critical (this,
|
||||||
@ -136,6 +168,13 @@ void Downloader::installUpdate() {
|
|||||||
if (useCustomInstallProcedures())
|
if (useCustomInstallProcedures())
|
||||||
return;
|
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;
|
QMessageBox box;
|
||||||
box.setIcon (QMessageBox::Question);
|
box.setIcon (QMessageBox::Question);
|
||||||
box.setDefaultButton (QMessageBox::Ok);
|
box.setDefaultButton (QMessageBox::Ok);
|
||||||
@ -146,11 +185,13 @@ void Downloader::installUpdate() {
|
|||||||
"quit the application.")
|
"quit the application.")
|
||||||
+ "</h3>");
|
+ "</h3>");
|
||||||
|
|
||||||
|
/* User wants to install the download */
|
||||||
if (box.exec() == QMessageBox::Ok) {
|
if (box.exec() == QMessageBox::Ok) {
|
||||||
if (!useCustomInstallProcedures())
|
if (!useCustomInstallProcedures())
|
||||||
openDownload();
|
openDownload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Wait */
|
||||||
else {
|
else {
|
||||||
m_ui->openButton->setEnabled (true);
|
m_ui->openButton->setEnabled (true);
|
||||||
m_ui->openButton->setVisible (true);
|
m_ui->openButton->setVisible (true);
|
||||||
@ -182,48 +223,40 @@ void Downloader::cancelDownload() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the downloaded data to a temp. directory and updates the UI controls.
|
* Writes the downloaded data to the disk
|
||||||
* \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.
|
|
||||||
*/
|
*/
|
||||||
void Downloader::onDownloadFinished() {
|
void Downloader::saveFile (qint64 received, qint64 total) {
|
||||||
m_ui->stopButton->setText (tr ("Close"));
|
/* Check if we need to redirect */
|
||||||
m_ui->downloadLabel->setText (tr ("Download complete!"));
|
QUrl url = m_reply->attribute (
|
||||||
m_ui->timeLabel->setText (tr ("The installer will open separately")
|
QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||||
+ "...");
|
if (!url.isEmpty()) {
|
||||||
|
startDownload (url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray data = m_reply->readAll();
|
/* Save downloaded data to disk */
|
||||||
|
QFile file (DOWNLOAD_DIR.filePath (m_fileName + PARTIAL_DOWN));
|
||||||
|
if (file.open (QIODevice::WriteOnly | QIODevice::Append)) {
|
||||||
|
file.write (m_reply->readAll());
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (!data.isEmpty()) {
|
/* Open downloaded update */
|
||||||
QString name = m_reply->url().toString().split ("/").last();
|
if (received >= total && total > 0) {
|
||||||
|
/* Rename file */
|
||||||
|
QFile::rename (DOWNLOAD_DIR.filePath (m_fileName + PARTIAL_DOWN),
|
||||||
|
DOWNLOAD_DIR.filePath (m_fileName));
|
||||||
|
|
||||||
/* Check if we need to redirect */
|
/* Notify application */
|
||||||
QUrl url = m_reply->attribute (
|
emit downloadFinished (m_url, DOWNLOAD_DIR.filePath (m_fileName));
|
||||||
QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
|
||||||
if (!url.isEmpty()) {
|
|
||||||
startDownload (url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save downloaded data to disk */
|
/* Install the update */
|
||||||
QFile file (QDir::tempPath() + "/" + name);
|
|
||||||
if (file.open (QIODevice::WriteOnly)) {
|
|
||||||
file.write (data);
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
m_filePath = file.fileName();
|
|
||||||
emit downloadFinished (m_reply->url().toString(), m_filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open downloaded update */
|
|
||||||
m_reply->close();
|
m_reply->close();
|
||||||
installUpdate();
|
installUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the appropiate size units (bytes, KB or MB) for the received
|
* 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
|
* 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);
|
calculateSizes (received, total);
|
||||||
calculateTimeRemaining (received, total);
|
calculateTimeRemaining (received, total);
|
||||||
|
saveFile (received, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
@ -56,14 +56,16 @@ class Downloader : public QWidget {
|
|||||||
bool useCustomInstallProcedures() const;
|
bool useCustomInstallProcedures() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void setUrlId (const QString& url);
|
||||||
void startDownload (const QUrl& url);
|
void startDownload (const QUrl& url);
|
||||||
|
void setFileName (const QString& file);
|
||||||
void setUseCustomInstallProcedures (const bool custom);
|
void setUseCustomInstallProcedures (const bool custom);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void openDownload();
|
void openDownload();
|
||||||
void installUpdate();
|
void installUpdate();
|
||||||
void cancelDownload();
|
void cancelDownload();
|
||||||
void onDownloadFinished();
|
void saveFile (qint64 received, qint64 total);
|
||||||
void calculateSizes (qint64 received, qint64 total);
|
void calculateSizes (qint64 received, qint64 total);
|
||||||
void updateProgress (qint64 received, qint64 total);
|
void updateProgress (qint64 received, qint64 total);
|
||||||
void calculateTimeRemaining (qint64 received, qint64 total);
|
void calculateTimeRemaining (qint64 received, qint64 total);
|
||||||
@ -72,8 +74,9 @@ class Downloader : public QWidget {
|
|||||||
qreal round (const qreal& input);
|
qreal round (const qreal& input);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QString m_url;
|
||||||
uint m_startTime;
|
uint m_startTime;
|
||||||
QString m_filePath;
|
QString m_fileName;
|
||||||
Ui::Downloader* m_ui;
|
Ui::Downloader* m_ui;
|
||||||
QNetworkReply* m_reply;
|
QNetworkReply* m_reply;
|
||||||
bool m_useCustomProcedures;
|
bool m_useCustomProcedures;
|
||||||
|
@ -362,8 +362,11 @@ void Updater::setUpdateAvailable (const bool available) {
|
|||||||
if (!openUrl().isEmpty())
|
if (!openUrl().isEmpty())
|
||||||
QDesktopServices::openUrl (QUrl (openUrl()));
|
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()));
|
m_downloader->startDownload (QUrl (downloadUrl()));
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
QDesktopServices::openUrl (QUrl (downloadUrl()));
|
QDesktopServices::openUrl (QUrl (downloadUrl()));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user