#include "downloadmanager.h" #include "fbgui.h" int DownloadManager::downloaded = 0; // ---------------------------------------------------------------------------------------- DownloadManager::DownloadManager(){ qxtLog->debug() << "Initializing download manager..."; checkDownloadDirectory(); qnam = new QNetworkAccessManager(); dip = false; } // ---------------------------------------------------------------------------------------- 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(); } // ---------------------------------------------------------------------------------------- void DownloadManager::downloadFile(const QString& filename) { QUrl fileUrl(baseURL.resolved(QUrl(filename))); this->processDownloadRequest(fileUrl); } // ---------------------------------------------------------------------------------------- void DownloadManager::downloadFile(const QUrl& fileUrl) { this->processDownloadRequest(fileUrl); } // ---------------------------------------------------------------------------------------- void DownloadManager::processDownloadRequest(const QUrl& url) { if (url.isEmpty()){ qxtLog->debug() << "[dm] No URL specified for download."; return; } // if download in progress, enqueue file and return. if (dip){ dlQ.enqueue(url); qxtLog->debug() << "[dm] Download in progress! Queued:" << url.toString() << "(" << dlQ.size() << " in queue)"; return; } // no running downloads: enqueue and start next download. dlQ.enqueue(url); qxtLog->debug() << "[dm] Enqueueing:" << url.toString(); startNextDownload(); } // ---------------------------------------------------------------------------------------- void DownloadManager::startNextDownload() { 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; dltime.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 process downloads // ---------------------------------------------------------------------------------------- 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); emit downloadInfo(outfile.fileName(), clinfo.toDouble()); } // ---------------------------------------------------------------------------------------- void DownloadManager::downloadReady() { // data ready, save it outfile.write(currentDownload->readAll()); } // ---------------------------------------------------------------------------------------- void DownloadManager::downloadProgress(qint64 bytesIn, qint64 bytesTotal) { if (bytesIn > bytesTotal) return; // calculate current speed double speed = bytesIn * 1000 / dltime.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 << "\%)"; } return; } // ---------------------------------------------------------------------------------------- void DownloadManager::downloadFinished() { // check for errors if (currentDownload->error()){ currentDownload->deleteLater(); 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)); } else{ // if kcl, append the session ID to it if (outfile.fileName() == downloadDir.absoluteFilePath("kcl")){ qxtLog->debug() << "[dm] Completing kernel command line..."; outfile.write(" session=" + sessionID.toUtf8()); } // end download currentDownload->deleteLater(); outfile.close(); downloaded++; qxtLog->debug() << "[dm] Download of " << currentDownload->url().toString() << " finished. (downloaded = "<< downloaded << ")"; emit notify(QString("Successfully downloaded %1").arg(currentDownload->url().toString())); } dip = false; // process next in queue if (dlQ.isEmpty()){ emit downloadQueueEmpty(); qxtLog->debug() << "[dm] Download manager ready. (2)"; return; } startNextDownload(); } /******************************************************************************************************** * ** dead code: Header filename fetching & renaming ** const QByteArray cd = "Content-Disposition"; QByteArray cdc = currentDownload->rawHeader(cd); int x = cdc.indexOf("filename=\"") + 10; cdc.remove(0, x).chop(1); if (!cdc.isEmpty()) currentTargetFilename = cdc; else currentTargetFilename = QString("download.\%1").arg(downloaded); QString tmp = outfile.fileName(); tmp.remove(0, tmp.lastIndexOf(QChar('/')) + 1); qDebug() << "Trying to rename " << tmp << " to --> " << currentTargetFilename; if (outfile.rename(downloadPath + "/" + currentTargetFilename)) { qxtLog->debug() << "Renamed file!"; } else { qxtLog->debug() << "Failure to rename file!"; } */