717 lines
23 KiB
C++
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
|