Exemple #1
0
static bool isVersionValid(const string& version, const string& base)
{
	GBVersion v = splitVersion(version);
	GBVersion b = splitVersion(base);

	if (v.version1 == b.version1)
	{
		if (v.version2 == b.version2)
			return v.version3 > b.version3;
		else
			return v.version2 > b.version2;
	}

	return false;
}
Exemple #2
0
GBUpdate::GBUpdate()
{
	_isUpdateEnabled = false;
	_isAutoUpdate = false;
	_remoteVersion = "";
	_localVersion = "";
	_localExternalVersion = "";
	
	_downloader.reset(new network::Downloader());
	_downloader->onFileTaskSuccess = [this](const DownloadTask& task) { onDownloadSuccess(task); };
	_downloader->onTaskError = [this](const DownloadTask& task, int errorCode, int errorCodeInternal, const std::string& errorStr) {onDownloadError(task, errorCode, errorCodeInternal, errorStr); };
	
	DIRECTOR()->getEventDispatcher()->addCustomEventListener(GBUPDATE_EVENT_UPDATE_START, [this](EventCustom * pEvent){
		for (map<string, GBUpdateInfo>::iterator it = _downloadList.begin(); it != _downloadList.end(); it++)
		{
			if (it->second.location.empty())
			{
				GBVersion version = splitVersion(_remoteVersion);
				_downloader->createDownloadFileTask(StringUtils::format("%s/%d.%d/%s", _updateUrl.c_str(), version.version1, version.version2, it->first.c_str()), GBUtils::getExternalPath(it->first), it->first);
				return;
			}
		}
		DIRECTOR()->getEventDispatcher()->dispatchCustomEvent(GBUPDATE_EVENT_UPDATE_FINISH, (void *)0);
	});

	DIRECTOR()->getEventDispatcher()->addCustomEventListener(GBUPDATE_EVENT_UPDATED_ONE, [this](EventCustom * pEvent){
		for (map<string, GBUpdateInfo>::iterator it = _downloadList.begin(); it != _downloadList.end(); it++)
		{
			if (it->second.location.empty())
			{
				GBVersion version = splitVersion(_remoteVersion);
				_downloader->createDownloadFileTask(StringUtils::format("%s/%d.%d/%s", _updateUrl.c_str(), version.version1, version.version2, it->first.c_str()), GBUtils::getExternalPath(it->first), it->first);
				return;
			}
		}
		DIRECTOR()->getEventDispatcher()->dispatchCustomEvent(GBUPDATE_EVENT_UPDATE_FINISH, (void *)1);
	});

	DIRECTOR()->getEventDispatcher()->addCustomEventListener(GBUPDATE_EVENT_UPDATE_FINISH, [this](EventCustom * pEvent){
		long isDownloadFinish = (long)pEvent->getUserData();
		if(isDownloadFinish) parseMD5();
	});
}
Exemple #3
0
void GBUpdate::requestRemoteVersion()
{
	GBVersion version = splitVersion(getLocalVersion());

	auto request = new (std::nothrow) HttpRequest();
	request->setUrl(StringUtils::format("%s/%d.%d/md5", _updateUrl.c_str(), version.version1, version.version2).c_str());
	request->setRequestType(HttpRequest::Type::GET);
	request->setResponseCallback(CC_CALLBACK_2(GBUpdate::onRequestVersionCompleted, this));
	HttpClient::getInstance()->sendImmediate(request);
	request->release();
}
Exemple #4
0
void GBUpdate::onRequestVersionCompleted(HttpClient *sender, HttpResponse *response)
{
	do 
	{
		if (!response)
			break;
		if (!response->isSucceed())
			break;
		vector<char> * pBuf = response->getResponseData();
		if (pBuf->size() > 0)
		{
			vector<vector<string>> v = GBCsv::parseCsv((unsigned char *)pBuf->data(), pBuf->size());
			_remoteVersion = v[0][0];
		}

		if (!_remoteVersion.empty())
		{
			string localVersion = getLocalVersion();
			if (_remoteVersion == localVersion)
			{
				if (getDownloadTotalSize() > MIN_DOWNLOAD_SIZE && !_isAutoUpdate)
				{
					DIRECTOR()->getEventDispatcher()->dispatchCustomEvent(GBUPDATE_EVENT_UPDATE_READY);
				}
				else
				{
					DIRECTOR()->getEventDispatcher()->dispatchCustomEvent(GBUPDATE_EVENT_UPDATE_START);
				}				
				return;
			}
			else if (isVersionValid(_remoteVersion, getLocalVersion()))
			{
				GBVersion version = splitVersion(_remoteVersion);
				string md5Url = StringUtils::format("%s/%d.%d/md5", _updateUrl.c_str(), version.version1, version.version2);				
				_downloader->createDownloadFileTask(md5Url, GBUtils::getExternalPath("md5"), "md5");
				return;
			}
		}
	} while (false);
	DIRECTOR()->getEventDispatcher()->dispatchCustomEvent(GBUPDATE_EVENT_UPDATE_FINISH, (void *)0);
}
			void DLCchecking::update(entityx::ptr<entityx::EntityManager> es, entityx::ptr<entityx::EventManager> events, double dt)
			{
				for (auto entity : es->entities_with_components<Comp::DataVerCheck>())
				{
					entityx::ptr<Comp::DataVerCheck> dllist = entity.component<Comp::DataVerCheck>();
					std::string url = dllist->m_url;

					if (!dllist->m_verlist.empty())
					{
						//we need to check if the version url is valid ( contains a manifest.json )
						url += "/" + dllist->m_verlist.back() + "/manifest.json";
						m_manifest = "";
						CCLOG("DLCchecking reading from %s", url.c_str());

						//list all files at given url
						CURLcode res;
						curl_easy_setopt(_curl, CURLOPT_URL, url.c_str());
#ifdef _DEBUG
						curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L);
#endif
						curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, write_data);
						curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &m_manifest);
						if (_connectionTimeout) curl_easy_setopt(_curl, CURLOPT_CONNECTTIMEOUT, _connectionTimeout);
						curl_easy_setopt(_curl, CURLOPT_NOSIGNAL, 1L);
						curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_LIMIT, LOW_SPEED_LIMIT);
						curl_easy_setopt(_curl, CURLOPT_LOW_SPEED_TIME, LOW_SPEED_TIME);
						res = curl_easy_perform(_curl);

						CCLOG("DLCchecking read from %s", url.c_str());

						if (res != 0)
						{

							CCLOG("DLCchecking can not read from %s, error code is %d", url.c_str(), res);

							dllist->m_retries--;
							if (0 == dllist->m_retries)
							{
								CCLOGERROR("DLCchecking can not read from %s, error code is %d", url.c_str(), res);
								//signal error
								events->emit<Events::Error>(entity, "DLCchecking system");
								//we give up on this entity
								entity.destroy();
							}
						}
						else
						{
							//read the downloaded manifest to compare md5
							rapidjson::Document json;
							json.Parse<0>(m_manifest.c_str());
							if (json.HasParseError()) {
								CCLOG("GetParseError %s\n", json.GetParseError());
								//version will be removed from the list later.
							}
							else
							{
								//is it possible to update ?
								bool dlc_update_allowed = false;

								//do we need to update ?
								bool dlc_update_required = false;

								std::string version = cocostudio::DictionaryHelper::getInstance()->getStringValue_json(json, "version", "");
								if (version == dllist->m_current_version) //if we have the exact same string : developer update or current version hotfix.
								{
									dlc_update_required = true;
								}
								else if (version.length() > 0 )  //we need to compare string to find if the online version is more recent
								{
									unsigned long lver = 0;
									try {
										lver = ToolBox::stoul(version);
										CCLOG("DLC at %s has Manifest version %lu", url.c_str(), lver);
									}
									catch (std::out_of_range oor)
									{
										lver = 0; //disabling update if online version is too high ( developer version )
									}

									unsigned long lcver = 0;
									try {
										lcver = ToolBox::stoul(dllist->m_current_version);
										CCLOG("Local DLC has Manifest version %lu", url.c_str(), lcver);
									}
									catch (std::out_of_range oor)
									{
										lcver = LONG_MAX; // if local version is too high, update should have been done before
									}

									if (lver > lcver) //not == to prevent LONG_MAX == LONG_MAX
									{
										dlc_update_required = true;
									}
								}

								std::string minAppVersion = cocostudio::DictionaryHelper::getInstance()->getStringValue_json(json, "minAppVersion", "error");
								if (minAppVersion != "error" && dllist->m_current_minAppVersion != "" )
								{
									//CAREFUL HERE with version comparison
									std::vector<unsigned long> mav = splitVersion(minAppVersion);
									std::vector<unsigned long> cmav = splitVersion(dllist->m_current_minAppVersion);

									dlc_update_allowed = true;
									while ( mav.size() < cmav.size() )
									{
										mav.push_back(0);
									}
									for (unsigned int i = 0; i < cmav.size(); ++i)
									{
										if (mav.at(i) > cmav.at(i))
										{
											dlc_update_allowed = false; break;
										}
									}
								}//if we cannot read the minimum app version. we dont download. better safe than sorry.

								if (dlc_update_allowed && dlc_update_required)
								{

									//prepare the list of downloads
									const rapidjson::Value & assets = cocostudio::DictionaryHelper::getInstance()->getSubDictionary_json(json, "assets");

									for (rapidjson::Value::ConstMemberIterator m = assets.MemberonBegin(); m != assets.MemberonEnd(); ++m)
									{
										std::string filename = m->name.GetString();
										std::string filehash = cocostudio::DictionaryHelper::getInstance()->getStringValue_json(m->value, "md5", "error");

										//lowering filehash to be sure
										std::transform(filehash.begin(), filehash.end(), filehash.begin(), ::tolower);

										//std::cout << filename << " : " << filehash << std::endl;

										entityx::Entity newentity = es->create();
										newentity.assign<Comp::LocalFile>(filename);
										newentity.assign<Comp::RemoteMD5>(filehash);
										newentity.assign<Comp::RemoteFile>(dllist->m_url + "/" + dllist->m_verlist.back(), filename);
										
										newentity.assign<Comp::ProgressValue>(1);
									}


									//downloading only the last verison should always be enough ( avoiding too many downloads - keeping all data for one version in same place )
									//if (dllist->m_verlist.empty()) //if we checked all versions
									//{
									entity.remove<Comp::DataVerCheck>();
									//}

									//we dont need to do anything more with this entity
									entity.destroy();
								}

							}

							//remove the version checked from the list
							dllist->m_verlist.pop_back();
							//In case of error, we should check the next version in stack on next update.
							//If success this will not be done ( entity destroyed )
							//TODO : check behavior

						}

						//exit this loop. one per update is enough
						break;
			
					}
					else //no version left to check
					{
						//we dont need to do anything more with this entity
						entity.destroy();
					}
				}
			};