#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() << "Download directory: " << downloadDir.path() << " doesn't exist."; QDir::current().mkdir(downloadPath); if (downloadDir.exists()){ qxtLog->debug() << "Created download directory: " << downloadDir.path(); } else { qxtLog->debug() << "Failed to create directory: " << downloadDir.path(); // try to save to /tmp/fbgui downloadDir.setPath(QDir::tempPath () + "/fbgui"); if (!downloadDir.exists()){ QDir::current().mkdir(QDir::tempPath () + "/fbgui"); if (!downloadDir.exists()){ // TODO: dont exit, this shouldn't happen anyway (right?) qxtLog->debug() << "Fatal, no target for downloads. Exiting..."; exit(EXIT_FAILURE); } } qxtLog->debug() << "Saving downloads to: " << downloadDir.absolutePath(); } } else qxtLog->debug() << "Download directory: " << downloadDir.path() << " exists."; } // ---------------------------------------------------------------------------------------- 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() << "No URL specified for download."; return; } // if download in progress, enqueue file and return. if (dip){ dlQ.enqueue(url); qxtLog->debug() << "Download in progress! Queued:" << url.toString() << "(" << dlQ.size() << " in queue)"; return; } // no running downloads: enqueue and start next download. dlQ.enqueue(url); qxtLog->debug() << "Enqueueing:" << url.toString(); startNextDownload(); } // ---------------------------------------------------------------------------------------- void DownloadManager::startNextDownload() { if (dlQ.isEmpty()){ emit downloadQueueEmpty(); qxtLog->debug() << "Download manager ready. (1)"; return; } qxtLog->debug() << "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() << "File already exists: " << downloadDir.absoluteFilePath(tmp); outfile.setFileName(QString(downloadDir.absolutePath() + "/" + tmp + ".\%1").arg(downloaded)); } else outfile.setFileName(downloadDir.absoluteFilePath(tmp)); qxtLog->debug() << "Saving to: " << outfile.fileName(); // try to open for writing if (!outfile.open(QIODevice::WriteOnly)){ qxtLog->debug() << "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() << "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() << "Download of " << currentDownload->url().toString() << " failed with HTTP error code: " << statusCode; emit notify(QString("Download failed! HTTP Status Code: %1").arg(statusCode)); } else{ completeKCL(); // end download currentDownload->deleteLater(); outfile.close(); downloaded++; qxtLog->debug() << "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() << "Download manager ready. (2)"; return; } startNextDownload(); } // ---------------------------------------------------------------------------------------- void DownloadManager::completeKCL(){ // check if current download is kcl if (outfile.fileName() == downloadDir.absoluteFilePath("kcl")){ qxtLog->debug() << "Completing kernel command line ..."; outfile.write(" session=" + sessionID.toUtf8()); } } /******************************************************************************************************** * ** 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!"; } */