diff --git a/extensions/assets-manager/Downloader.cpp b/extensions/assets-manager/Downloader.cpp index d35d8d21dd..2e5c6f1926 100644 --- a/extensions/assets-manager/Downloader.cpp +++ b/extensions/assets-manager/Downloader.cpp @@ -52,7 +52,7 @@ size_t bufferWriteFunc(void *ptr, size_t size, size_t nmemb, void *userdata) Downloader::StreamData *streamBuffer = (Downloader::StreamData *)userdata; size_t written = size * nmemb; // Avoid pointer overflow - if (streamBuffer->offset + written <= static_cast(streamBuffer->total)) + if (streamBuffer->offset + written <= static_cast(streamBuffer->total)) { memcpy(streamBuffer->buffer + streamBuffer->offset, ptr, written); streamBuffer->offset += written; @@ -273,28 +273,74 @@ void Downloader::prepareDownload(const std::string &srcUrl, const std::string &s } } -bool Downloader::prepareHeader(void *curl, const std::string &srcUrl) const +#if(CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) +Downloader::HeaderInfo Downloader::prepare(const std::string &srcUrl) { - curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str()); - curl_easy_setopt(curl, CURLOPT_HEADER, 1); - curl_easy_setopt(curl, CURLOPT_NOBODY, 1); - if (curl_easy_perform(curl) == CURLE_OK) - return true; + return prepareHeader(srcUrl); +} +#endif + +Downloader::HeaderInfo Downloader::prepareHeader(const std::string &srcUrl, void* header/* = nullptr */) +{ + bool headerGiven = true; + HeaderInfo info; + info.valid = false; + + if (!header) + { + headerGiven = false; + header = curl_easy_init(); + } + + curl_easy_setopt(header, CURLOPT_URL, srcUrl.c_str()); + curl_easy_setopt(header, CURLOPT_HEADER, 1); + curl_easy_setopt(header, CURLOPT_NOBODY, 1); + if (curl_easy_perform(header) == CURLE_OK) + { + char *url; + char *contentType; + curl_easy_getinfo(header, CURLINFO_EFFECTIVE_URL, &url); + curl_easy_getinfo(header, CURLINFO_CONTENT_TYPE, &contentType); + curl_easy_getinfo(header, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &info.contentSize); + curl_easy_getinfo(header, CURLINFO_RESPONSE_CODE, &info.responseCode); + info.url = url; + info.contentType = contentType; + info.valid = true; + + if (_onHeader) + { + _onHeader(srcUrl, info); + } + } else - return false; + { + info.contentSize = -1; + std::string msg = StringUtils::format("Can not get content size of file (%s) : Request header failed", srcUrl.c_str()); + this->notifyError(ErrorCode::PREPARE_HEADER_ERROR, msg); + } + + if (!headerGiven) { + curl_easy_cleanup(header); + } + + return info; } -long Downloader::getContentSize(const std::string &srcUrl) const +long Downloader::getContentSize(const std::string &srcUrl) { - double contentLength = -1; - CURL *header = curl_easy_init(); - if (prepareHeader(header, srcUrl)) - { - curl_easy_getinfo(header, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength); - } - curl_easy_cleanup(header); - - return contentLength; + HeaderInfo info = prepareHeader(srcUrl); + return info.contentSize; +} + +void Downloader::getHeaderAsync(const std::string &srcUrl, const HeaderCallback &callback) +{ + setHeaderCallback(callback); +#if(CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) + auto t = std::thread(&Downloader::prepare, this, srcUrl); +#else + auto t = std::thread(&Downloader::prepareHeader, this, srcUrl, nullptr); +#endif + t.detach(); } void Downloader::downloadToBufferAsync(const std::string &srcUrl, unsigned char *buffer, const long &size, const std::string &customId/* = ""*/) @@ -482,11 +528,10 @@ void Downloader::batchDownloadSync(const DownloadUnits &units, const std::string CURL *header = curl_easy_init(); // Make a resume request curl_easy_setopt(header, CURLOPT_RESUME_FROM_LARGE, 0); - if (prepareHeader(header, units.begin()->second.srcUrl)) + HeaderInfo headerInfo = prepareHeader(units.begin()->second.srcUrl, header); + if (headerInfo.valid) { - long responseCode; - curl_easy_getinfo(header, CURLINFO_RESPONSE_CODE, &responseCode); - if (responseCode == HTTP_CODE_SUPPORT_RESUME) + if (headerInfo.responseCode == HTTP_CODE_SUPPORT_RESUME) { _supportResuming = true; } @@ -682,4 +727,4 @@ void Downloader::groupBatchDownload(const DownloadUnits &units) clearBatchDownloadData(); } -NS_CC_EXT_END +NS_CC_EXT_END \ No newline at end of file diff --git a/extensions/assets-manager/Downloader.h b/extensions/assets-manager/Downloader.h index 55fb405c3e..c012787daa 100644 --- a/extensions/assets-manager/Downloader.h +++ b/extensions/assets-manager/Downloader.h @@ -60,7 +60,9 @@ public: INVALID_URL, - INVALID_STORAGE_PATH + INVALID_STORAGE_PATH, + + PREPARE_HEADER_ERROR }; struct Error @@ -99,11 +101,21 @@ public: unsigned char *buffer; }; + struct HeaderInfo + { + bool valid; + std::string url; + std::string contentType; + double contentSize; + double responseCode; + }; + typedef std::unordered_map DownloadUnits; typedef std::function ErrorCallback; typedef std::function ProgressCallback; typedef std::function SuccessCallback; + typedef std::function HeaderCallback; int getConnectionTimeout(); @@ -114,6 +126,8 @@ public: void setProgressCallback(const ProgressCallback &callback) { _onProgress = callback; }; void setSuccessCallback(const SuccessCallback &callback) { _onSuccess = callback; }; + + void setHeaderCallback(const HeaderCallback &callback) { _onHeader = callback; }; ErrorCallback getErrorCallback() const { return _onError; }; @@ -121,7 +135,11 @@ public: SuccessCallback getSuccessCallback() const { return _onSuccess; }; - long getContentSize(const std::string &srcUrl) const; + HeaderCallback getHeaderCallback() const { return _onHeader; }; + + long getContentSize(const std::string &srcUrl); + + void getHeaderAsync(const std::string &srcUrl, const HeaderCallback &callback); void downloadToBufferAsync(const std::string &srcUrl, unsigned char *buffer, const long &size, const std::string &customId = ""); @@ -152,7 +170,10 @@ protected: void prepareDownload(const std::string &srcUrl, const std::string &storagePath, const std::string &customId, bool resumeDownload, FileDescriptor *fDesc, ProgressData *pData); - bool prepareHeader(void *curl, const std::string &srcUrl) const; +#if(CC_TARGET_PLATFORM == CC_PLATFORM_WP8 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) + HeaderInfo prepare(const std::string &srcUrl); +#endif + HeaderInfo prepareHeader(const std::string &srcUrl, void* header = nullptr); void downloadToBuffer(const std::string &srcUrl, const std::string &customId, const StreamData &buffer, const ProgressData &data); @@ -175,6 +196,8 @@ private: ProgressCallback _onProgress; SuccessCallback _onSuccess; + + HeaderCallback _onHeader; std::string getFileNameFromUrl(const std::string &srcUrl); @@ -193,4 +216,4 @@ int downloadProgressFunc(Downloader::ProgressData *ptr, double totalToDownload, NS_CC_EXT_END -#endif /* defined(__Downloader__) */ +#endif /* defined(__Downloader__) */ \ No newline at end of file