123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- #include "AssetsManager.h"
- #include <thread>
- #include "base/CCDirector.h"
- #include "base/CCScheduler.h"
- #include "base/CCUserDefault.h"
- #include "network/CCDownloader.h"
- #include "platform/CCFileUtils.h"
- #ifdef MINIZIP_FROM_SYSTEM
- #include <minizip/unzip.h>
- #else
- #include "unzip.h"
- #endif
- NS_CC_EXT_BEGIN;
- using namespace std;
- using namespace cocos2d;
- using namespace cocos2d::network;
- #define KEY_OF_VERSION "current-version-code"
- #define KEY_OF_DOWNLOADED_VERSION "downloaded-version-code"
- #define TEMP_PACKAGE_FILE_NAME "cocos2dx-update-temp-package.zip"
- #define BUFFER_SIZE 8192
- #define MAX_FILENAME 512
- AssetsManager::AssetsManager(const char* packageUrl, const char* versionFileUrl, const char* storagePath)
- : _storagePath(storagePath ? storagePath : "")
- , _version("")
- , _packageUrl(packageUrl ? packageUrl : "")
- , _versionFileUrl(versionFileUrl ? versionFileUrl : "")
- , _downloadedVersion("")
- , _downloader(new Downloader())
- , _connectionTimeout(0)
- , _delegate(nullptr)
- , _isDownloading(false)
- , _shouldDeleteDelegateWhenExit(false)
- {
- checkStoragePath();
-
- _downloader->onTaskError = [this](const DownloadTask& ,
- int errorCode,
- int ,
- const std::string& )
- {
- _isDownloading = false;
-
- if (nullptr == _delegate)
- {
- return;
- }
- auto err = (DownloadTask::ERROR_FILE_OP_FAILED == errorCode) ? ErrorCode::CREATE_FILE : ErrorCode::NETWORK;
- _delegate->onError(err);
- };
-
-
- _downloader->onTaskProgress = [this](const DownloadTask& task,
- int64_t ,
- int64_t totalBytesReceived,
- int64_t totalBytesExpected)
- {
- if(FileUtils::getInstance()->getFileExtension(task.requestURL) != ".zip")
- {
-
- return;
- }
-
- if (nullptr == _delegate)
- {
- return;
- }
-
- int percent = totalBytesExpected ? int(totalBytesReceived * 100 / totalBytesExpected) : 0;
- _delegate->onProgress(percent);
- CCLOG("downloading... %d%%", percent);
- };
-
-
- _downloader->onDataTaskSuccess = [this](const DownloadTask& ,
- std::vector<unsigned char>& data)
- {
-
- const char *p = (char *)data.data();
- _version.insert(_version.end(), p, p + data.size());
-
- if (getVersion() == _version)
- {
- if (_delegate)
- {
- _delegate->onError(ErrorCode::NO_NEW_VERSION);
- }
- CCLOG("there is not new version");
-
- setSearchPath();
- _isDownloading = false;
- return;
- }
-
-
-
- if (_versionFileUrl.empty()
- || _packageUrl.empty()
- || FileUtils::getInstance()->getFileExtension(_packageUrl) != ".zip"
- )
- {
- CCLOG("no version file url, or no package url, or the package is not a zip file");
- _isDownloading = false;
- return;
- }
-
-
- _downloadedVersion = UserDefault::getInstance()->getStringForKey(keyOfDownloadedVersion().c_str());
- if (_downloadedVersion == _version)
- {
- downloadAndUncompress();
- return;
- }
-
-
- const string outFileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
- _downloader->createDownloadFileTask(_packageUrl, outFileName);
- };
-
-
- _downloader->onFileTaskSuccess = [this](const DownloadTask& )
- {
- downloadAndUncompress();
- };
- }
- AssetsManager::~AssetsManager()
- {
- if (_shouldDeleteDelegateWhenExit)
- {
- delete _delegate;
- }
- CC_SAFE_DELETE(_downloader);
- }
- void AssetsManager::checkStoragePath()
- {
- if (_storagePath.size() > 0 && _storagePath[_storagePath.size() - 1] != '/')
- {
- _storagePath.append("/");
- }
- }
- static std::string keyWithHash( const char* prefix, const std::string& url )
- {
- char buf[256];
- sprintf(buf,"%s%zd",prefix,std::hash<std::string>()(url));
- return buf;
- }
- std::string AssetsManager::keyOfVersion() const
- {
- return keyWithHash(KEY_OF_VERSION,_packageUrl);
- }
- std::string AssetsManager::keyOfDownloadedVersion() const
- {
- return keyWithHash(KEY_OF_DOWNLOADED_VERSION,_packageUrl);
- }
- bool AssetsManager::checkUpdate()
- {
- if (_versionFileUrl.size() == 0 || _isDownloading) return false;
-
-
- _version.clear();
- _isDownloading = true;
- _downloader->createDownloadDataTask(_versionFileUrl);
- return true;
- }
- void AssetsManager::downloadAndUncompress()
- {
- std::thread([this]()
- {
- do
- {
-
- if (! uncompress())
- {
- Director::getInstance()->getScheduler()->performFunctionInCocosThread([&, this]{
- UserDefault::getInstance()->setStringForKey(this->keyOfDownloadedVersion().c_str(),"");
- UserDefault::getInstance()->flush();
- if (this->_delegate)
- this->_delegate->onError(ErrorCode::UNCOMPRESS);
- });
- break;
- }
-
- Director::getInstance()->getScheduler()->performFunctionInCocosThread([&, this] {
-
-
- UserDefault::getInstance()->setStringForKey(this->keyOfVersion().c_str(), this->_version.c_str());
-
-
- UserDefault::getInstance()->setStringForKey(this->keyOfDownloadedVersion().c_str(), "");
- UserDefault::getInstance()->flush();
-
-
- this->setSearchPath();
-
-
- string zipfileName = this->_storagePath + TEMP_PACKAGE_FILE_NAME;
- if (remove(zipfileName.c_str()) != 0)
- {
- CCLOG("can not remove downloaded zip file %s", zipfileName.c_str());
- }
-
- if (this->_delegate) this->_delegate->onSuccess();
- });
-
- } while (0);
-
- _isDownloading = false;
- }).detach();
- }
- void AssetsManager::update()
- {
-
-
- }
- bool AssetsManager::uncompress()
- {
-
- string outFileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
- unzFile zipfile = unzOpen(FileUtils::getInstance()->getSuitableFOpen(outFileName).c_str());
- if (! zipfile)
- {
- CCLOG("can not open downloaded zip file %s", outFileName.c_str());
- return false;
- }
-
-
- unz_global_info global_info;
- if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK)
- {
- CCLOG("can not read file global info of %s", outFileName.c_str());
- unzClose(zipfile);
- return false;
- }
-
-
- char readBuffer[BUFFER_SIZE];
-
- CCLOG("start uncompressing");
-
-
- uLong i;
- for (i = 0; i < global_info.number_entry; ++i)
- {
-
- unz_file_info fileInfo;
- char fileName[MAX_FILENAME];
- if (unzGetCurrentFileInfo(zipfile,
- &fileInfo,
- fileName,
- MAX_FILENAME,
- nullptr,
- 0,
- nullptr,
- 0) != UNZ_OK)
- {
- CCLOG("can not read file info");
- unzClose(zipfile);
- return false;
- }
-
- const string fullPath = _storagePath + fileName;
-
-
- const size_t filenameLength = strlen(fileName);
- if (fileName[filenameLength-1] == '/')
- {
-
-
- if (!FileUtils::getInstance()->createDirectory(fullPath))
- {
- CCLOG("can not create directory %s", fullPath.c_str());
- unzClose(zipfile);
- return false;
- }
- }
- else
- {
-
-
-
- const string fileNameStr(fileName);
-
- size_t startIndex=0;
-
- size_t index=fileNameStr.find("/",startIndex);
-
- while(index != std::string::npos)
- {
- const string dir=_storagePath+fileNameStr.substr(0,index);
-
- FILE *out = fopen(FileUtils::getInstance()->getSuitableFOpen(dir).c_str(), "r");
-
- if(!out)
- {
- if (!FileUtils::getInstance()->createDirectory(dir))
- {
- CCLOG("can not create directory %s", dir.c_str());
- unzClose(zipfile);
- return false;
- }
- else
- {
- CCLOG("create directory %s",dir.c_str());
- }
- }
- else
- {
- fclose(out);
- }
-
- startIndex=index+1;
-
- index=fileNameStr.find("/",startIndex);
-
- }
-
-
-
- if (unzOpenCurrentFile(zipfile) != UNZ_OK)
- {
- CCLOG("can not open file %s", fileName);
- unzClose(zipfile);
- return false;
- }
-
-
- FILE *out = fopen(FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str(), "wb");
- if (! out)
- {
- CCLOG("can not open destination file %s", fullPath.c_str());
- unzCloseCurrentFile(zipfile);
- unzClose(zipfile);
- return false;
- }
-
-
- int error = UNZ_OK;
- do
- {
- error = unzReadCurrentFile(zipfile, readBuffer, BUFFER_SIZE);
- if (error < 0)
- {
- CCLOG("can not read zip file %s, error code is %d", fileName, error);
- unzCloseCurrentFile(zipfile);
- unzClose(zipfile);
- return false;
- }
-
- if (error > 0)
- {
- fwrite(readBuffer, error, 1, out);
- }
- } while(error > 0);
-
- fclose(out);
- }
-
- unzCloseCurrentFile(zipfile);
-
-
- if ((i+1) < global_info.number_entry)
- {
- if (unzGoToNextFile(zipfile) != UNZ_OK)
- {
- CCLOG("can not read next file");
- unzClose(zipfile);
- return false;
- }
- }
- }
-
- CCLOG("end uncompressing");
- unzClose(zipfile);
-
- return true;
- }
- void AssetsManager::setSearchPath()
- {
- vector<string> searchPaths = FileUtils::getInstance()->getSearchPaths();
- vector<string>::iterator iter = searchPaths.begin();
- searchPaths.insert(iter, _storagePath);
- FileUtils::getInstance()->setSearchPaths(searchPaths);
- }
- const char* AssetsManager::getPackageUrl() const
- {
- return _packageUrl.c_str();
- }
- void AssetsManager::setPackageUrl(const char *packageUrl)
- {
- _packageUrl = packageUrl;
- }
- const char* AssetsManager::getStoragePath() const
- {
- return _storagePath.c_str();
- }
- void AssetsManager::setStoragePath(const char *storagePath)
- {
- _storagePath = storagePath;
- checkStoragePath();
- }
- const char* AssetsManager::getVersionFileUrl() const
- {
- return _versionFileUrl.c_str();
- }
- void AssetsManager::setVersionFileUrl(const char *versionFileUrl)
- {
- _versionFileUrl = versionFileUrl;
- }
- string AssetsManager::getVersion()
- {
- return UserDefault::getInstance()->getStringForKey(keyOfVersion().c_str());
- }
- void AssetsManager::deleteVersion()
- {
- UserDefault::getInstance()->setStringForKey(keyOfVersion().c_str(), "");
- }
- void AssetsManager::setDelegate(AssetsManagerDelegateProtocol *delegate)
- {
- _delegate = delegate;
- }
- void AssetsManager::setConnectionTimeout(unsigned int timeout)
- {
- _connectionTimeout = timeout;
- }
- unsigned int AssetsManager::getConnectionTimeout()
- {
- return _connectionTimeout;
- }
- AssetsManager* AssetsManager::create(const char* packageUrl, const char* versionFileUrl, const char* storagePath, ErrorCallback errorCallback, ProgressCallback progressCallback, SuccessCallback successCallback )
- {
- class DelegateProtocolImpl : public AssetsManagerDelegateProtocol
- {
- public :
- DelegateProtocolImpl(ErrorCallback& aErrorCallback, ProgressCallback& aProgressCallback, SuccessCallback& aSuccessCallback)
- : errorCallback(aErrorCallback), progressCallback(aProgressCallback), successCallback(aSuccessCallback)
- {}
- virtual void onError(AssetsManager::ErrorCode errorCode) { errorCallback(int(errorCode)); }
- virtual void onProgress(int percent) { progressCallback(percent); }
- virtual void onSuccess() { successCallback(); }
- private :
- ErrorCallback errorCallback;
- ProgressCallback progressCallback;
- SuccessCallback successCallback;
- };
- auto* manager = new (std::nothrow) AssetsManager(packageUrl,versionFileUrl,storagePath);
- auto* delegate = new (std::nothrow) DelegateProtocolImpl(errorCallback,progressCallback,successCallback);
- manager->setDelegate(delegate);
- manager->_shouldDeleteDelegateWhenExit = true;
- manager->autorelease();
- return manager;
- }
- NS_CC_EXT_END;
|