299 lines
8.8 KiB
C++
299 lines
8.8 KiB
C++
#include "DebugRoutines.h"
|
|
#include "JFileSystem.h"
|
|
#include "Downloader.h"
|
|
|
|
#define RECORDS_DEFAULT_FILE "cache/records.txt"
|
|
|
|
#ifdef QT_CONFIG
|
|
QNetworkAccessManager DownloadRequest::networkAccessManager;
|
|
#endif
|
|
|
|
DownloadRequest::DownloadRequest(string localPath,
|
|
string remoteResourceURL,
|
|
string ETag,
|
|
DownloadStatus downloadStatus,
|
|
size_t totalSize,
|
|
size_t currentSize):
|
|
mLocalPath(localPath),
|
|
mRemoteResourceURL(remoteResourceURL),
|
|
mRequestedRemoteResourceURL(remoteResourceURL),
|
|
mETag(ETag),
|
|
mDownloadStatus(downloadStatus),
|
|
mUpgradeAvailable(false),
|
|
mTotalSize(totalSize),
|
|
mCurrentSize(currentSize)
|
|
{
|
|
}
|
|
|
|
DownloadRequest::~DownloadRequest()
|
|
{
|
|
}
|
|
|
|
void DownloadRequest::startHead()
|
|
{
|
|
#ifdef QT_CONFIG
|
|
QNetworkRequest request(QUrl(QString(mRequestedRemoteResourceURL.c_str())));
|
|
request.setRawHeader("If-None-Match", mETag.c_str());
|
|
mNetworkReply = networkAccessManager.head(request);
|
|
connect(mNetworkReply, SIGNAL(finished()), SLOT(fileDownloaded()));
|
|
#endif
|
|
}
|
|
|
|
void DownloadRequest::startGet()
|
|
{
|
|
#ifdef QT_CONFIG
|
|
mNetworkReply = networkAccessManager.get(QNetworkRequest(QUrl(QString(mRequestedRemoteResourceURL.c_str()))));
|
|
#endif
|
|
mFile.close();
|
|
JFileSystem::GetInstance()->Remove(getTempLocalPath());
|
|
JFileSystem::GetInstance()->openForWrite(mFile, getTempLocalPath());
|
|
#ifdef QT_CONFIG
|
|
connect(mNetworkReply, SIGNAL(downloadProgress(qint64, qint64)),
|
|
SLOT(downloadProgress(qint64, qint64)));
|
|
connect(mNetworkReply, SIGNAL(finished()), SLOT(fileDownloaded()));
|
|
#endif
|
|
}
|
|
|
|
void DownloadRequest::fileDownloaded()
|
|
{
|
|
do {
|
|
QByteArray eTagByteArray = mNetworkReply->rawHeader("ETag");
|
|
if(!eTagByteArray.isEmpty()) {
|
|
string oldETag = mETag;
|
|
mETag = QString(eTagByteArray).toStdString();
|
|
if(oldETag!="" && oldETag != mETag)
|
|
mUpgradeAvailable = true;
|
|
}
|
|
|
|
// let's check some error
|
|
if(mNetworkReply->error() != QNetworkReply::NoError) {
|
|
DebugTrace(mNetworkReply->errorString().toStdString());
|
|
mDownloadStatus = DownloadRequest::DOWNLOAD_ERROR;
|
|
mFile.close();
|
|
JFileSystem::GetInstance()->Remove(getTempLocalPath());
|
|
break;
|
|
}
|
|
|
|
// check if we're getting redirected
|
|
QVariant redirectionTarget = mNetworkReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
|
if (!redirectionTarget.isNull()) {
|
|
QUrl newUrl = QUrl(mRequestedRemoteResourceURL.c_str()).resolved(redirectionTarget.toUrl());
|
|
DebugTrace(string("Redirect to ")+ newUrl.toString().toStdString());
|
|
|
|
mRequestedRemoteResourceURL = newUrl.toString().toStdString();
|
|
mNetworkReply->deleteLater();
|
|
if(mFile.is_open())
|
|
startGet();
|
|
else
|
|
startHead();
|
|
return;
|
|
}
|
|
|
|
if(mFile.is_open())
|
|
{
|
|
QByteArray byteArray = mNetworkReply->readAll();
|
|
mFile.write(byteArray.constData(), byteArray.size());
|
|
mFile.close();
|
|
if(!JFileSystem::GetInstance()->Rename(getTempLocalPath(), mLocalPath)) {
|
|
mDownloadStatus = DownloadRequest::DOWNLOAD_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
mDownloadStatus = DownloadRequest::DOWNLOADED;
|
|
} while(0);
|
|
|
|
Downloader::GetInstance()->Update();
|
|
mNetworkReply->deleteLater();
|
|
|
|
emit statusChanged((int)mDownloadStatus);
|
|
}
|
|
|
|
void DownloadRequest::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
|
|
{
|
|
QByteArray byteArray = mNetworkReply->readAll();
|
|
mFile.write(byteArray.constData(), byteArray.size());
|
|
mCurrentSize = bytesReceived;
|
|
mTotalSize = bytesTotal;
|
|
int percent = 0;
|
|
if(bytesTotal)
|
|
percent = (bytesReceived/bytesTotal)*100;
|
|
emit percentChanged(percent);
|
|
}
|
|
|
|
Downloader* Downloader::mInstance = 0;
|
|
|
|
Downloader::Downloader(string globalRemoteURL, string localcacheRecords):
|
|
mGlobalRemoteURL(globalRemoteURL),
|
|
mLocalCacheRecords(localcacheRecords)
|
|
{
|
|
JFileSystem::GetInstance()->MakeDir("cache");
|
|
|
|
izfstream downloadRecords;
|
|
if(mLocalCacheRecords.empty())
|
|
mLocalCacheRecords = RECORDS_DEFAULT_FILE;
|
|
if(JFileSystem::GetInstance()->openForRead(downloadRecords, mLocalCacheRecords))
|
|
{// File exists, let's read it.
|
|
downloadRecords >> (*this);
|
|
}
|
|
JFileSystem::GetInstance()->CloseFile();
|
|
}
|
|
|
|
Downloader::~Downloader()
|
|
{
|
|
map<string, DownloadRequest*>::iterator ite;
|
|
for(ite = mRequestMap.begin(); ite != mRequestMap.end(); ite++)
|
|
{
|
|
delete (*ite).second;
|
|
}
|
|
mRequestMap.erase(mRequestMap.begin(), mRequestMap.end());
|
|
}
|
|
|
|
Downloader* Downloader::GetInstance()
|
|
{
|
|
if(!mInstance)
|
|
{
|
|
mInstance = new Downloader();
|
|
}
|
|
return mInstance;
|
|
}
|
|
|
|
void Downloader::Release()
|
|
{
|
|
if(mInstance)
|
|
{
|
|
delete mInstance;
|
|
mInstance = 0;
|
|
}
|
|
}
|
|
|
|
bool DownloadRequest::NetworkIsAccessible()
|
|
{
|
|
bool result = false;
|
|
|
|
#ifdef QT_CONFIG
|
|
networkAccessManager.setNetworkAccessible(QNetworkAccessManager::Accessible);
|
|
result = networkAccessManager.networkAccessible();
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
DownloadRequest* Downloader::Get(string localPath, string remoteResourceURL)
|
|
{
|
|
map<string, DownloadRequest*>::iterator ite = mRequestMap.find(localPath);
|
|
if(ite == mRequestMap.end())
|
|
{ // request does not exist, let's create it
|
|
DownloadRequest* request = new DownloadRequest(localPath, remoteResourceURL);
|
|
std::pair<std::map<string,DownloadRequest*>::iterator,bool> ret;
|
|
ret = mRequestMap.insert ( std::pair<string,DownloadRequest*>(localPath, request) );
|
|
if (ret.second==false) {
|
|
DebugTrace("Downloader::Get Error inserting request in Map");
|
|
return 0;
|
|
}
|
|
ite = ret.first;
|
|
}
|
|
|
|
// Now, we can check the server
|
|
if((*ite).second->getDownloadStatus() == DownloadRequest::NOT_PRESENT ||
|
|
(*ite).second->upgradeAvailable())
|
|
{ // File is not here or an update is available, let's get it
|
|
(*ite).second->startGet();
|
|
(*ite).second->mDownloadStatus = DownloadRequest::DOWNLOADING;
|
|
}
|
|
else if ((*ite).second->getDownloadStatus() == DownloadRequest::DOWNLOADED)
|
|
{ // File is here, let's check if there is some update without blocking the playback
|
|
(*ite).second->startHead();
|
|
}
|
|
|
|
return (*ite).second;
|
|
}
|
|
|
|
void Downloader::Update()
|
|
{
|
|
ofstream downloadRecords;
|
|
if(JFileSystem::GetInstance()->openForWrite(downloadRecords, mLocalCacheRecords))
|
|
{
|
|
downloadRecords << (*this);
|
|
}
|
|
downloadRecords.close();
|
|
}
|
|
|
|
ostream& operator<<(ostream& out, const DownloadRequest& d)
|
|
{
|
|
// HEAD request fails, so this line erase cache record after upgrade check :(
|
|
// if(d.getDownloadStatus() == DownloadRequest::DOWNLOADED)
|
|
{
|
|
out << "localPath=" << d.mLocalPath << endl;
|
|
out << "remoteResource=" << d.mRemoteResourceURL << endl;
|
|
out << "ETag=" << d.mETag << endl;
|
|
out << "upgradeAvailable=" << d.mUpgradeAvailable <<endl;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
istream& operator>>(istream& in, DownloadRequest& d)
|
|
{
|
|
string s;
|
|
|
|
while(std::getline(in, s))
|
|
{
|
|
size_t limiter = s.find("=");
|
|
string areaS;
|
|
if (limiter != string::npos)
|
|
{
|
|
areaS = s.substr(0, limiter);
|
|
if (areaS.compare("localPath") == 0)
|
|
{
|
|
d.mLocalPath = s.substr(limiter + 1);
|
|
}
|
|
else if (areaS.compare("remoteResource") == 0)
|
|
{
|
|
d.mRemoteResourceURL = s.substr(limiter + 1);
|
|
d.mRequestedRemoteResourceURL = d.mRemoteResourceURL;
|
|
}
|
|
else if (areaS.compare("ETag") == 0)
|
|
{
|
|
d.mETag = s.substr(limiter + 1);
|
|
d.mDownloadStatus = DownloadRequest::DOWNLOADED;
|
|
}
|
|
else if (areaS.compare("upgradeAvailable") == 0)
|
|
{
|
|
d.mUpgradeAvailable = (bool)atoi(s.substr(limiter + 1).c_str());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return in;
|
|
}
|
|
|
|
ostream& operator<<(ostream& out, const Downloader& d)
|
|
{
|
|
map<string, DownloadRequest*>::const_iterator ite;
|
|
for(ite = d.mRequestMap.begin(); ite != d.mRequestMap.end(); ite++)
|
|
{
|
|
out << (*(*ite).second) << endl;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
istream& operator>>(istream& in, Downloader& d)
|
|
{
|
|
while(!in.eof())
|
|
{
|
|
DownloadRequest* downloadRequest = new DownloadRequest();
|
|
in >> (*downloadRequest);
|
|
|
|
if(!downloadRequest->getLocalPath().empty() &&
|
|
!downloadRequest->getRemoteResource().empty() &&
|
|
!downloadRequest->getETag().empty()) {
|
|
d.mRequestMap[downloadRequest->getLocalPath()] = downloadRequest;
|
|
} else {
|
|
delete downloadRequest;
|
|
}
|
|
}
|
|
return in;
|
|
}
|
|
|