summaryrefslogblamecommitdiffstats
path: root/src/downloadmanager.cpp
blob: 22c1c0952e5b72ce20bd4ad226eab98cfe0240f3 (plain) (tree)
1
2
3
4
5
6
7
8
9
                            

                                    
                                                                                                          
                                    


                                                         
                                  
               
 
                                     
                
 
                                                                                                          
                                                































                                                                          
 


                                                  
 


                                                                                                          
                                                             

                                                  
 
                                                                                                          
                                                         
                                         
 


                                                                                                          
                                                               













                                                                               
 
                                                                                                          
                                           







                                                                              
 

                                   
 


                                                  
 



                                                     


                                                                         


                                                               
 





                                                                         
 














                                                                              
 


                                                                                                          
                                         






                                                                           
 
                                                                                                          
                                       

                                             
 
                                                                                                          
                                                                           




















                                                                               

                                                   



                                                                          
 
                                                                                                          
                                          








                                                              

                                                                               







                                                                               



                                                      









                                                            
 
#include "downloadmanager.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();
}