void AssetsManager::update() { if (!_localManifest->isLoaded()) { CCLOG("AssetsManager : No local manifest file found error.\n"); dispatchUpdateEvent(EventAssetsManager::EventCode::ERROR_NO_LOCAL_MANIFEST); return; } _waitToUpdate = true; switch (_updateState) { case State::UNCHECKED: { _updateState = State::PREDOWNLOAD_VERSION; } case State::PREDOWNLOAD_VERSION: { downloadVersion(); } break; case State::VERSION_LOADED: { parseVersion(); } break; case State::PREDOWNLOAD_MANIFEST: { downloadManifest(); } break; case State::MANIFEST_LOADED: { parseManifest(); } break; case State::FAIL_TO_UPDATE: case State::NEED_UPDATE: { // Manifest not loaded yet if (!_remoteManifest->isLoaded()) { _waitToUpdate = true; _updateState = State::PREDOWNLOAD_MANIFEST; downloadManifest(); } else { startUpdate(); } } break; case State::UP_TO_DATE: case State::UPDATING: _waitToUpdate = false; break; default: break; } }
void AssetsManagerEx::downloadManifest() { if (_updateState != State::PREDOWNLOAD_MANIFEST) return; std::string manifestUrl; if (_remoteManifest->isVersionLoaded()) { manifestUrl = _remoteManifest->getManifestFileUrl(); } else { manifestUrl = _localManifest->getManifestFileUrl(); } if (manifestUrl.size() > 0) { _updateState = State::DOWNLOADING_MANIFEST; // Download version file asynchronously _downloader->createDownloadFileTask(manifestUrl, _tempManifestPath, MANIFEST_ID); } // No manifest file found else { CCLOG("AssetsManagerEx : No manifest file found, check update failed\n"); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST); _updateState = State::UNCHECKED; } }
void AssetsManager::loadLocalManifest(const std::string& manifestUrl) { // Prefer to use the cached manifest file, if not found use user configured manifest file if (_fileUtils->isFileExist(_cacheManifestPath)) { _localManifest->parse(_cacheManifestPath); if (_localManifest->isLoaded()) prepareLocalManifest(); else _fileUtils->removeFile(_cacheManifestPath); } // Fail to found or load cached manifest file if (!_localManifest->isLoaded()) { _localManifest->parse(_manifestUrl); if (_localManifest->isLoaded()) prepareLocalManifest(); } // Fail to load local manifest if (!_localManifest->isLoaded()) { CCLOG("AssetsManager : No local manifest file found error.\n"); dispatchUpdateEvent(EventAssetsManager::EventCode::ERROR_NO_LOCAL_MANIFEST); } }
void AssetsManagerEx::updateAssets(const DownloadUnits& assets) { if (!_inited){ CCLOG("AssetsManagerEx : Manifests uninited.\n"); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST); return; } if (_updateState != State::UPDATING && _localManifest->isLoaded() && _remoteManifest->isLoaded()) { _updateState = State::UPDATING; _downloadUnits.clear(); _downloadedSize.clear(); _percent = _percentByFile = _sizeCollected = _totalSize = 0; _totalWaitToDownload = _totalToDownload = (int)assets.size(); _nextSavePoint = 0; _totalEnabled = false; if (_totalToDownload > 0) { _downloadUnits = assets; this->batchDownload(); } else if (_totalToDownload == 0) { onDownloadUnitsFinished(); } } }
void AssetsManagerEx::checkUpdate() { if (_updateEntry != UpdateEntry::NONE) { CCLOGERROR("AssetsManagerEx::checkUpdate, updateEntry isn't NONE"); return; } if (!_inited){ CCLOG("AssetsManagerEx : Manifests uninited.\n"); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST); return; } if (!_localManifest->isLoaded()) { CCLOG("AssetsManagerEx : No local manifest file found error.\n"); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST); return; } _updateEntry = UpdateEntry::CHECK_UPDATE; switch (_updateState) { case State::UNCHECKED: case State::PREDOWNLOAD_VERSION: { downloadVersion(); } break; case State::UP_TO_DATE: { dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE); } break; case State::FAIL_TO_UPDATE: case State::NEED_UPDATE: { dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND); } break; default: break; } }
void ModuleMgr::onError(const ModuleDownloader::Error &error) { // Skip version error occured if (error.customId == MANIFEST_ID) { dispatchUpdateEvent(ModuleMgrEvent::EventCode::ERROR_DOWNLOAD_MANIFEST, error.customId, error.message, error.curle_code, error.curlm_code); } else { auto unitIt = _downloadUnits.find(error.customId); // Found unit and add it to failed units if (unitIt != _downloadUnits.end()) { ModuleDownloader::DownloadUnit unit = unitIt->second; _failedUnits.emplace(unit.customId, unit); } dispatchUpdateEvent(ModuleMgrEvent::EventCode::ERROR_UPDATING, error.customId, error.message, error.curle_code, error.curlm_code); } }
void AssetsManagerEx::parseVersion() { if (_updateState != State::VERSION_LOADED) return; _remoteManifest->parseVersion(_tempVersionPath); if (!_remoteManifest->isVersionLoaded()) { CCLOG("AssetsManagerEx : Fail to parse version file, step skipped\n"); _updateState = State::PREDOWNLOAD_MANIFEST; downloadManifest(); } else { if (_localManifest->versionGreater(_remoteManifest, _versionCompareHandle)) { _updateState = State::UP_TO_DATE; _fileUtils->removeDirectory(_tempStoragePath); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE); } else { _updateState = State::NEED_UPDATE; // Wait to update so continue the process if (_updateEntry == UpdateEntry::DO_UPDATE) { // dispatch after checking update entry because event dispatching may modify the update entry dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND); _updateState = State::PREDOWNLOAD_MANIFEST; downloadManifest(); } else { dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND); } } } }
void ModuleMgr::updateSucceed() { // Every thing is correctly downloaded, do the following // 1. rename temporary manifest to valid manifest _fileUtils->renameFile(_storagePath, TEMP_MANIFEST_FILENAME, MANIFEST_FILENAME); // 4. decompress all compressed files decompressDownloadedZip(); // 5. Set update state _updateState = State::UP_TO_DATE; // 6. Notify finished event dispatchUpdateEvent(ModuleMgrEvent::EventCode::UPDATE_FINISHED); }
void ModuleMgr::decompressDownloadedZip() { // Decompress all compressed files for (auto it = _compressedFiles.begin(); it != _compressedFiles.end(); ++it) { std::string zipfile = *it; if (!decompress(zipfile)) { dispatchUpdateEvent(ModuleMgrEvent::EventCode::ERROR_DECOMPRESS, "", "Unable to decompress file " + zipfile); } _fileUtils->removeFile(zipfile); } _compressedFiles.clear(); }
void AssetsManagerEx::updateSucceed() { // Every thing is correctly downloaded, do the following // 1. rename temporary manifest to valid manifest std::string tempFileName = TEMP_MANIFEST_FILENAME; std::string fileName = MANIFEST_FILENAME; _fileUtils->renameFile(_tempStoragePath, tempFileName, fileName); // 2. merge temporary storage path to storage path so that temporary version turns to cached version if (_fileUtils->isDirectoryExist(_tempStoragePath)) { // Merging all files in temp storage path to storage path std::vector<std::string> files; _fileUtils->listFilesRecursively(_tempStoragePath, &files); int baseOffset = (int)_tempStoragePath.length(); std::string relativePath, dstPath; for (std::vector<std::string>::iterator it = files.begin(); it != files.end(); ++it) { relativePath.assign((*it).substr(baseOffset)); dstPath.assign(_storagePath + relativePath); // Create directory if (relativePath.back() == '/') { _fileUtils->createDirectory(dstPath); } // Copy file else { if (_fileUtils->isFileExist(dstPath)) { _fileUtils->removeFile(dstPath); } _fileUtils->renameFile(*it, dstPath); } } // Remove temp storage path _fileUtils->removeDirectory(_tempStoragePath); } // 3. swap the localManifest CC_SAFE_RELEASE(_localManifest); _localManifest = _remoteManifest; _localManifest->setManifestRoot(_storagePath); _remoteManifest = nullptr; // 4. make local manifest take effect prepareLocalManifest(); // 5. Set update state _updateState = State::UP_TO_DATE; // 6. Notify finished event dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FINISHED); }
void AssetsManagerEx::onDownloadUnitsFinished() { // Finished with error check if (_failedUnits.size() > 0) { // Save current download manifest information for resuming _tempManifest->saveToFile(_tempManifestPath); _updateState = State::FAIL_TO_UPDATE; dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FAILED); } else if (_updateState == State::UPDATING) { updateSucceed(); } }
void AssetsManagerEx::fileError(const std::string& identifier, const std::string& errorStr, int errorCode, int errorCodeInternal) { auto unitIt = _downloadUnits.find(identifier); // Found unit and add it to failed units if (unitIt != _downloadUnits.end()) { _totalWaitToDownload--; DownloadUnit unit = unitIt->second; _failedUnits.emplace(unit.customId, unit); } dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_UPDATING, identifier, errorStr, errorCode, errorCodeInternal); _tempManifest->setAssetDownloadState(identifier, Manifest::DownloadState::UNSTARTED); _currConcurrentTask = MAX(0, _currConcurrentTask-1); queueDowload(); }
void AssetsManager::updateSucceed() { // Every thing is correctly downloaded, do the following // 1. rename temporary manifest to valid manifest _fileUtils->renameFile(_storagePath, TEMP_MANIFEST_FILENAME, MANIFEST_FILENAME); // 2. swap the localManifest if (_localManifest != nullptr) _localManifest->release(); _localManifest = _remoteManifest; _remoteManifest = nullptr; // 3. make local manifest take effect prepareLocalManifest(); // 4. decompress all compressed files decompressDownloadedZip(); // 5. Set update state _updateState = State::UP_TO_DATE; // 6. Notify finished event dispatchUpdateEvent(EventAssetsManager::EventCode::UPDATE_FINISHED); }
void ModuleMgr::downloadManifest() { if (_updateState != State::PREDOWNLOAD_MANIFEST) { return; } if (_remoteManifestUrl.size() > 0) { _updateState = State::DOWNLOADING_MANIFEST; // Download version file asynchronously _downloader->downloadAsync(_remoteManifestUrl, _remoteManifestPath, MANIFEST_ID); } // No manifest file found else { CCLOG("ModuleMgr : No manifest file found, check update failed\n"); dispatchUpdateEvent(ModuleMgrEvent::EventCode::ERROR_DOWNLOAD_MANIFEST); _updateState = State::UNCHECKED; } }
void ModuleMgr::parseManifest() { if (_updateState != State::MANIFEST_LOADED) return; _remoteManifest->parse(_remoteManifestPath); if (!_remoteManifest->isLoaded()) { CCLOG("ModuleMgr : Error parsing manifest file\n"); dispatchUpdateEvent(ModuleMgrEvent::EventCode::ERROR_PARSE_MANIFEST); _updateState = State::UNCHECKED; } else { // _updateState = State::NEED_UPDATE; // dispatchUpdateEvent(ModuleMgrEvent::EventCode::NEW_VERSION_FOUND); startUpdate(); } }
void AssetsManagerEx::decompressDownloadedZip(const std::string &customId, const std::string &storagePath) { struct AsyncData { std::string customId; std::string zipFile; bool succeed; }; AsyncData* asyncData = new AsyncData; asyncData->customId = customId; asyncData->zipFile = storagePath; asyncData->succeed = false; std::function<void(void*)> decompressFinished = [this](void* param) { auto dataInner = reinterpret_cast<AsyncData*>(param); if (dataInner->succeed) { fileSuccess(dataInner->customId, dataInner->zipFile); } else { std::string errorMsg = "Unable to decompress file " + dataInner->zipFile; // Ensure zip file deletion (if decompress failure cause task thread exit anormally) _fileUtils->removeFile(dataInner->zipFile); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS, "", errorMsg); fileError(dataInner->customId, errorMsg); } delete dataInner; }; AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_OTHER, std::move(decompressFinished), (void*)asyncData, [this, asyncData]() { // Decompress all compressed files if (decompress(asyncData->zipFile)) { asyncData->succeed = true; } _fileUtils->removeFile(asyncData->zipFile); }); }
void AssetsManagerEx::onError(const network::DownloadTask& task, int errorCode, int errorCodeInternal, const std::string& errorStr) { // Skip version error occurred if (task.identifier == VERSION_ID) { CCLOG("AssetsManagerEx : Fail to download version file, step skipped\n"); _updateState = State::PREDOWNLOAD_MANIFEST; downloadManifest(); } else if (task.identifier == MANIFEST_ID) { dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST, task.identifier, errorStr, errorCode, errorCodeInternal); _updateState = State::FAIL_TO_UPDATE; } else { fileError(task.identifier, errorStr, errorCode, errorCodeInternal); } }
void ModuleMgr::onSuccess(const std::string &srcUrl, const std::string &storagePath, const std::string &customId) { CCLOG("ModuleMgr::onSuccess: %s %s", customId.c_str(), storagePath.c_str()); if (customId == MANIFEST_ID) { _updateState = State::MANIFEST_LOADED; parseManifest(); } else if (customId == BATCH_UPDATE_ID) { // Finished with error check if (_failedUnits.size() > 0 || _totalWaitToDownload > 0) { // Save current download manifest information for resuming //_tempManifest->saveToFile(_tempManifestPath); decompressDownloadedZip(); _updateState = State::FAIL_TO_UPDATE; dispatchUpdateEvent(ModuleMgrEvent::EventCode::UPDATE_FAILED); } else { updateSucceed(); } } else { auto assets = _remoteManifest->getAssets(); auto assetIt = assets.find(customId); if (assetIt != assets.end()) { // Set download state to SUCCESSED _remoteManifest->setAssetDownloadState(customId, ModuleManifest::DownloadState::SUCCESSED); // Add file to need decompress list if (assetIt->second.compressed) { _compressedFiles.push_back(storagePath); } } auto unitIt = _downloadUnits.find(customId); if (unitIt != _downloadUnits.end()) { // Reduce count only when unit found in _downloadUnits _totalWaitToDownload--; _percentByFile = 100 * (float)(_totalToDownload - _totalWaitToDownload) / _totalToDownload; // Notify progression event dispatchUpdateEvent(ModuleMgrEvent::EventCode::UPDATE_PROGRESSION, ""); } // Notify asset updated event dispatchUpdateEvent(ModuleMgrEvent::EventCode::ASSET_UPDATED, customId); unitIt = _failedUnits.find(customId); // Found unit and delete it if (unitIt != _failedUnits.end()) { // Remove from failed units list _failedUnits.erase(unitIt); } } }
void AssetsManagerEx::loadLocalManifest(const std::string& /*manifestUrl*/) { Manifest *cachedManifest = nullptr; // Find the cached manifest file if (_fileUtils->isFileExist(_cacheManifestPath)) { cachedManifest = new (std::nothrow) Manifest(); if (cachedManifest) { cachedManifest->parse(_cacheManifestPath); if (!cachedManifest->isLoaded()) { _fileUtils->removeFile(_cacheManifestPath); CC_SAFE_RELEASE(cachedManifest); cachedManifest = nullptr; } } } // Ensure no search path of cached manifest is used to load this manifest std::vector<std::string> searchPaths = _fileUtils->getSearchPaths(); if (cachedManifest) { std::vector<std::string> cacheSearchPaths = cachedManifest->getSearchPaths(); std::vector<std::string> trimmedPaths = searchPaths; for (auto path : cacheSearchPaths) { const auto pos = std::find(trimmedPaths.begin(), trimmedPaths.end(), path); if (pos != trimmedPaths.end()) { trimmedPaths.erase(pos); } } _fileUtils->setSearchPaths(trimmedPaths); } // Load local manifest in app package _localManifest->parse(_manifestUrl); if (cachedManifest) { // Restore search paths _fileUtils->setSearchPaths(searchPaths); } if (_localManifest->isLoaded()) { // Compare with cached manifest to determine which one to use if (cachedManifest) { bool localNewer = _localManifest->versionGreater(cachedManifest, _versionCompareHandle); if (localNewer) { // Recreate storage, to empty the content _fileUtils->removeDirectory(_storagePath); _fileUtils->createDirectory(_storagePath); CC_SAFE_RELEASE(cachedManifest); } else { CC_SAFE_RELEASE(_localManifest); _localManifest = cachedManifest; } } prepareLocalManifest(); } // Fail to load local manifest if (!_localManifest->isLoaded()) { CCLOG("AssetsManagerEx : No local manifest file found error.\n"); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST); } }
void AssetsManagerEx::startUpdate() { if (_updateState != State::NEED_UPDATE) return; _updateState = State::UPDATING; // Clean up before update _failedUnits.clear(); _downloadUnits.clear(); _totalWaitToDownload = _totalToDownload = 0; _nextSavePoint = 0; _percent = _percentByFile = _sizeCollected = _totalSize = 0; _downloadedSize.clear(); _totalEnabled = false; // Temporary manifest exists, resuming previous download if (_tempManifest && _tempManifest->isLoaded() && _tempManifest->versionEquals(_remoteManifest)) { _tempManifest->saveToFile(_tempManifestPath); _tempManifest->genResumeAssetsList(&_downloadUnits); _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size(); this->batchDownload(); std::string msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg); } else { // Temporary manifest exists, but can't be parsed or version doesn't equals remote manifest (out of date) if (_tempManifest) { // Remove all temp files _fileUtils->removeDirectory(_tempStoragePath); CC_SAFE_RELEASE(_tempManifest); // Recreate temp storage path and save remote manifest _fileUtils->createDirectory(_tempStoragePath); _remoteManifest->saveToFile(_tempManifestPath); } // Temporary manifest will be used to register the download states of each asset, // in this case, it equals remote manifest. _tempManifest = _remoteManifest; // Check difference between local manifest and remote manifest std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest); if (diff_map.size() == 0) { updateSucceed(); } else { // Generate download units for all assets that need to be updated or added std::string packageUrl = _remoteManifest->getPackageUrl(); // Save current download manifest information for resuming _tempManifest->saveToFile(_tempManifestPath); // Preprocessing local files in previous version and creating download folders for (auto it = diff_map.begin(); it != diff_map.end(); ++it) { Manifest::AssetDiff diff = it->second; if (diff.type != Manifest::DiffType::DELETED) { std::string path = diff.asset.path; DownloadUnit unit; unit.customId = it->first; unit.srcUrl = packageUrl + path; unit.storagePath = _tempStoragePath + path; unit.size = diff.asset.size; _downloadUnits.emplace(unit.customId, unit); _tempManifest->setAssetDownloadState(it->first, Manifest::DownloadState::UNSTARTED); } } _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size(); this->batchDownload(); std::string msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg); } } }
void ModuleMgr::startUpdate() { // Clean up before update _failedUnits.clear(); _downloadUnits.clear(); _compressedFiles.clear(); _totalWaitToDownload = _totalToDownload = 0; _percent = _percentByFile = _sizeCollected = _totalSize = 0; _downloadedSize.clear(); _totalEnabled = false; std::unordered_map<std::string, ModuleManifest::AssetDiff> diff_map = _remoteManifest->genDiff(); if (diff_map.size() == 0) { _updateState = State::UP_TO_DATE; // Rename temporary manifest to valid manifest _fileUtils->removeFile(_remoteManifestPath); dispatchUpdateEvent(ModuleMgrEvent::EventCode::ALREADY_UP_TO_DATE); } else { if (false == _waitToUpdate) { _updateState = State::NEED_UPDATE; dispatchUpdateEvent(ModuleMgrEvent::EventCode::NEW_VERSION_FOUND); return; } _updateState = State::UPDATING; // Generate download units for all assets that need to be updated or added std::string packageUrl = _remoteManifest->getPackageUrl(); for (auto it = diff_map.begin(); it != diff_map.end(); ++it) { ModuleManifest::AssetDiff diff = it->second; if (diff.type == ModuleManifest::DiffType::DELETED) { _fileUtils->removeFile(_storagePath + diff.asset.path); } else { std::string path = diff.asset.path; // Create path _fileUtils->createDirectory(basename(_storagePath + path)); ModuleDownloader::DownloadUnit unit; unit.customId = it->first; unit.srcUrl = packageUrl + path; unit.storagePath = _storagePath + path; unit.resumeDownload = false; _downloadUnits.emplace(unit.customId, unit); } } // Set other assets' downloadState to SUCCESSED auto assets = _remoteManifest->getAssets(); for (auto it = assets.cbegin(); it != assets.cend(); ++it) { const std::string &key = it->first; auto diffIt = diff_map.find(key); if (diffIt == diff_map.end()) { _remoteManifest->setAssetDownloadState(key, ModuleManifest::DownloadState::SUCCESSED); } } _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size(); _downloader->batchDownloadAsync(_downloadUnits, BATCH_UPDATE_ID); std::string msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload); dispatchUpdateEvent(ModuleMgrEvent::EventCode::UPDATE_PROGRESSION, "", msg); } _waitToUpdate = false; }
void AssetsManagerEx::update() { if (_updateEntry != UpdateEntry::NONE) { CCLOGERROR("AssetsManagerEx::update, updateEntry isn't NONE"); return; } if (!_inited){ CCLOG("AssetsManagerEx : Manifests uninited.\n"); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST); return; } if (!_localManifest->isLoaded()) { CCLOG("AssetsManagerEx : No local manifest file found error.\n"); dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST); return; } _updateEntry = UpdateEntry::DO_UPDATE; switch (_updateState) { case State::UNCHECKED: { _updateState = State::PREDOWNLOAD_VERSION; } case State::PREDOWNLOAD_VERSION: { downloadVersion(); } break; case State::VERSION_LOADED: { parseVersion(); } break; case State::PREDOWNLOAD_MANIFEST: { downloadManifest(); } break; case State::MANIFEST_LOADED: { parseManifest(); } break; case State::FAIL_TO_UPDATE: case State::NEED_UPDATE: { // Manifest not loaded yet if (!_remoteManifest->isLoaded()) { _updateState = State::PREDOWNLOAD_MANIFEST; downloadManifest(); } else { startUpdate(); } } break; case State::UP_TO_DATE: case State::UPDATING: case State::UNZIPPING: _updateEntry = UpdateEntry::NONE; break; default: break; } }
void AssetsManager::startUpdate() { if (_updateState != State::NEED_UPDATE) return; _updateState = State::UPDATING; // Clean up before update _failedUnits.clear(); _downloadUnits.clear(); _compressedFiles.clear(); _totalWaitToDownload = _totalToDownload = 0; _percent = _percentByFile = _sizeCollected = _totalSize = 0; _downloadedSize.clear(); _totalEnabled = false; // Temporary manifest exists, resuming previous download if (_tempManifest->isLoaded() && _tempManifest->versionEquals(_remoteManifest)) { _tempManifest->genResumeAssetsList(&_downloadUnits); _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size(); _downloader->batchDownloadAsync(_downloadUnits, BATCH_UPDATE_ID); std::string msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload); dispatchUpdateEvent(EventAssetsManager::EventCode::UPDATE_PROGRESSION, "", msg); } // Check difference else { // Temporary manifest not exists, // it will be used to register the download states of each asset, // in this case, it equals remote manifest. if(!_tempManifest->isLoaded()) { _tempManifest->release(); _tempManifest = _remoteManifest; } std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest); if (diff_map.size() == 0) { _updateState = State::UP_TO_DATE; // Rename temporary manifest to valid manifest _fileUtils->renameFile(_storagePath, TEMP_MANIFEST_FILENAME, MANIFEST_FILENAME); dispatchUpdateEvent(EventAssetsManager::EventCode::ALREADY_UP_TO_DATE); } else { // Generate download units for all assets that need to be updated or added std::string packageUrl = _remoteManifest->getPackageUrl(); for (auto it = diff_map.begin(); it != diff_map.end(); ++it) { Manifest::AssetDiff diff = it->second; if (diff.type == Manifest::DiffType::DELETED) { _fileUtils->removeFile(_storagePath + diff.asset.path); } else { std::string path = diff.asset.path; // Create path _fileUtils->createDirectories(basename(_storagePath + path)); Downloader::DownloadUnit unit; unit.customId = it->first; unit.srcUrl = packageUrl + path; unit.storagePath = _storagePath + path; unit.resumeDownload = false; _downloadUnits.emplace(unit.customId, unit); } } // Set other assets' downloadState to SUCCESSED auto assets = _remoteManifest->getAssets(); for (auto it = assets.cbegin(); it != assets.cend(); ++it) { const std::string &key = it->first; auto diffIt = diff_map.find(key); if (diffIt == diff_map.end()) { _tempManifest->setAssetDownloadState(key, Manifest::DownloadState::SUCCESSED); } } _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size(); _downloader->batchDownloadAsync(_downloadUnits, BATCH_UPDATE_ID); std::string msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload); dispatchUpdateEvent(EventAssetsManager::EventCode::UPDATE_PROGRESSION, "", msg); } } _waitToUpdate = false; }