AssetsManagerEx.cpp 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412
  1. /****************************************************************************
  2. Copyright (c) 2014 cocos2d-x.org
  3. Copyright (c) 2015-2016 Chukong Technologies Inc.
  4. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  5. http://www.cocos2d-x.org
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. ****************************************************************************/
  22. #include "AssetsManagerEx.h"
  23. #include "base/ccUTF8.h"
  24. #include "CCAsyncTaskPool.h"
  25. #include <stdio.h>
  26. #include <errno.h>
  27. #ifdef MINIZIP_FROM_SYSTEM
  28. #include <minizip/unzip.h>
  29. #else // from our embedded sources
  30. #include "unzip/unzip.h"
  31. #endif
  32. NS_CC_EXT_BEGIN
  33. #define VERSION_FILENAME "version.manifest"
  34. #define TEMP_MANIFEST_FILENAME "project.manifest.temp"
  35. #define TEMP_PACKAGE_SUFFIX "_temp"
  36. #define MANIFEST_FILENAME "project.manifest"
  37. #define BUFFER_SIZE 8192
  38. #define MAX_FILENAME 512
  39. #define DEFAULT_CONNECTION_TIMEOUT 45
  40. #define SAVE_POINT_INTERVAL 0.1
  41. const std::string AssetsManagerEx::VERSION_ID = "@version";
  42. const std::string AssetsManagerEx::MANIFEST_ID = "@manifest";
  43. // Implementation of AssetsManagerEx
  44. AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath)
  45. : _updateState(State::UNINITED)
  46. , _assets(nullptr)
  47. , _storagePath("")
  48. , _tempVersionPath("")
  49. , _cacheManifestPath("")
  50. , _tempManifestPath("")
  51. , _localManifest(nullptr)
  52. , _tempManifest(nullptr)
  53. , _remoteManifest(nullptr)
  54. , _updateEntry(UpdateEntry::NONE)
  55. , _percent(0)
  56. , _percentByFile(0)
  57. , _totalSize(0)
  58. , _sizeCollected(0)
  59. , _totalDownloaded(0)
  60. , _totalToDownload(0)
  61. , _totalWaitToDownload(0)
  62. , _nextSavePoint(0.0)
  63. , _downloadResumed(false)
  64. , _maxConcurrentTask(32)
  65. , _currConcurrentTask(0)
  66. , _verifyCallback(nullptr)
  67. , _inited(false)
  68. {
  69. init(manifestUrl, storagePath);
  70. }
  71. AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath, const VersionCompareHandle& handle)
  72. : _updateState(State::UNINITED)
  73. , _assets(nullptr)
  74. , _storagePath("")
  75. , _tempVersionPath("")
  76. , _cacheManifestPath("")
  77. , _tempManifestPath("")
  78. , _localManifest(nullptr)
  79. , _tempManifest(nullptr)
  80. , _remoteManifest(nullptr)
  81. , _updateEntry(UpdateEntry::NONE)
  82. , _percent(0)
  83. , _percentByFile(0)
  84. , _totalSize(0)
  85. , _sizeCollected(0)
  86. , _totalDownloaded(0)
  87. , _totalToDownload(0)
  88. , _totalWaitToDownload(0)
  89. , _nextSavePoint(0.0)
  90. , _downloadResumed(false)
  91. , _maxConcurrentTask(32)
  92. , _currConcurrentTask(0)
  93. , _versionCompareHandle(handle)
  94. , _verifyCallback(nullptr)
  95. , _eventCallback(nullptr)
  96. , _inited(false)
  97. {
  98. init(manifestUrl, storagePath);
  99. }
  100. void AssetsManagerEx::init(const std::string& manifestUrl, const std::string& storagePath)
  101. {
  102. // Init variables
  103. std::string pointer = StringUtils::format("%p", this);
  104. _eventName = "__cc_assets_manager_" + pointer;
  105. _fileUtils = FileUtils::getInstance();
  106. network::DownloaderHints hints =
  107. {
  108. static_cast<uint32_t>(_maxConcurrentTask),
  109. DEFAULT_CONNECTION_TIMEOUT,
  110. ".tmp"
  111. };
  112. _downloader = std::shared_ptr<network::Downloader>(new network::Downloader(hints));
  113. _downloader->onTaskError = std::bind(&AssetsManagerEx::onError, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
  114. _downloader->onTaskProgress = [this](const network::DownloadTask& task,
  115. int64_t /*bytesReceived*/,
  116. int64_t totalBytesReceived,
  117. int64_t totalBytesExpected)
  118. {
  119. this->onProgress(totalBytesExpected, totalBytesReceived, task.requestURL, task.identifier);
  120. };
  121. _downloader->onFileTaskSuccess = [this](const network::DownloadTask& task)
  122. {
  123. this->onSuccess(task.requestURL, task.storagePath, task.identifier);
  124. };
  125. setStoragePath(storagePath);
  126. _tempVersionPath = _tempStoragePath + VERSION_FILENAME;
  127. _cacheManifestPath = _storagePath + MANIFEST_FILENAME;
  128. _tempManifestPath = _tempStoragePath + TEMP_MANIFEST_FILENAME;
  129. if (manifestUrl.size() > 0)
  130. {
  131. loadLocalManifest(manifestUrl);
  132. }
  133. }
  134. AssetsManagerEx::~AssetsManagerEx()
  135. {
  136. _downloader->onTaskError = (nullptr);
  137. _downloader->onFileTaskSuccess = (nullptr);
  138. _downloader->onTaskProgress = (nullptr);
  139. CC_SAFE_RELEASE(_localManifest);
  140. // _tempManifest could share a ptr with _remoteManifest or _localManifest
  141. if (_tempManifest != _localManifest && _tempManifest != _remoteManifest)
  142. CC_SAFE_RELEASE(_tempManifest);
  143. CC_SAFE_RELEASE(_remoteManifest);
  144. }
  145. AssetsManagerEx* AssetsManagerEx::create(const std::string& manifestUrl, const std::string& storagePath)
  146. {
  147. AssetsManagerEx* ret = new (std::nothrow) AssetsManagerEx(manifestUrl, storagePath);
  148. if (ret)
  149. {
  150. ret->autorelease();
  151. }
  152. else
  153. {
  154. CC_SAFE_DELETE(ret);
  155. }
  156. return ret;
  157. }
  158. void AssetsManagerEx::initManifests()
  159. {
  160. _inited = true;
  161. // Init and load temporary manifest
  162. _tempManifest = new (std::nothrow) Manifest();
  163. if (_tempManifest)
  164. {
  165. _tempManifest->parseFile(_tempManifestPath);
  166. // Previous update is interrupted
  167. if (_fileUtils->isFileExist(_tempManifestPath))
  168. {
  169. // Manifest parse failed, remove all temp files
  170. if (!_tempManifest->isLoaded())
  171. {
  172. _fileUtils->removeDirectory(_tempStoragePath);
  173. CC_SAFE_RELEASE(_tempManifest);
  174. _tempManifest = nullptr;
  175. }
  176. }
  177. }
  178. else
  179. {
  180. _inited = false;
  181. }
  182. // Init remote manifest for future usage
  183. _remoteManifest = new (std::nothrow) Manifest();
  184. if (!_remoteManifest)
  185. {
  186. _inited = false;
  187. }
  188. if (!_inited)
  189. {
  190. CC_SAFE_RELEASE(_localManifest);
  191. CC_SAFE_RELEASE(_tempManifest);
  192. CC_SAFE_RELEASE(_remoteManifest);
  193. _localManifest = nullptr;
  194. _tempManifest = nullptr;
  195. _remoteManifest = nullptr;
  196. }
  197. }
  198. void AssetsManagerEx::prepareLocalManifest()
  199. {
  200. // An alias to assets
  201. _assets = &(_localManifest->getAssets());
  202. // Add search paths
  203. _localManifest->prependSearchPaths();
  204. }
  205. bool AssetsManagerEx::loadLocalManifest(Manifest* localManifest, const std::string& storagePath)
  206. {
  207. if (_updateState > State::UNINITED)
  208. {
  209. return false;
  210. }
  211. if (!localManifest || !localManifest->isLoaded())
  212. {
  213. return false;
  214. }
  215. _inited = true;
  216. // Reset storage path
  217. if (storagePath.size() > 0)
  218. {
  219. setStoragePath(storagePath);
  220. _tempVersionPath = _tempStoragePath + VERSION_FILENAME;
  221. _cacheManifestPath = _storagePath + MANIFEST_FILENAME;
  222. _tempManifestPath = _tempStoragePath + TEMP_MANIFEST_FILENAME;
  223. }
  224. // Release existing local manifest
  225. if (_localManifest)
  226. {
  227. CC_SAFE_RELEASE(_localManifest);
  228. }
  229. _localManifest = localManifest;
  230. _localManifest->retain();
  231. // Find the cached manifest file
  232. Manifest *cachedManifest = nullptr;
  233. if (_fileUtils->isFileExist(_cacheManifestPath))
  234. {
  235. cachedManifest = new (std::nothrow) Manifest();
  236. if (cachedManifest)
  237. {
  238. cachedManifest->parseFile(_cacheManifestPath);
  239. if (!cachedManifest->isLoaded())
  240. {
  241. _fileUtils->removeFile(_cacheManifestPath);
  242. CC_SAFE_RELEASE(cachedManifest);
  243. cachedManifest = nullptr;
  244. }
  245. }
  246. }
  247. // Compare with cached manifest to determine which one to use
  248. if (cachedManifest)
  249. {
  250. bool localNewer = _localManifest->versionGreater(cachedManifest, _versionCompareHandle);
  251. if (localNewer)
  252. {
  253. // Recreate storage, to empty the content
  254. _fileUtils->removeDirectory(_storagePath);
  255. _fileUtils->createDirectory(_storagePath);
  256. CC_SAFE_RELEASE(cachedManifest);
  257. }
  258. else
  259. {
  260. CC_SAFE_RELEASE(_localManifest);
  261. _localManifest = cachedManifest;
  262. }
  263. }
  264. prepareLocalManifest();
  265. // Init temp manifest and remote manifest
  266. initManifests();
  267. if (!_inited)
  268. {
  269. return false;
  270. }
  271. else
  272. {
  273. _updateState = State::UNCHECKED;
  274. return true;
  275. }
  276. }
  277. bool AssetsManagerEx::loadLocalManifest(const std::string& manifestUrl)
  278. {
  279. if (manifestUrl.size() == 0)
  280. {
  281. return false;
  282. }
  283. if (_updateState > State::UNINITED)
  284. {
  285. return false;
  286. }
  287. _manifestUrl = manifestUrl;
  288. // Init and load local manifest
  289. _localManifest = new (std::nothrow) Manifest();
  290. if (!_localManifest)
  291. {
  292. return false;
  293. }
  294. Manifest *cachedManifest = nullptr;
  295. // Find the cached manifest file
  296. if (_fileUtils->isFileExist(_cacheManifestPath))
  297. {
  298. cachedManifest = new (std::nothrow) Manifest();
  299. if (cachedManifest)
  300. {
  301. cachedManifest->parseFile(_cacheManifestPath);
  302. if (!cachedManifest->isLoaded())
  303. {
  304. _fileUtils->removeFile(_cacheManifestPath);
  305. CC_SAFE_RELEASE(cachedManifest);
  306. cachedManifest = nullptr;
  307. }
  308. }
  309. }
  310. // Ensure no search path of cached manifest is used to load this manifest
  311. std::vector<std::string> searchPaths = _fileUtils->getSearchPaths();
  312. if (cachedManifest)
  313. {
  314. std::vector<std::string> cacheSearchPaths = cachedManifest->getSearchPaths();
  315. std::vector<std::string> trimmedPaths = searchPaths;
  316. for (auto path : cacheSearchPaths)
  317. {
  318. const auto pos = std::find(trimmedPaths.begin(), trimmedPaths.end(), path);
  319. if (pos != trimmedPaths.end())
  320. {
  321. trimmedPaths.erase(pos);
  322. }
  323. }
  324. _fileUtils->setSearchPaths(trimmedPaths);
  325. }
  326. // Load local manifest in app package
  327. _localManifest->parseFile(_manifestUrl);
  328. if (cachedManifest)
  329. {
  330. // Restore search paths
  331. _fileUtils->setSearchPaths(searchPaths);
  332. }
  333. if (_localManifest->isLoaded())
  334. {
  335. // Compare with cached manifest to determine which one to use
  336. if (cachedManifest)
  337. {
  338. bool localNewer = _localManifest->versionGreater(cachedManifest, _versionCompareHandle);
  339. if (localNewer)
  340. {
  341. // Recreate storage, to empty the content
  342. _fileUtils->removeDirectory(_storagePath);
  343. _fileUtils->createDirectory(_storagePath);
  344. CC_SAFE_RELEASE(cachedManifest);
  345. }
  346. else
  347. {
  348. CC_SAFE_RELEASE(_localManifest);
  349. _localManifest = cachedManifest;
  350. }
  351. }
  352. prepareLocalManifest();
  353. }
  354. // Fail to load local manifest
  355. if (!_localManifest->isLoaded())
  356. {
  357. CCLOG("AssetsManagerEx : No local manifest file found error.\n");
  358. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
  359. return false;
  360. }
  361. initManifests();
  362. _updateState = State::UNCHECKED;
  363. return true;
  364. }
  365. bool AssetsManagerEx::loadRemoteManifest(Manifest* remoteManifest)
  366. {
  367. if (!_inited || _updateState > State::UNCHECKED)
  368. {
  369. return false;
  370. }
  371. if (!remoteManifest || !remoteManifest->isLoaded())
  372. {
  373. return false;
  374. }
  375. // Release existing remote manifest
  376. if (_remoteManifest)
  377. {
  378. CC_SAFE_RELEASE(_remoteManifest);
  379. }
  380. _remoteManifest = remoteManifest;
  381. _remoteManifest->retain();
  382. // Compare manifest version and set state
  383. if (_localManifest->versionGreaterOrEquals(_remoteManifest, _versionCompareHandle))
  384. {
  385. _updateState = State::UP_TO_DATE;
  386. _fileUtils->removeDirectory(_tempStoragePath);
  387. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
  388. }
  389. else
  390. {
  391. _updateState = State::NEED_UPDATE;
  392. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
  393. }
  394. return true;
  395. }
  396. std::string AssetsManagerEx::basename(const std::string& path) const
  397. {
  398. size_t found = path.find_last_of("/\\");
  399. if (std::string::npos != found)
  400. {
  401. return path.substr(0, found);
  402. }
  403. else
  404. {
  405. return path;
  406. }
  407. }
  408. std::string AssetsManagerEx::get(const std::string& key) const
  409. {
  410. auto it = _assets->find(key);
  411. if (it != _assets->cend()) {
  412. return _storagePath + it->second.path;
  413. }
  414. else return "";
  415. }
  416. const Manifest* AssetsManagerEx::getLocalManifest() const
  417. {
  418. return _localManifest;
  419. }
  420. const Manifest* AssetsManagerEx::getRemoteManifest() const
  421. {
  422. return _remoteManifest;
  423. }
  424. const std::string& AssetsManagerEx::getStoragePath() const
  425. {
  426. return _storagePath;
  427. }
  428. void AssetsManagerEx::setStoragePath(const std::string& storagePath)
  429. {
  430. _storagePath = storagePath;
  431. adjustPath(_storagePath);
  432. _fileUtils->createDirectory(_storagePath);
  433. _tempStoragePath = _storagePath;
  434. _tempStoragePath.insert(_storagePath.size() - 1, TEMP_PACKAGE_SUFFIX);
  435. _fileUtils->createDirectory(_tempStoragePath);
  436. }
  437. void AssetsManagerEx::adjustPath(std::string &path)
  438. {
  439. if (path.size() > 0 && path[path.size() - 1] != '/')
  440. {
  441. path.append("/");
  442. }
  443. }
  444. bool AssetsManagerEx::decompress(const std::string &zip)
  445. {
  446. // Find root path for zip file
  447. size_t pos = zip.find_last_of("/\\");
  448. if (pos == std::string::npos)
  449. {
  450. CCLOG("AssetsManagerEx : no root path specified for zip file %s\n", zip.c_str());
  451. return false;
  452. }
  453. const std::string rootPath = zip.substr(0, pos+1);
  454. // Open the zip file
  455. unzFile zipfile = unzOpen(FileUtils::getInstance()->getSuitableFOpen(zip).c_str());
  456. if (! zipfile)
  457. {
  458. CCLOG("AssetsManagerEx : can not open downloaded zip file %s\n", zip.c_str());
  459. return false;
  460. }
  461. // Get info about the zip file
  462. unz_global_info global_info;
  463. if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK)
  464. {
  465. CCLOG("AssetsManagerEx : can not read file global info of %s\n", zip.c_str());
  466. unzClose(zipfile);
  467. return false;
  468. }
  469. // Buffer to hold data read from the zip file
  470. char readBuffer[BUFFER_SIZE];
  471. // Loop to extract all files.
  472. uLong i;
  473. for (i = 0; i < global_info.number_entry; ++i)
  474. {
  475. // Get info about current file.
  476. unz_file_info fileInfo;
  477. char fileName[MAX_FILENAME];
  478. if (unzGetCurrentFileInfo(zipfile,
  479. &fileInfo,
  480. fileName,
  481. MAX_FILENAME,
  482. NULL,
  483. 0,
  484. NULL,
  485. 0) != UNZ_OK)
  486. {
  487. CCLOG("AssetsManagerEx : can not read compressed file info\n");
  488. unzClose(zipfile);
  489. return false;
  490. }
  491. const std::string fullPath = rootPath + fileName;
  492. // Check if this entry is a directory or a file.
  493. const size_t filenameLength = strlen(fileName);
  494. if (fileName[filenameLength-1] == '/')
  495. {
  496. //There are not directory entry in some case.
  497. //So we need to create directory when decompressing file entry
  498. if ( !_fileUtils->createDirectory(basename(fullPath)) )
  499. {
  500. // Failed to create directory
  501. CCLOG("AssetsManagerEx : can not create directory %s\n", fullPath.c_str());
  502. unzClose(zipfile);
  503. return false;
  504. }
  505. }
  506. else
  507. {
  508. // Create all directories in advance to avoid issue
  509. std::string dir = basename(fullPath);
  510. if (!_fileUtils->isDirectoryExist(dir)) {
  511. if (!_fileUtils->createDirectory(dir)) {
  512. // Failed to create directory
  513. CCLOG("AssetsManagerEx : can not create directory %s\n", fullPath.c_str());
  514. unzClose(zipfile);
  515. return false;
  516. }
  517. }
  518. // Entry is a file, so extract it.
  519. // Open current file.
  520. if (unzOpenCurrentFile(zipfile) != UNZ_OK)
  521. {
  522. CCLOG("AssetsManagerEx : can not extract file %s\n", fileName);
  523. unzClose(zipfile);
  524. return false;
  525. }
  526. // Create a file to store current file.
  527. FILE *out = fopen(FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str(), "wb");
  528. if (!out)
  529. {
  530. CCLOG("AssetsManagerEx : can not create decompress destination file %s (errno: %d)\n", fullPath.c_str(), errno);
  531. unzCloseCurrentFile(zipfile);
  532. unzClose(zipfile);
  533. return false;
  534. }
  535. // Write current file content to destinate file.
  536. int error = UNZ_OK;
  537. do
  538. {
  539. error = unzReadCurrentFile(zipfile, readBuffer, BUFFER_SIZE);
  540. if (error < 0)
  541. {
  542. CCLOG("AssetsManagerEx : can not read zip file %s, error code is %d\n", fileName, error);
  543. fclose(out);
  544. unzCloseCurrentFile(zipfile);
  545. unzClose(zipfile);
  546. return false;
  547. }
  548. if (error > 0)
  549. {
  550. fwrite(readBuffer, error, 1, out);
  551. }
  552. } while(error > 0);
  553. fclose(out);
  554. }
  555. unzCloseCurrentFile(zipfile);
  556. // Goto next entry listed in the zip file.
  557. if ((i+1) < global_info.number_entry)
  558. {
  559. if (unzGoToNextFile(zipfile) != UNZ_OK)
  560. {
  561. CCLOG("AssetsManagerEx : can not read next file for decompressing\n");
  562. unzClose(zipfile);
  563. return false;
  564. }
  565. }
  566. }
  567. unzClose(zipfile);
  568. return true;
  569. }
  570. void AssetsManagerEx::decompressDownloadedZip(const std::string &customId, const std::string &storagePath)
  571. {
  572. struct AsyncData
  573. {
  574. std::string customId;
  575. std::string zipFile;
  576. bool succeed;
  577. };
  578. AsyncData* asyncData = new AsyncData;
  579. asyncData->customId = customId;
  580. asyncData->zipFile = storagePath;
  581. asyncData->succeed = false;
  582. std::function<void(void*)> decompressFinished = [this](void* param) {
  583. auto dataInner = reinterpret_cast<AsyncData*>(param);
  584. if (dataInner->succeed)
  585. {
  586. fileSuccess(dataInner->customId, dataInner->zipFile);
  587. }
  588. else
  589. {
  590. std::string errorMsg = "Unable to decompress file " + dataInner->zipFile;
  591. // Ensure zip file deletion (if decompress failure cause task thread exit anormally)
  592. _fileUtils->removeFile(dataInner->zipFile);
  593. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS, "", errorMsg);
  594. fileError(dataInner->customId, errorMsg);
  595. }
  596. delete dataInner;
  597. };
  598. AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_OTHER, decompressFinished, (void*)asyncData, [this, asyncData]() {
  599. // Decompress all compressed files
  600. if (decompress(asyncData->zipFile))
  601. {
  602. asyncData->succeed = true;
  603. }
  604. _fileUtils->removeFile(asyncData->zipFile);
  605. });
  606. }
  607. void AssetsManagerEx::dispatchUpdateEvent(EventAssetsManagerEx::EventCode code, const std::string &assetId/* = ""*/, const std::string &message/* = ""*/, int curle_code/* = CURLE_OK*/, int curlm_code/* = CURLM_OK*/)
  608. {
  609. switch (code)
  610. {
  611. case EventAssetsManagerEx::EventCode::ERROR_UPDATING:
  612. case EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST:
  613. case EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST:
  614. case EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS:
  615. case EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST:
  616. case EventAssetsManagerEx::EventCode::UPDATE_FAILED:
  617. case EventAssetsManagerEx::EventCode::UPDATE_FINISHED:
  618. case EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE:
  619. _updateEntry = UpdateEntry::NONE;
  620. break;
  621. case EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION:
  622. break;
  623. case EventAssetsManagerEx::EventCode::ASSET_UPDATED:
  624. break;
  625. case EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND:
  626. if (_updateEntry == UpdateEntry::CHECK_UPDATE)
  627. {
  628. _updateEntry = UpdateEntry::NONE;
  629. }
  630. break;
  631. default:
  632. break;
  633. }
  634. if (_eventCallback != nullptr) {
  635. EventAssetsManagerEx* event = new (std::nothrow) EventAssetsManagerEx(_eventName, this, code, assetId, message, curle_code, curlm_code);
  636. _eventCallback(event);
  637. event->release();
  638. }
  639. }
  640. AssetsManagerEx::State AssetsManagerEx::getState() const
  641. {
  642. return _updateState;
  643. }
  644. void AssetsManagerEx::downloadVersion()
  645. {
  646. if (_updateState > State::PREDOWNLOAD_VERSION)
  647. return;
  648. std::string versionUrl = _localManifest->getVersionFileUrl();
  649. if (versionUrl.size() > 0)
  650. {
  651. _updateState = State::DOWNLOADING_VERSION;
  652. // Download version file asynchronously
  653. _downloader->createDownloadFileTask(versionUrl, _tempVersionPath, VERSION_ID);
  654. }
  655. // No version file found
  656. else
  657. {
  658. CCLOG("AssetsManagerEx : No version file found, step skipped\n");
  659. _updateState = State::PREDOWNLOAD_MANIFEST;
  660. downloadManifest();
  661. }
  662. }
  663. void AssetsManagerEx::parseVersion()
  664. {
  665. if (_updateState != State::VERSION_LOADED)
  666. return;
  667. _remoteManifest->parseVersion(_tempVersionPath);
  668. if (!_remoteManifest->isVersionLoaded())
  669. {
  670. CCLOG("AssetsManagerEx : Fail to parse version file, step skipped\n");
  671. _updateState = State::PREDOWNLOAD_MANIFEST;
  672. downloadManifest();
  673. }
  674. else
  675. {
  676. if (_localManifest->versionGreaterOrEquals(_remoteManifest, _versionCompareHandle))
  677. {
  678. _updateState = State::UP_TO_DATE;
  679. _fileUtils->removeDirectory(_tempStoragePath);
  680. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
  681. }
  682. else
  683. {
  684. _updateState = State::PREDOWNLOAD_MANIFEST;
  685. downloadManifest();
  686. }
  687. }
  688. }
  689. void AssetsManagerEx::downloadManifest()
  690. {
  691. if (_updateState != State::PREDOWNLOAD_MANIFEST)
  692. return;
  693. std::string manifestUrl = _localManifest->getManifestFileUrl();
  694. if (manifestUrl.size() > 0)
  695. {
  696. _updateState = State::DOWNLOADING_MANIFEST;
  697. // Download version file asynchronously
  698. _downloader->createDownloadFileTask(manifestUrl, _tempManifestPath, MANIFEST_ID);
  699. }
  700. // No manifest file found
  701. else
  702. {
  703. CCLOG("AssetsManagerEx : No manifest file found, check update failed\n");
  704. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST);
  705. _updateState = State::UNCHECKED;
  706. }
  707. }
  708. void AssetsManagerEx::parseManifest()
  709. {
  710. if (_updateState != State::MANIFEST_LOADED)
  711. return;
  712. _remoteManifest->parseFile(_tempManifestPath);
  713. if (!_remoteManifest->isLoaded())
  714. {
  715. CCLOG("AssetsManagerEx : Error parsing manifest file, %s", _tempManifestPath.c_str());
  716. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST);
  717. _updateState = State::UNCHECKED;
  718. }
  719. else
  720. {
  721. if (_localManifest->versionGreaterOrEquals(_remoteManifest, _versionCompareHandle))
  722. {
  723. _updateState = State::UP_TO_DATE;
  724. _fileUtils->removeDirectory(_tempStoragePath);
  725. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
  726. }
  727. else
  728. {
  729. _updateState = State::NEED_UPDATE;
  730. if (_updateEntry == UpdateEntry::DO_UPDATE)
  731. {
  732. startUpdate();
  733. }
  734. else if (_updateEntry == UpdateEntry::CHECK_UPDATE)
  735. {
  736. prepareUpdate();
  737. }
  738. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
  739. }
  740. }
  741. }
  742. void AssetsManagerEx::prepareUpdate()
  743. {
  744. if (_updateState != State::NEED_UPDATE)
  745. return;
  746. // Clean up before update
  747. _failedUnits.clear();
  748. _downloadUnits.clear();
  749. _totalWaitToDownload = _totalToDownload = 0;
  750. _nextSavePoint = 0;
  751. _percent = _percentByFile = _sizeCollected = _totalDownloaded = _totalSize = 0;
  752. _downloadResumed = false;
  753. _downloadedSize.clear();
  754. _totalEnabled = false;
  755. // Temporary manifest exists, previously updating and equals to the remote version, resuming previous download
  756. if (_tempManifest && _tempManifest->isLoaded() && _tempManifest->isUpdating() && _tempManifest->versionEquals(_remoteManifest))
  757. {
  758. _tempManifest->saveToFile(_tempManifestPath);
  759. _tempManifest->genResumeAssetsList(&_downloadUnits);
  760. _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
  761. _downloadResumed = true;
  762. // Collect total size
  763. for(auto iter : _downloadUnits)
  764. {
  765. const DownloadUnit& unit = iter.second;
  766. if (unit.size > 0)
  767. {
  768. _totalSize += unit.size;
  769. }
  770. }
  771. }
  772. else
  773. {
  774. // Temporary manifest exists, but can't be parsed or version doesn't equals remote manifest (out of date)
  775. if (_tempManifest)
  776. {
  777. // Remove all temp files
  778. _fileUtils->removeDirectory(_tempStoragePath);
  779. CC_SAFE_RELEASE(_tempManifest);
  780. // Recreate temp storage path and save remote manifest
  781. _fileUtils->createDirectory(_tempStoragePath);
  782. _remoteManifest->saveToFile(_tempManifestPath);
  783. }
  784. // Temporary manifest will be used to register the download states of each asset,
  785. // in this case, it equals remote manifest.
  786. _tempManifest = _remoteManifest;
  787. // Check difference between local manifest and remote manifest
  788. std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest);
  789. if (diff_map.size() == 0)
  790. {
  791. updateSucceed();
  792. return;
  793. }
  794. else
  795. {
  796. // Generate download units for all assets that need to be updated or added
  797. std::string packageUrl = _remoteManifest->getPackageUrl();
  798. // Preprocessing local files in previous version and creating download folders
  799. for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
  800. {
  801. Manifest::AssetDiff diff = it->second;
  802. if (diff.type != Manifest::DiffType::DELETED)
  803. {
  804. std::string path = diff.asset.path;
  805. DownloadUnit unit;
  806. unit.customId = it->first;
  807. unit.srcUrl = packageUrl + path + "?md5=" + diff.asset.md5;
  808. unit.storagePath = _tempStoragePath + path;
  809. unit.size = diff.asset.size;
  810. _downloadUnits.emplace(unit.customId, unit);
  811. _tempManifest->setAssetDownloadState(it->first, Manifest::DownloadState::UNSTARTED);
  812. _totalSize += unit.size;
  813. }
  814. }
  815. // Start updating the temp manifest
  816. _tempManifest->setUpdating(true);
  817. // Save current download manifest information for resuming
  818. _tempManifest->saveToFile(_tempManifestPath);
  819. _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
  820. }
  821. }
  822. _updateState = State::READY_TO_UPDATE;
  823. }
  824. void AssetsManagerEx::startUpdate()
  825. {
  826. if (_updateState == State::NEED_UPDATE)
  827. {
  828. prepareUpdate();
  829. }
  830. if (_updateState == State::READY_TO_UPDATE)
  831. {
  832. _totalSize = 0;
  833. _updateState = State::UPDATING;
  834. std::string msg;
  835. if (_downloadResumed)
  836. {
  837. msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload);
  838. }
  839. else
  840. {
  841. msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload);
  842. }
  843. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg);
  844. batchDownload();
  845. }
  846. }
  847. void AssetsManagerEx::updateSucceed()
  848. {
  849. // Set temp manifest's updating
  850. if (_tempManifest != nullptr) {
  851. _tempManifest->setUpdating(false);
  852. }
  853. // Every thing is correctly downloaded, do the following
  854. // 1. rename temporary manifest to valid manifest
  855. if (_fileUtils->isFileExist(_tempManifestPath)) {
  856. _fileUtils->renameFile(_tempStoragePath, TEMP_MANIFEST_FILENAME, MANIFEST_FILENAME);
  857. }
  858. // 2. Get the delete files
  859. std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest);
  860. // 3. merge temporary storage path to storage path so that temporary version turns to cached version
  861. if (_fileUtils->isDirectoryExist(_tempStoragePath))
  862. {
  863. // Merging all files in temp storage path to storage path
  864. std::vector<std::string> files;
  865. _fileUtils->listFilesRecursively(_tempStoragePath, &files);
  866. int baseOffset = (int)_tempStoragePath.length();
  867. std::string relativePath, dstPath;
  868. for (std::vector<std::string>::iterator it = files.begin(); it != files.end(); ++it)
  869. {
  870. relativePath.assign((*it).substr(baseOffset));
  871. dstPath.assign(_storagePath + relativePath);
  872. // Create directory
  873. if (relativePath.back() == '/')
  874. {
  875. _fileUtils->createDirectory(dstPath);
  876. }
  877. // Copy file
  878. else
  879. {
  880. if (_fileUtils->isFileExist(dstPath))
  881. {
  882. _fileUtils->removeFile(dstPath);
  883. }
  884. _fileUtils->renameFile(*it, dstPath);
  885. }
  886. // Remove from delete list for safe, although this is not the case in general.
  887. auto diff_itr = diff_map.find(dstPath);
  888. if (diff_itr != diff_map.end()) {
  889. diff_map.erase(diff_itr);
  890. }
  891. }
  892. // Preprocessing local files in previous version and creating download folders
  893. for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
  894. {
  895. Manifest::AssetDiff diff = it->second;
  896. if (diff.type == Manifest::DiffType::DELETED)
  897. {
  898. // TODO: Do this when download finish, it don’t matter delete or not.
  899. std::string exsitedPath = _storagePath + diff.asset.path;
  900. _fileUtils->removeFile(exsitedPath);
  901. }
  902. }
  903. }
  904. // 4. swap the localManifest
  905. CC_SAFE_RELEASE(_localManifest);
  906. _localManifest = _remoteManifest;
  907. _localManifest->setManifestRoot(_storagePath);
  908. _remoteManifest = nullptr;
  909. // 5. make local manifest take effect
  910. prepareLocalManifest();
  911. // 6. Set update state
  912. _updateState = State::UP_TO_DATE;
  913. // 7. Notify finished event
  914. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FINISHED);
  915. // 8. Remove temp storage path
  916. _fileUtils->removeDirectory(_tempStoragePath);
  917. }
  918. void AssetsManagerEx::checkUpdate()
  919. {
  920. if (_updateEntry != UpdateEntry::NONE)
  921. {
  922. CCLOGERROR("AssetsManagerEx::checkUpdate, updateEntry isn't NONE");
  923. return;
  924. }
  925. if (!_inited){
  926. CCLOG("AssetsManagerEx : Manifests uninited.\n");
  927. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
  928. return;
  929. }
  930. if (!_localManifest->isLoaded())
  931. {
  932. CCLOG("AssetsManagerEx : No local manifest file found error.\n");
  933. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
  934. return;
  935. }
  936. _updateEntry = UpdateEntry::CHECK_UPDATE;
  937. switch (_updateState) {
  938. case State::FAIL_TO_UPDATE:
  939. _updateState = State::UNCHECKED;
  940. case State::UNCHECKED:
  941. case State::PREDOWNLOAD_VERSION:
  942. {
  943. downloadVersion();
  944. }
  945. break;
  946. case State::UP_TO_DATE:
  947. {
  948. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
  949. }
  950. break;
  951. case State::NEED_UPDATE:
  952. {
  953. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
  954. }
  955. break;
  956. default:
  957. break;
  958. }
  959. }
  960. void AssetsManagerEx::update()
  961. {
  962. if (_updateEntry != UpdateEntry::NONE)
  963. {
  964. CCLOGERROR("AssetsManagerEx::update, updateEntry isn't NONE");
  965. return;
  966. }
  967. if (!_inited){
  968. CCLOG("AssetsManagerEx : Manifests uninited.\n");
  969. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
  970. return;
  971. }
  972. if (!_localManifest->isLoaded())
  973. {
  974. CCLOG("AssetsManagerEx : No local manifest file found error.\n");
  975. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
  976. return;
  977. }
  978. _updateEntry = UpdateEntry::DO_UPDATE;
  979. switch (_updateState) {
  980. case State::UNCHECKED:
  981. {
  982. _updateState = State::PREDOWNLOAD_VERSION;
  983. }
  984. case State::PREDOWNLOAD_VERSION:
  985. {
  986. downloadVersion();
  987. }
  988. break;
  989. case State::VERSION_LOADED:
  990. {
  991. parseVersion();
  992. }
  993. break;
  994. case State::PREDOWNLOAD_MANIFEST:
  995. {
  996. downloadManifest();
  997. }
  998. break;
  999. case State::MANIFEST_LOADED:
  1000. {
  1001. parseManifest();
  1002. }
  1003. break;
  1004. case State::FAIL_TO_UPDATE:
  1005. case State::READY_TO_UPDATE:
  1006. case State::NEED_UPDATE:
  1007. {
  1008. // Manifest not loaded yet
  1009. if (!_remoteManifest->isLoaded())
  1010. {
  1011. _updateState = State::PREDOWNLOAD_MANIFEST;
  1012. downloadManifest();
  1013. }
  1014. else if (_updateEntry == UpdateEntry::DO_UPDATE)
  1015. {
  1016. startUpdate();
  1017. }
  1018. }
  1019. break;
  1020. case State::UP_TO_DATE:
  1021. case State::UPDATING:
  1022. case State::UNZIPPING:
  1023. _updateEntry = UpdateEntry::NONE;
  1024. break;
  1025. default:
  1026. break;
  1027. }
  1028. }
  1029. void AssetsManagerEx::updateAssets(const DownloadUnits& assets)
  1030. {
  1031. if (!_inited){
  1032. CCLOG("AssetsManagerEx : Manifests uninited.\n");
  1033. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
  1034. return;
  1035. }
  1036. if (_updateState != State::UPDATING && _localManifest->isLoaded() && _remoteManifest->isLoaded())
  1037. {
  1038. _updateState = State::UPDATING;
  1039. _downloadUnits.clear();
  1040. _downloadedSize.clear();
  1041. _percent = _percentByFile = _sizeCollected = _totalDownloaded = _totalSize = 0;
  1042. _totalWaitToDownload = _totalToDownload = (int)assets.size();
  1043. _nextSavePoint = 0;
  1044. _totalEnabled = false;
  1045. if (_totalToDownload > 0)
  1046. {
  1047. _downloadUnits = assets;
  1048. this->batchDownload();
  1049. }
  1050. else if (_totalToDownload == 0)
  1051. {
  1052. onDownloadUnitsFinished();
  1053. }
  1054. }
  1055. }
  1056. const DownloadUnits& AssetsManagerEx::getFailedAssets() const
  1057. {
  1058. return _failedUnits;
  1059. }
  1060. void AssetsManagerEx::downloadFailedAssets()
  1061. {
  1062. CCLOG("AssetsManagerEx : Start update %lu failed assets.\n", static_cast<unsigned long>(_failedUnits.size()));
  1063. updateAssets(_failedUnits);
  1064. }
  1065. void AssetsManagerEx::fileError(const std::string& identifier, const std::string& errorStr, int errorCode, int errorCodeInternal)
  1066. {
  1067. auto unitIt = _downloadUnits.find(identifier);
  1068. // Found unit and add it to failed units
  1069. if (unitIt != _downloadUnits.end())
  1070. {
  1071. _totalWaitToDownload--;
  1072. DownloadUnit unit = unitIt->second;
  1073. _failedUnits.emplace(unit.customId, unit);
  1074. }
  1075. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_UPDATING, identifier, errorStr, errorCode, errorCodeInternal);
  1076. _tempManifest->setAssetDownloadState(identifier, Manifest::DownloadState::UNSTARTED);
  1077. _currConcurrentTask = std::max(0, _currConcurrentTask-1);
  1078. queueDowload();
  1079. }
  1080. void AssetsManagerEx::fileSuccess(const std::string &customId, const std::string &storagePath)
  1081. {
  1082. // Set download state to SUCCESSED
  1083. _tempManifest->setAssetDownloadState(customId, Manifest::DownloadState::SUCCESSED);
  1084. auto unitIt = _failedUnits.find(customId);
  1085. // Found unit and delete it
  1086. if (unitIt != _failedUnits.end())
  1087. {
  1088. // Remove from failed units list
  1089. _failedUnits.erase(unitIt);
  1090. }
  1091. unitIt = _downloadUnits.find(customId);
  1092. if (unitIt != _downloadUnits.end())
  1093. {
  1094. // Reduce count only when unit found in _downloadUnits
  1095. _totalWaitToDownload--;
  1096. _percentByFile = 100 * (float)(_totalToDownload - _totalWaitToDownload) / _totalToDownload;
  1097. // Notify progression event
  1098. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "");
  1099. }
  1100. // Notify asset updated event
  1101. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ASSET_UPDATED, customId);
  1102. _currConcurrentTask = std::max(0, _currConcurrentTask-1);
  1103. queueDowload();
  1104. }
  1105. void AssetsManagerEx::onError(const network::DownloadTask& task,
  1106. int errorCode,
  1107. int errorCodeInternal,
  1108. const std::string& errorStr)
  1109. {
  1110. // Skip version error occurred
  1111. if (task.identifier == VERSION_ID)
  1112. {
  1113. CCLOG("AssetsManagerEx : Fail to download version file, step skipped\n");
  1114. _updateState = State::PREDOWNLOAD_MANIFEST;
  1115. downloadManifest();
  1116. }
  1117. else if (task.identifier == MANIFEST_ID)
  1118. {
  1119. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST, task.identifier, errorStr, errorCode, errorCodeInternal);
  1120. _updateState = State::FAIL_TO_UPDATE;
  1121. }
  1122. else
  1123. {
  1124. fileError(task.identifier, errorStr, errorCode, errorCodeInternal);
  1125. }
  1126. }
  1127. void AssetsManagerEx::onProgress(double total, double downloaded, const std::string& /*url*/, const std::string &customId)
  1128. {
  1129. if (customId == VERSION_ID || customId == MANIFEST_ID)
  1130. {
  1131. _percent = 100 * downloaded / total;
  1132. // Notify progression event
  1133. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, customId);
  1134. return;
  1135. }
  1136. else
  1137. {
  1138. // Calcul total downloaded
  1139. bool found = false;
  1140. _totalDownloaded = 0;
  1141. for (auto it = _downloadedSize.begin(); it != _downloadedSize.end(); ++it)
  1142. {
  1143. if (it->first == customId)
  1144. {
  1145. it->second = downloaded;
  1146. found = true;
  1147. }
  1148. _totalDownloaded += it->second;
  1149. }
  1150. // Collect information if not registed
  1151. if (!found)
  1152. {
  1153. // Set download state to DOWNLOADING, this will run only once in the download process
  1154. _tempManifest->setAssetDownloadState(customId, Manifest::DownloadState::DOWNLOADING);
  1155. // Register the download size information
  1156. _downloadedSize.emplace(customId, downloaded);
  1157. // Check download unit size existance, if not exist collect size in total size
  1158. if (_downloadUnits[customId].size == 0)
  1159. {
  1160. _totalSize += total;
  1161. _sizeCollected++;
  1162. // All collected, enable total size
  1163. if (_sizeCollected == _totalToDownload)
  1164. {
  1165. _totalEnabled = true;
  1166. }
  1167. }
  1168. }
  1169. if (_totalEnabled && _updateState == State::UPDATING)
  1170. {
  1171. float currentPercent = 100 * _totalDownloaded / _totalSize;
  1172. // Notify at integer level change
  1173. if ((int)currentPercent != (int)_percent) {
  1174. _percent = currentPercent;
  1175. // Notify progression event
  1176. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, customId);
  1177. }
  1178. }
  1179. }
  1180. }
  1181. void AssetsManagerEx::onSuccess(const std::string &/*srcUrl*/, const std::string &storagePath, const std::string &customId)
  1182. {
  1183. if (customId == VERSION_ID)
  1184. {
  1185. _updateState = State::VERSION_LOADED;
  1186. parseVersion();
  1187. }
  1188. else if (customId == MANIFEST_ID)
  1189. {
  1190. _updateState = State::MANIFEST_LOADED;
  1191. parseManifest();
  1192. }
  1193. else
  1194. {
  1195. bool ok = true;
  1196. auto &assets = _remoteManifest->getAssets();
  1197. auto assetIt = assets.find(customId);
  1198. if (assetIt != assets.end())
  1199. {
  1200. Manifest::Asset asset = assetIt->second;
  1201. if (_verifyCallback != nullptr)
  1202. {
  1203. ok = _verifyCallback(storagePath, asset);
  1204. }
  1205. }
  1206. if (ok)
  1207. {
  1208. bool compressed = assetIt != assets.end() ? assetIt->second.compressed : false;
  1209. if (compressed)
  1210. {
  1211. decompressDownloadedZip(customId, storagePath);
  1212. }
  1213. else
  1214. {
  1215. fileSuccess(customId, storagePath);
  1216. }
  1217. }
  1218. else
  1219. {
  1220. fileError(customId, "Asset file verification failed after downloaded");
  1221. }
  1222. }
  1223. }
  1224. void AssetsManagerEx::destroyDownloadedVersion()
  1225. {
  1226. _fileUtils->removeDirectory(_storagePath);
  1227. _fileUtils->removeDirectory(_tempStoragePath);
  1228. }
  1229. void AssetsManagerEx::batchDownload()
  1230. {
  1231. _queue.clear();
  1232. for(auto iter : _downloadUnits)
  1233. {
  1234. const DownloadUnit& unit = iter.second;
  1235. if (unit.size > 0)
  1236. {
  1237. _totalSize += unit.size;
  1238. _sizeCollected++;
  1239. }
  1240. _queue.push_back(iter.first);
  1241. }
  1242. // All collected, enable total size
  1243. if (_sizeCollected == _totalToDownload)
  1244. {
  1245. _totalEnabled = true;
  1246. }
  1247. queueDowload();
  1248. }
  1249. void AssetsManagerEx::queueDowload()
  1250. {
  1251. if (_totalWaitToDownload == 0)
  1252. {
  1253. this->onDownloadUnitsFinished();
  1254. return;
  1255. }
  1256. while (_currConcurrentTask < _maxConcurrentTask && _queue.size() > 0)
  1257. {
  1258. std::string key = _queue.back();
  1259. _queue.pop_back();
  1260. _currConcurrentTask++;
  1261. DownloadUnit& unit = _downloadUnits[key];
  1262. _fileUtils->createDirectory(basename(unit.storagePath));
  1263. _downloader->createDownloadFileTask(unit.srcUrl, unit.storagePath, unit.customId);
  1264. _tempManifest->setAssetDownloadState(key, Manifest::DownloadState::DOWNLOADING);
  1265. }
  1266. if (_percentByFile / 100 > _nextSavePoint)
  1267. {
  1268. // Save current download manifest information for resuming
  1269. _tempManifest->saveToFile(_tempManifestPath);
  1270. _nextSavePoint += SAVE_POINT_INTERVAL;
  1271. }
  1272. }
  1273. void AssetsManagerEx::onDownloadUnitsFinished()
  1274. {
  1275. // Always save current download manifest information for resuming
  1276. _tempManifest->saveToFile(_tempManifestPath);
  1277. // Finished with error check
  1278. if (_failedUnits.size() > 0)
  1279. {
  1280. _updateState = State::FAIL_TO_UPDATE;
  1281. dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FAILED);
  1282. }
  1283. else if (_updateState == State::UPDATING)
  1284. {
  1285. updateSucceed();
  1286. }
  1287. }
  1288. NS_CC_EXT_END