|
|
#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!";
}
*/
|