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



                                    
                                                                                                          


                                                              

                                            

                    


                                    
                                                                                                          




                                                          
                                                                                                          

                                                        
                                                                                                     
                      
                                                                                                     


                                                                          
                                                                                        
                                                                                                                       

                                                       

                                                                                                                   


                                                           
                            
                                                                                                               

                 
            
                                                                                                                   
 
                                                                                      
                                                    
 


                                                                                                          




                                                           
                                                                                                          



                                                       


                                                                                                          


                                                             
                                                                         

                       
                                                                 
                         
                 
                                            
                                                                                         


                                                                                     
                                                    

                            
                                                                                                          

                                         
                                                   

                                          
                                                                      

                       
                                                                                   










                                                                                    
                                                                                                     



                                                                                                              
                                                                    


                                                 
                                                                                                                 




                                        
                                              


                            
                      





                                                                                                    


                                                                                                          





                                                                   

                                                                                                             
 
                                                                                                          




                                                  
                                                                                                          

                                                                         




                                                                              
                                  
                                                        
                     
                          
                                   

                                    

                      

             

                           
         




                                                                                    
                                                                                                    

                                                                                                            
 
                                                                                                          



                                        
                                

                                                                                                              
                                                                                           

                                                                                                  
                                       


                               

                                
                                                                                           

                                                                                                          
                                               

                    
                                        

                                          
                                                                      



                            
#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();
}