diff options
Diffstat (limited to 'src/fbgui/downloadmanager.cpp')
-rw-r--r-- | src/fbgui/downloadmanager.cpp | 215 |
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(); +} |