JD2022-TU1/main/extern/Camcam/TestApp/download_task.cpp

717 lines
23 KiB
C++

#include "Scene.h"
#ifdef ONLINE_MODE
//#pragma optimize("",off)
#include "download_task.h"
#include "sha1.h"
#include "account.h"
extern CCamCamAccount Account;
extern WORLD *TheScene;
extern char CurrentDir[];
std::string DownloadThumbnailAction::_CDNBaseURL;
// ***************************************************************************
void DownloadAction::onEnqueue()
{
if (_RelatedCard)
_RelatedCard->IsDownloadPending = true;
}
// ***************************************************************************
void DownloadAction::onDownloaded(CDownloadQueueTask *task, lua_State * L)
{
if (_RelatedCard)
{
_RelatedCard->IsDownloadPending = false;
}
}
// ***************************************************************************
// Called by background task
void DownloadThumbnailAction::bgDownload(CDownloadQueueTask *task)
{
//logStr(__FUNCTION__"-begin %u", _RelatedCard->Id);
if (!_RelatedCard)
return;
if (_CDNBaseURL.empty())
{
// Ask the server if we have to fetch the thumbnail directly from the CDN
// TODO: move this to the log-in page
if (task->doRequest("dlfile", "t=tbnU&id=0", USE_MORE_INFO, __FUNCTION__, "Could not get CDN base URL"))
{
const HttpPage& buffer = task->getHttpClient().getResponsePage();
const char *bufPos = buffer.c_str() + 2; // skip "0|"
_CDNBaseURL = getNextResultField(&bufPos);
}
else
_CDNBaseURL = '-';
}
if (_CDNBaseURL[0] != '-')
{
// Direct CDN request
extern const char *ThumbnailPath;
Card *card = static_cast<Card*>(_RelatedCard);
std::string tbUrl = _CDNBaseURL + card->Thumbnail;
std::string::size_type bp = tbUrl.find(" ");
while (bp != std::string::npos)
{
tbUrl.replace(bp, 1, "%20", 3); // some blank chars might be part of the filename
bp = tbUrl.find(" ");
}
// Theme card ? check if lang file exists
if(card->getType() == Card::Theme)
{
tbUrl.insert(tbUrl.rfind('.'), std::string("_") + Account._LanguageCode.c_str());
}
std::string tbPath = std::string(CurrentDir) + std::string(ThumbnailPath) + card->Thumbnail;
_Status = task->downloadFileFromURL(tbUrl.c_str(), tbPath);
// CHeck download status
if(card->getType() == Card::Theme && !_Status)
{
tbUrl.erase(tbUrl.rfind('_') , 3); // set tbUrl with no lang
_Status = task->downloadFileFromURL(tbUrl.c_str(), tbPath);
}
if (card->getType() == CardElement::Asset || card->getType() == Card::Theme) //TEMP: theme and roles have no alpha thumb
{
std::string tbaUrl = tbUrl, tbaPath = tbPath;
std::string::size_type p = tbaUrl.rfind("."), q = tbaPath.rfind(".");
if ((p != std::string::npos) && (q != std::string::npos))
{
tbaUrl.insert(p, "_alpha").c_str();
tbaPath.insert(q, "_alpha").c_str();
task->downloadFileFromURL(tbaUrl.c_str(), tbaPath, true);
}
}
}
else
{
// Regular dlfile request (might redirect to the CDN, though)
_Status = task->downloadFile(_RelatedCard->Id, (std::string("tbn")+std::string(1, '0'+_RelatedCard->getType())).c_str(), _ActualPath);
std::string actualAlphaPath;
task->downloadFile(_RelatedCard->Id, (std::string("tba")+std::string(1, '0'+_RelatedCard->getType())).c_str(), actualAlphaPath);
}
// Delete previous files
std::string fileName = _ActualPath.substr(_ActualPath.rfind('/') + 1);
// Filename = tb%IDCard%_%Version%.jpg
// New name with version
if (fileName.find("tb") != std::string::npos)
{
std::string pathFile = _ActualPath.substr(0, _ActualPath.rfind('_'));
std::string extFile = _ActualPath.substr(_ActualPath.rfind('.') + 1);
char tmpFilename [1024];
unsigned int previousVersion = atoi (
fileName.substr(fileName.rfind('_') + 1,
fileName.rfind('.') - fileName.rfind('_') - 1).c_str() ) - 1;
for (; previousVersion >= 1; -- previousVersion)
{
// Delete previous version if needed ..
_snprintf(tmpFilename, 1023, "%s_%d.%s", pathFile.c_str(), previousVersion, extFile.c_str());
DeleteFile(tmpFilename);
// Delete alpha file
_snprintf(tmpFilename, 1023, "%s_%d_alpha.%s", pathFile.c_str(), previousVersion, extFile.c_str());
DeleteFile(tmpFilename);
}
}
//logStr(__FUNCTION__"-end %u", _RelatedCard->Id);
}
// ***************************************************************************
// Warning: this is *not* called by the background task
void DownloadThumbnailAction::onDownloaded(CDownloadQueueTask *task, lua_State * L)
{
//logStr(__FUNCTION__"-begin %s ", _ActualPath.c_str());
DownloadAction::onDownloaded(task, L);
if ((_IdMedia != ~0) && TheScene->ID_MEDIA[_IdMedia])
{
// Draw (note: CreateMedia automatically combines normal and alpha files) (TEMP: path)
u32 idTbMedia = TheScene->CreateMedia(const_cast<char*>(_ActualPath.c_str()), 0);
if (idTbMedia != ~0)
{
// Software copy (full pic)
/*
void COPY_RESAMPLE(MAP *MapSRC,MAP *MapDST);
COPY_RESAMPLE(&TheScene->ID_MEDIA[idTbMedia]->Image, &TheScene->ID_MEDIA[_IdMedia]->Image);
TheScene->DI->UpdateTexture_BM_2_HW(TheScene->ID_MEDIA[_IdMedia]->ulAssociatedTextureIndex);
//*/
// The OpenGL way produces a fast and good-looking pic, but it is truncated as soon as the
// the main window is moved partially off-screen
//*
int oldVpX = TheScene->DI->CurrentViewport[0];
int oldVpY = TheScene->DI->CurrentViewport[1];
int oldVpW = TheScene->DI->CurrentViewport[2];
int oldVpH = TheScene->DI->CurrentViewport[3];
int vpX = 0; lua_getglobal(L, "RetourViewportX");
vpX = (int)lua_tonumber(L, -1); lua_pop(L,1);
int vpY = 0; lua_getglobal(L, "RetourViewportY");
vpY = (int)lua_tonumber(L, -1); lua_pop(L,1);
int vpW = 0; lua_getglobal(L, "RetourViewportW");
vpW = (int)lua_tonumber(L, -1); lua_pop(L,1);
int vpH = 0; lua_getglobal(L, "RetourViewportH");
vpH = (int)lua_tonumber(L, -1); lua_pop(L,1);
TheScene->DI->SetViewport(vpX,vpY,vpW,vpH);
TheScene->DI->BeginTextureTarget(TheScene->ID_MEDIA[_IdMedia]->ulAssociatedTextureIndex);
TheScene->DI->Clear(ARGB2ABGR(0));
TheScene->DI->SetBackGround(TheScene->ID_MEDIA[idTbMedia]->ulAssociatedTextureIndex, 0); // TODO: scale
TheScene->DI->EndTextureTarget(TheScene->ID_MEDIA[_IdMedia]->ulAssociatedTextureIndex, 0);
TheScene->DI->SetViewport(oldVpX,oldVpY,oldVpW,oldVpH);
//*/
TheScene->DestroyMedia(idTbMedia);
}
else
{
// Software copy (full pic)
/*
memset(TheScene->ID_MEDIA[_IdMedia]->Image.BASE, 0, TheScene->ID_MEDIA[_IdMedia]->Image.PITCH*TheScene->ID_MEDIA[_IdMedia]->Image.SY*4);
TheScene->DI->UpdateTexture_BM_2_HW(TheScene->ID_MEDIA[_IdMedia]->ulAssociatedTextureIndex);
*/
// The OpenGL way
//*
int oldVpX = TheScene->DI->CurrentViewport[0];
int oldVpY = TheScene->DI->CurrentViewport[1];
int oldVpW = TheScene->DI->CurrentViewport[2];
int oldVpH = TheScene->DI->CurrentViewport[3];
int vpX = 0; lua_getglobal(L, "RetourViewportX");
vpX = (int)lua_tonumber(L, -1); lua_pop(L,1);
int vpY = 0; lua_getglobal(L, "RetourViewportY");
vpY = (int)lua_tonumber(L, -1); lua_pop(L,1);
int vpW = 0; lua_getglobal(L, "RetourViewportW");
vpW = (int)lua_tonumber(L, -1); lua_pop(L,1);
int vpH = 0; lua_getglobal(L, "RetourViewportH");
vpH = (int)lua_tonumber(L, -1); lua_pop(L,1);
TheScene->DI->SetViewport(vpX,vpY,vpW,vpH);
TheScene->DI->BeginTextureTarget(TheScene->ID_MEDIA[_IdMedia]->ulAssociatedTextureIndex);
TheScene->DI->Clear(ARGB2ABGR(0)); // show a special media instead?
TheScene->DI->EndTextureTarget(TheScene->ID_MEDIA[_IdMedia]->ulAssociatedTextureIndex, 0);
TheScene->DI->SetViewport(oldVpX,oldVpY,oldVpW,oldVpH);
//*/
}
}
if (task) // if no background downloading was needed, don't call lua
{
// Call lua callback
lua_getglobal(L, "OnThumbnailDownloaded");
lua_pushnumber(L, _RelatedCard->getType());
lua_pushnumber(L, _RelatedCard->Id);
lua_pushboolean(L, _Status);
#ifndef USER_MODE
extern int mainThread;
if (mainThread != GetCurrentThreadId()) MessageBox(NULL, "Bad Threard Access 2!", "YouUp", MB_OK | MB_ICONERROR);
#endif
if (lua_pcall(L,3,0,0) != 0)
{
char *luaRes = (char *)lua_tostring(L, -1);
logStr(__FUNCTION__"-err: Could not call OnThumbnailDownloaded: %s", luaRes ? luaRes : "unknown error");
}
}
//logStr(__FUNCTION__"-end %s ", _ActualPath.c_str());
}
// ***************************************************************************
// Called by background task
void DownloadZccAction::bgDownload(CDownloadQueueTask *task)
{
ZccCard *zccCard = static_cast<ZccCard*>(_RelatedCard);
if (zccCard->Hash.empty())
{
logStr(__FUNCTION__"-info: not enough information about zcc #%u", zccCard->Id);
return;
}
// Check if the ZCC is already present, and check its integrity, then download it if not
std::string zccFilename = zccCard->getFilename();
if (!ensureValidZccPresent(task, zccCard))
{
logStr(__FUNCTION__"-error: could not download %s matching hash", zccFilename.c_str());
return;
}
// Unpack ZCC
if (!TheScene->UNPACK(&zccFilename[0], 0, 1, false, &task->getHttpClient().isAbortingRef()))
{
logStr(__FUNCTION__"-error: could not unpack %s", zccFilename.c_str());
return;
} else
{
int nbFiles = 0;
char **files = TheScene->GETZCCFILES(&zccFilename[0], &nbFiles);
zccCard->fillClearZCC(files, nbFiles);
}
//logStr(__FUNCTION__"-info: unpacked %s", zccFilename.c_str());
_Status = true;
}
// ***************************************************************************
// Warning: this is *not* called by the background task
void DownloadZccAction::onDownloaded(CDownloadQueueTask *task, lua_State * L)
{
//logStr(__FUNCTION__"-begin %u", _RelatedCard->Id);
DownloadAction::onDownloaded(task, L);
if (task) // if no background downloading was needed, don't call lua
{
// Call lua callback
ZccCard *zccCard = static_cast<ZccCard*>(_RelatedCard);
int zccCardIdx = 1;
lua_getglobal(L, "OnAssetDownloaded");
lua_pushnumber(L, _RelatedCard->Id);
lua_pushboolean(L, _Status);
lua_newtable(L);
for (std::vector<std::string>::iterator it=zccCard->ZCCFiles.begin(); it!=zccCard->ZCCFiles.end(); ++it, zccCardIdx++)
{
std::string fileName = *it;
lua_pushinteger(L, zccCardIdx);
lua_pushstring(L, &fileName[0]);
lua_settable(L, -3);
}
#ifndef USER_MODE
extern int mainThread;
if (mainThread != GetCurrentThreadId()) MessageBox(NULL, "Bad Threard Access 3!", "YouUp", MB_OK | MB_ICONERROR);
#endif
if (lua_pcall(L,3,0,0) != 0)
{
char *luaRes = (char *)lua_tostring(L, -1);
logStr(__FUNCTION__"-err: Could not call OnAssetDownloaded: %s", luaRes ? luaRes : "unknown error");
}
}
//logStr(__FUNCTION__"-end %u", _RelatedCard->Id);
}
// ***************************************************************************
bool DownloadZccAction::checkFileIntegrity(const char *zccFilename, const char *serverHashCode)
{
CSHA1 sha1;
SimpleString<41> clientHashCode;
if (sha1.HashFile(zccFilename))
{
sha1.Final();
sha1.ReportHash(clientHashCode.Buf, CSHA1::REPORT_HEX_NOBLANKS);
}
return (strcmp(serverHashCode, clientHashCode.c_str()) == 0);
}
// ***************************************************************************
bool DownloadZccAction::ensureValidZccPresent(CDownloadQueueTask *task, ZccCard *zccCard)
{
for (int i=0; i!=5; ++i) // try several attempts, in case the download is fucked up
{
if (checkFileIntegrity(zccCard->getFilename().c_str(), zccCard->Hash.c_str()))
return true;
// The ZCC is not present or not valid, then download it from the server
std::string actualPath;
if(task->downloadFile(zccCard->Id, "zcc", actualPath))
{
// Delete previous versions
if(zccCard->ZccVersion > 0)
{
for (int version = zccCard->ZccVersion - 1; version >= 0; -- version)
{
DeleteFile(zccCard->getFilename(version).c_str());
}
}
}
else if (task->getHttpClient().isAborting())
return false; // do not retry if aborting
if (i != 0)
Sleep(500);
}
//_ErrorString.sprintf("Could not download a valid %s", zccFilename);
//logStr(__FUNCTION__"-error: %s", _ErrorString.c_str());
return false;
}
// ***************************************************************************
void RefreshCardStatusAction::bgDownload(CDownloadQueueTask *task)
{
// Get server status
if (!task->doRequest("refresh", "", COULD_NOT_REFRESH_STATUS, __FUNCTION__))
return;
// Get the whole card structure if needed
_Buffer.clear();
const HttpPage& buffer = task->getHttpClient().getResponsePage();
const char *bufPos = buffer.c_str() + 2; // skip "0|"
bool hasNewCards = (getNextResultField(&bufPos) == "1");
if (hasNewCards)
{
requestAssets(*task);
_Buffer = task->getHttpClient().getResponsePage();
}
}
// ***************************************************************************
bool RefreshCardStatusAction::requestAssets(CamCamHttpClient& ccHttpClient)
{
SimpleString<32> args;
args.sprintf("");
return ccHttpClient.doRequest("get-assets", args.c_str(), COULD_NOT_GET_ASSET_LIST, __FUNCTION__);
}
// ***************************************************************************
// Called from the main thread
void RefreshCardStatusAction::onDownloaded(CDownloadQueueTask *task, lua_State * L)
{
if (!_Buffer.empty())
{
Account.updateCards(&_Buffer);
}
}
// ***************************************************************************
bool CDownloadQueueTask::init(const SimpleString<16> *pIdAccount)
{
CBackgroundTask::init();
MUTEX_SETUP(_MutexToDownload);
MUTEX_SETUP(_MutexDownloaded);
return CamCamHttpClient::init(pIdAccount);
}
// ***************************************************************************
void CDownloadQueueTask::enqueue(DownloadAction *action, bool topPriority)
{
action->onEnqueue();
MUTEX_LOCK(_MutexToDownload);
if (topPriority)
_FifoToDownload.push_front(action);
else
_FifoToDownload.push_back(action);
MUTEX_UNLOCK(_MutexToDownload);
}
// ***************************************************************************
void CDownloadQueueTask::setPriority(CardElement *card)
{
MUTEX_LOCK(_MutexToDownload);
for (Fifo::iterator it=_FifoToDownload.begin(); it!=_FifoToDownload.end(); ++it)
{
DownloadAction *action = *it;
if (action && (action->relatedCard() == card))
{
_FifoToDownload.erase(it);
_FifoToDownload.push_front(action);
//_HttpClient->abortRequest(); // kill the current download if the background thread is downloading
// TODO: if aborting a current download, reinsert the current action in second position
break;
}
}
MUTEX_UNLOCK(_MutexToDownload);
}
// ***************************************************************************
bool CDownloadQueueTask::isAlreadyDownloaded(CardElement *card)
{
MUTEX_LOCK(_MutexDownloaded);
for (Fifo::iterator it=_FifoDownloaded.begin(); it!=_FifoDownloaded.end(); ++it)
{
DownloadAction *action = *it;
if (action && (action->relatedCard() == card))
{
MUTEX_UNLOCK(_MutexDownloaded);
return true;
}
}
MUTEX_UNLOCK(_MutexDownloaded);
return false;
}
// ***************************************************************************
void CDownloadQueueTask::setDestinationMedia(CardElement *card, u32 idMedia)
{
MUTEX_LOCK(_MutexToDownload);
for (Fifo::iterator it=_FifoToDownload.begin(); it!=_FifoToDownload.end(); ++it)
{
DownloadAction *action = *it;
if (action && (action->relatedCard() == card))
{
// Don't change current destination media if already set, set only if blank
if ((idMedia == ~0) || (action->getIdMedia() == ~0))
{
action->setIdMedia(idMedia);
}
MUTEX_UNLOCK(_MutexToDownload);
return;
}
}
MUTEX_UNLOCK(_MutexToDownload);
MUTEX_LOCK(_MutexDownloaded);
for (Fifo::iterator it=_FifoDownloaded.begin(); it!=_FifoDownloaded.end(); ++it)
{
DownloadAction *action = *it;
if (action && (action->relatedCard() == card))
{
// Don't change current destination media if already set, set only if blank
if ((idMedia == ~0) || (action->getIdMedia() == ~0))
{
action->setIdMedia(idMedia);
}
MUTEX_UNLOCK(_MutexDownloaded);
return;
}
}
MUTEX_UNLOCK(_MutexDownloaded);
DownloadAction *action = _CurrentDownloadingAction;
if (action && (action->relatedCard() == card))
{
// Don't change current destination media if already set, set only if blank
if ((idMedia == ~0) || (action->getIdMedia() == ~0))
{
action->setIdMedia(idMedia);
}
}
}
// ***************************************************************************
DownloadAction *CDownloadQueueTask::getNextCompletedDownload()
{
MUTEX_LOCK(_MutexDownloaded);
if (_FifoDownloaded.empty())
{
MUTEX_UNLOCK(_MutexDownloaded);
return NULL;
}
DownloadAction *downloadAction = _FifoDownloaded.front();
_FifoDownloaded.pop_front();
MUTEX_UNLOCK(_MutexDownloaded);
return downloadAction;
}
#ifndef USER_MODE
unsigned int CDownloadQueueTask::getMemoryUsage() const
{
unsigned int size = CamCamHttpClient::getMemoryUsage();
size += sizeof(*this);
MUTEX_LOCK(_MutexDownloaded);
// We suppose that a "DownloadAction" is a void* and a bool
size += _FifoDownloaded.size() * (sizeof(bool) + sizeof(void*))
+ _FifoToDownload.size() * (sizeof(bool) + sizeof(void*));
MUTEX_UNLOCK(_MutexDownloaded);
return size;
}
#endif
// ***************************************************************************
void CDownloadQueueTask::clear()
{
// TODO: make sure the current download will not add an entry into _FifoDownloaded
MUTEX_LOCK(_MutexToDownload);
_FifoToDownload.clear();
MUTEX_UNLOCK(_MutexToDownload);
MUTEX_LOCK(_MutexDownloaded);
_FifoDownloaded.clear();
MUTEX_UNLOCK(_MutexDownloaded);
}
// ***************************************************************************
bool CamCamHttpClient::downloadFile(u32 fileId, const char *fileDesc, std::string& actualFilename)
{
const char errorTxt [] = "Could not download asset #%u %s, %s";
SimpleString<64> args;
#ifdef USER_MODE
args.sprintf("id=%u&t=%s&x=1&lg=%s", fileId, fileDesc, Account._LanguageCode.c_str());
#else
args.sprintf("id=%u&t=%s&lg=%s", fileId, fileDesc, Account._LanguageCode.c_str());
#endif
bool suppressAlphaWarning = (strncmp(fileDesc, "tba", 3) == 0);
if (!doRequest("dlfile", args.c_str(), suppressAlphaWarning ? SILENT : USE_MORE_INFO, __FUNCTION__, printfToStr(errorTxt, fileId, fileDesc, "failed").c_str(), false))
return false; // the method takes care of the log message
// Check if the file was downloaded, or an error was returned
const std::string& contentType = _HttpClient.getResponseHeader("Content-Type");
if ((contentType != "application/octet-stream") &&
(contentType.substr(0, 6) != "image/") &&
(contentType != "text/plain")) //TEMP
{
bool suppressAlphaWarning = (strncmp(fileDesc, "tba", 3) == 0);
return onPageError(printfToStr(errorTxt, fileId, fileDesc, "invalid content").c_str(), __FUNCTION__, !suppressAlphaWarning);
}
// Get filename
const std::string& contDisp = _HttpClient.getResponseHeader("Content-Disposition");
if (contDisp.empty())
{
// Get filename from Location, deduce folder from fileDesc
extern const char *ThumbnailPath;
if (strncmp(fileDesc, "tb", 2) == 0)
actualFilename = std::string(CurrentDir) + ThumbnailPath;
else if (strncmp(fileDesc, "zcc", 3) == 0)
actualFilename = std::string(CurrentDir) + "/ZCC/";
else
{
_ErrorString.sprintf(errorTxt, fileId, fileDesc, "unknown file desc");
logStr(__FUNCTION__"-error: %s", _ErrorString.c_str());
return false;
}
const std::string& location = _HttpClient.getResponseHeader("Location");
std::string filename = location.substr(location.rfind('/') + 1); // skip path
filename = filename.substr(0, filename.find('?')); // suppress authentication parameters
if (filename.empty())
{
_ErrorString.sprintf(errorTxt, fileId, fileDesc, "empty filename from location");
logStr(__FUNCTION__"-error: %s", _ErrorString.c_str());
return false;
}
actualFilename += filename;
}
else
{
// Get folder+filename from Content-Disposition header
std::string::size_type p = contDisp.find("filename=");
if (p == std::string::npos)
{
_ErrorString.sprintf(errorTxt, fileId, fileDesc, "unknown filename");
logStr(__FUNCTION__"-error: %s", _ErrorString.c_str());
return false;
}
actualFilename = contDisp.substr(p+9);
if (actualFilename.empty())
{
_ErrorString.sprintf(errorTxt, fileId, fileDesc, "empty filename");
logStr(__FUNCTION__"-error: %s", _ErrorString.c_str());
return false;
}
}
extern HANDLE PackFileMutex;
if (WAIT_OBJECT_0 != WaitForSingleObject(PackFileMutex, INFINITE))
return 0;
// Write buffer to disk
UEString udActualFilename(actualFilename.c_str(), false, &_HttpClient); // urldecode the filename
if (!writeDownloadedFile(udActualFilename.c_str()))
{
_ErrorString.sprintf(errorTxt, fileId, fileDesc, "writing file");
logStr(__FUNCTION__"-error: %s", _ErrorString.c_str());
ReleaseMutex(PackFileMutex);
return false;
}
ReleaseMutex(PackFileMutex);
//logStr(__FUNCTION__"-info: wrote %s (%u bytes)", actualFilename.c_str(), _HttpClient.getResponsePage().size());
return true;
}
// ***************************************************************************
bool CamCamHttpClient::downloadFileFromURL(const char *url, std::string& actualFilename, bool silentError)
{
if (!doRequest(url, "", silentError ? SILENT : USE_MORE_INFO, __FUNCTION__, printfToStr("Could not download %s from CDN", actualFilename.c_str()).c_str(), false, true))
return false;
// Write buffer to disk
if (!writeDownloadedFile(actualFilename.c_str()))
{
_ErrorString.sprintf("Could not download %s from CDN, writing file", actualFilename.c_str());
if (!silentError)
logStr(__FUNCTION__"-error: %s", _ErrorString.c_str());
return false;
}
//logStr(__FUNCTION__"-info: wrote %s (%u bytes)", actualFilename.c_str(), _HttpClient.getResponsePage().size());
return true;
}
#ifndef USER_MODE
unsigned int CamCamHttpClient::getMemoryUsage() const
{
unsigned int size = 0;
size += _HttpClient.getMemoryUsage() + sizeof(*this);
return size;
}
#endif
// ***************************************************************************
void CDownloadQueueTask::waitUntilNoCardsNeeded()
{
while (_CardsLocked)
{
Sleep(10);
}
}
// ***************************************************************************
const CardElement * CDownloadQueueTask::currentDownloadCardElement()
{
if (_CurrentDownloadingAction)
return _CurrentDownloadingAction->relatedCard();
return NULL;
}
// ***************************************************************************
bool CDownloadQueueTask::isEmpty()
{
MUTEX_LOCK(_MutexToDownload);
bool isEmpty = _FifoToDownload.empty();
MUTEX_UNLOCK(_MutexToDownload);
return isEmpty;
}
// ***************************************************************************
void CDownloadQueueTask::run()
{
_HttpClient.unabortRequest();
while (true)
{
// Check head of queue
MUTEX_LOCK(_MutexToDownload);
if (_FifoToDownload.empty())
{
_CardsLocked = false;
MUTEX_UNLOCK(_MutexToDownload);
Sleep(500);
if (_HttpClient.isAborting())
break;
continue;
}
_CardsLocked = true;
_CurrentDownloadingAction = _FifoToDownload.front();
_FifoToDownload.pop_front();
MUTEX_UNLOCK(_MutexToDownload);
// Execute the download action
_CurrentDownloadingAction->bgDownload(this);
// Tell the main thread that the downloaded has been completed
MUTEX_LOCK(_MutexDownloaded);
_FifoDownloaded.push_back(_CurrentDownloadingAction);
MUTEX_UNLOCK(_MutexDownloaded);
_CurrentDownloadingAction = NULL;
if (_HttpClient.isAborting())
{
_CardsLocked = false;
break;
}
}
DownloadThumbnailAction::clearCDNBaseURL();
_IsRunning = false;
}
#endif