#include "downloadmanager.h" #include "fbgui.h" int DownloadManager::downloaded = 0; // ------------------------------------------------------------------------------------------------------- DownloadManager::DownloadManager() { qxtLog->debug() << "Initializing download manager..."; checkDownloadDirectory(); _qnam = new QNetworkAccessManager(); _qnam->moveToThread(&dmThread); dip = false; } 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(); dlQ.enqueue(url); if (dip) { // download in progress, return. qxtLog->debug() << "[dm] Download in progress! Queued:" << url.toString() << "(" << dlQ.size() << " in queue)"; return; } // no running downloads: start next in queue startNextDownload(); } // ------------------------------------------------------------------------------------------------------- void DownloadManager::startNextDownload() { QWSServer::instance()->setCursorVisible(false); if (dlQ.isEmpty()) { emit downloadQueueEmpty(); qxtLog->debug() << "[dm] Download manager ready. (1)"; return; } qxtLog->debug() << "[dm] Starting next download: " << dlQ.head().toString() << " (" << dlQ.size() - 1 << " in queue.)"; // dequeue next URL to download. QUrl url = dlQ.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 (dlQ.isEmpty()) { emit downloadQueueEmpty(); qxtLog->debug() << "[dm] Download manager ready. (2)"; return; } startNextDownload(); }