summaryrefslogtreecommitdiffstats
path: root/src/fbgui/downloadmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/fbgui/downloadmanager.cpp')
-rw-r--r--src/fbgui/downloadmanager.cpp215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/fbgui/downloadmanager.cpp b/src/fbgui/downloadmanager.cpp
new file mode 100644
index 0000000..653bc7b
--- /dev/null
+++ b/src/fbgui/downloadmanager.cpp
@@ -0,0 +1,215 @@
+#include "downloadmanager.h"
+
+// static counter to save the number of successfully downloaded files.
+int DownloadManager::_downloaded = 0;
+// -------------------------------------------------------------------------------------------------------
+// Initialisation
+// -------------------------------------------------------------------------------------------------------
+// Constructor initialises a QNetworkAccessManager needed to create/received download requests/replies
+// This object is then moved to the thread for the download manager, to ensure that downloads
+// are done in a separate thread (to avoid GUI blocking.)
+// The flag "_dip" starts as false, since no download is in progress.
+// This flag is needed to control queueing functionality.
+// Lastly the given download directory's existance is checked. (see below)
+
+DownloadManager::DownloadManager() {
+ qxtLog->debug() << "Initializing download manager...";
+ checkDownloadDirectory();
+ _qnam = new QNetworkAccessManager();
+ _qnam->moveToThread(&dmThread);
+ _dip = false;
+}
+// Destructor
+DownloadManager::~DownloadManager() {
+ delete _qnam;
+}
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::checkDownloadDirectory() {
+ // check if downloadPath exists, if not create it.
+ _downloadDir = QDir(downloadPath);
+ if (!_downloadDir.exists()) {
+ qxtLog->debug() << "[dm] Download directory: " << _downloadDir.path() << " doesn't exist.";
+ // try to create the directory
+ if (QDir::current().mkdir(downloadPath))
+ qxtLog->debug() << "[dm] Created download directory: " << _downloadDir.path();
+ else {
+ qxtLog->debug() << "[dm] Failed to create directory: " << _downloadDir.path();
+ // try to save to /tmp/fbgui
+ _downloadDir.setPath(QDir::tempPath() + "/fbgui");
+ if (!_downloadDir.exists()) {
+ if (QDir::current().mkdir(QDir::tempPath() + "/fbgui"))
+ qxtLog->debug() << "[dm] Successfully created: " << _downloadDir.absolutePath();
+ else {
+ // just in case
+ qxtLog->debug() << "[dm] Failed to create: " << _downloadDir.absolutePath();
+ qxtLog->debug() << "[dm] Exiting...";
+ exit( EXIT_FAILURE);
+ }
+ } else
+ qxtLog->debug() << "[dm] " << _downloadDir.absolutePath() << " already exists.";
+ }
+ } else
+ qxtLog->debug() << "[dm] Download directory: " << _downloadDir.absolutePath()
+ << " already exists.";
+
+ qxtLog->debug() << "[dm] Saving downloads to: " << _downloadDir.absolutePath();
+ downloadPath = _downloadDir.absolutePath();
+}
+// -------------------------------------------------------------------------------------------------------
+// Public access
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::downloadFile(const QString& filename) {
+ QUrl fileUrl(baseURL.resolved(QUrl(filename)));
+ this->processDownloadRequest(fileUrl);
+}
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::downloadFile(const QUrl& fileUrl) {
+ this->processDownloadRequest(fileUrl);
+}
+// -------------------------------------------------------------------------------------------------------
+// Private functions handling download requests and queueing
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::processDownloadRequest(const QUrl& url) {
+ if (url.isEmpty()) {
+ qxtLog->debug() << "[dm] No URL specified for download.";
+ return;
+ }
+ qxtLog->debug() << "[dm] Enqueueing: " << url.toString();
+ _downloadQueue.enqueue(url);
+ if (_dip) {
+ // download in progress, return.
+ qxtLog->debug() << "[dm] Download in progress! Queued:" << url.toString() << "("
+ << _downloadQueue.size() << " in queue)";
+ return;
+ }
+ // no running downloads: start next in queue
+ startNextDownload();
+}
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::startNextDownload() {
+ //QWSServer::instance()->setCursorVisible(false);
+ if (_downloadQueue.isEmpty()) {
+ emit downloadQueueEmpty();
+ qxtLog->debug() << "[dm] Download manager ready. (1)";
+ return;
+ }
+ qxtLog->debug() << "[dm] Starting next download: " << _downloadQueue.head().toString() << " ("
+ << _downloadQueue.size() - 1 << " in queue.)";
+
+ // dequeue next URL to download.
+ QUrl url = _downloadQueue.dequeue();
+
+ // get filename from URL.
+ QString tmp = url.path();
+ tmp.remove(0, tmp.lastIndexOf(QChar('/')) + 1);
+
+ // check if filename exists on target file system
+ if (_downloadDir.exists(tmp)) {
+ qxtLog->debug() << "[dm] File already exists: " << _downloadDir.absoluteFilePath(tmp);
+ _outfile.setFileName(
+ QString(_downloadDir.absolutePath() + "/" + tmp + ".\%1").arg(_downloaded));
+ } else
+ _outfile.setFileName(_downloadDir.absoluteFilePath(tmp));
+ qxtLog->debug() << "[dm] Saving to: " << _outfile.fileName();
+
+ // try to open for writing
+ if (!_outfile.open(QIODevice::WriteOnly)) {
+ qxtLog->debug() << "[dm] No write access to " << _outfile.fileName()
+ << " . Skipping download...";
+ return;
+ }
+
+ // send the request for the file
+ QNetworkRequest request(url);
+ _currentDownload = _qnam->get(request);
+ _lastProgress = 0;
+ _currentProgress = 0;
+ _dip = true;
+ time.start();
+ QObject::connect(_currentDownload, SIGNAL(readyRead()), this, SLOT(
+ downloadReady()));
+ QObject::connect(_currentDownload, SIGNAL(metaDataChanged()), this, SLOT(
+ processMetaInfo()));
+ QObject::connect(_currentDownload, SIGNAL(downloadProgress(qint64, qint64)), this,
+ SLOT(downloadProgress(qint64, qint64)));
+ QObject::connect(_currentDownload, SIGNAL(finished()), this, SLOT(
+ downloadFinished()));
+}
+// -------------------------------------------------------------------------------------------------------
+// Private slots to handle a download in progress
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::processMetaInfo() {
+ // fetch filesize from header & filename from URL (for now)
+ const QByteArray cltag = "Content-Length";
+ QByteArray clinfo = _currentDownload->rawHeader(cltag);
+ QFileInfo fi(_outfile);
+ qxtLog->debug() << "[dm] Download Info: " << fi.fileName() << " (Size: " << clinfo.toDouble()
+ << ")";
+ emit downloadInfo(fi.fileName(), clinfo.toDouble());
+}
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::downloadReady() {
+ // data ready, save it
+ _outfile.write(_currentDownload->readAll());
+}
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::downloadProgress(qint64 bytesIn, qint64 bytesTotal) {
+ if (bytesIn > bytesTotal || bytesTotal <= 0) {
+ qxtLog->debug() << "[dm] downloadProgress invalid values:" << "In:" << bytesIn
+ << " / Total: " << bytesTotal;
+ return;
+ }
+ // calculate current speed
+ double speed = bytesIn * 1000 / time.elapsed();
+ QString unit;
+ if (speed < 1024) {
+ unit = "bytes/sec";
+ } else if (speed < 1024 * 1024) {
+ speed /= 1024;
+ unit = "KB/s";
+ } else {
+ speed /= 1024 * 1024;
+ unit = "MB/s";
+ }
+ // update progress only if difference higher than the updateInterval setting
+ _currentProgress = ((bytesIn * 100) / bytesTotal);
+ if (_currentProgress - _lastProgress >= updateInterval) {
+ _lastProgress = _currentProgress;
+ emit
+ updateProgress(_currentProgress, speed, unit);
+ qxtLog->debug() << "[dm] Download progress of " << _currentDownload->url().toString() << ": "
+ << bytesIn << "/" << bytesTotal << "(" << _currentProgress << "\%)";
+ }
+}
+// -------------------------------------------------------------------------------------------------------
+void DownloadManager::downloadFinished() {
+ // check for errors
+ if (_currentDownload->error()) {
+ _outfile.close();
+ _outfile.remove();
+ int statusCode =
+ _currentDownload->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ qxtLog->debug() << "[dm] Download of " << _currentDownload->url().toString()
+ << " failed with HTTP error code: " << statusCode;
+ emit
+ notify(QString("Download failed! HTTP Status Code: %1").arg(statusCode));
+ _currentDownload->deleteLater();
+ } else {
+ // end download
+ _outfile.close();
+ _downloaded++;
+ qxtLog->debug() << "[dm] Download of " << _currentDownload->url().toString()
+ << " finished. (downloaded = " << _downloaded << ")";
+ emit
+ notify(QString("Successfully downloaded %1").arg(_currentDownload->url().toString()));
+ _currentDownload->deleteLater();
+ }
+ _dip = false;
+ // process next in queue, if any
+ if (_downloadQueue.isEmpty()) {
+ emit downloadQueueEmpty();
+ qxtLog->debug() << "[dm] Download manager ready. (2)";
+ return;
+ }
+ startNextDownload();
+}