forked from organicmaps/organicmaps
Added processing of failures in local ads campaigns downloading
This commit is contained in:
parent
075d39e705
commit
bf54144093
2 changed files with 101 additions and 34 deletions
|
@ -37,6 +37,9 @@ std::string const kCampaignPageUrl = LOCAL_ADS_COMPANY_PAGE_URL;
|
|||
std::string const kCampaignFile = "local_ads_campaigns.dat";
|
||||
std::string const kLocalAdsSymbolsFile = "local_ads_symbols.txt";
|
||||
auto constexpr kWWanUpdateTimeout = std::chrono::hours(12);
|
||||
uint8_t constexpr kRequestMinZoomLevel = 12;
|
||||
auto constexpr kFailedDownloadingTimeout = std::chrono::seconds(2);
|
||||
auto constexpr kMaxDownloadingAttempts = 5;
|
||||
|
||||
void SerializeCampaign(FileWriter & writer, std::string const & countryName,
|
||||
LocalAdsManager::Timestamp const & ts,
|
||||
|
@ -76,20 +79,6 @@ std::string MakeCampaignDownloadingURL(MwmSet::MwmId const & mwmId)
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DownloadCampaign(MwmSet::MwmId const & mwmId)
|
||||
{
|
||||
std::string const url = MakeCampaignDownloadingURL(mwmId);
|
||||
if (url.empty())
|
||||
return {};
|
||||
|
||||
platform::HttpClient request(url);
|
||||
if (!request.RunHttpRequest() || request.ErrorCode() != 200)
|
||||
return {};
|
||||
|
||||
string const & response = request.ServerResponse();
|
||||
return std::vector<uint8_t>(response.cbegin(), response.cend());
|
||||
}
|
||||
|
||||
df::CustomSymbols ParseCampaign(std::vector<uint8_t> const & rawData, MwmSet::MwmId const & mwmId,
|
||||
LocalAdsManager::Timestamp timestamp)
|
||||
{
|
||||
|
@ -225,7 +214,7 @@ void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
|
|||
{
|
||||
auto connectionStatus = GetPlatform().ConnectionStatus();
|
||||
if (kServerUrl.empty() || connectionStatus == Platform::EConnectionType::CONNECTION_NONE ||
|
||||
df::GetZoomLevel(screen.GetScale()) <= scales::GetUpperWorldScale())
|
||||
df::GetZoomLevel(screen.GetScale()) < kRequestMinZoomLevel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -246,6 +235,18 @@ void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
|
|||
auto info = mwm.GetInfo();
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
// Skip downloading request if maximum attempts count has reached or
|
||||
// we are waiting for new attempt.
|
||||
auto const failedDownloadsIt = m_failedDownloads.find(mwm);
|
||||
if (failedDownloadsIt != m_failedDownloads.cend() &&
|
||||
(failedDownloadsIt->second.m_attemptsCount >= kMaxDownloadingAttempts ||
|
||||
Now() <= failedDownloadsIt->second.m_lastDownloading +
|
||||
failedDownloadsIt->second.m_currentTimeout))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string const & mwmName = info->GetCountryName();
|
||||
auto campaignIt = m_campaigns.find(mwmName);
|
||||
if (campaignIt == m_campaigns.end())
|
||||
|
@ -276,6 +277,51 @@ void LocalAdsManager::UpdateViewport(ScreenBase const & screen)
|
|||
}
|
||||
}
|
||||
|
||||
bool LocalAdsManager::DownloadCampaign(MwmSet::MwmId const & mwmId, std::vector<uint8_t> & bytes)
|
||||
{
|
||||
bytes.clear();
|
||||
|
||||
std::string const url = MakeCampaignDownloadingURL(mwmId);
|
||||
if (url.empty())
|
||||
return true;
|
||||
|
||||
// Skip already downloaded campaigns. We do not lock whole method because RunHttpRequest
|
||||
// is a synchronous method and may take a lot of time. The case in which countryName will
|
||||
// be added to m_campaigns between locks is neglected.
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
auto const & countryName = mwmId.GetInfo()->GetCountryName();
|
||||
if (m_campaigns.find(countryName) != m_campaigns.cend())
|
||||
return false;
|
||||
}
|
||||
|
||||
platform::HttpClient request(url);
|
||||
bool const success = request.RunHttpRequest() && request.ErrorCode() == 200;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (!success)
|
||||
{
|
||||
auto const it = m_failedDownloads.find(mwmId);
|
||||
if (it == m_failedDownloads.cend())
|
||||
{
|
||||
m_failedDownloads.insert(std::make_pair(
|
||||
mwmId, BackoffStats(Now(), kFailedDownloadingTimeout, 1 /* m_attemptsCount */)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Here we increase timeout as power 2 function.
|
||||
it->second.m_currentTimeout = std::chrono::seconds(it->second.m_currentTimeout.count() << 1);
|
||||
it->second.m_attemptsCount++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
m_failedDownloads.erase(mwmId);
|
||||
auto const & response = request.ServerResponse();
|
||||
bytes.assign(response.cbegin(), response.cend());
|
||||
return true;
|
||||
}
|
||||
|
||||
void LocalAdsManager::ThreadRoutine()
|
||||
{
|
||||
local_ads::IconsInfo::Instance().SetSourceFile(kLocalAdsSymbolsFile);
|
||||
|
@ -299,25 +345,28 @@ void LocalAdsManager::ThreadRoutine()
|
|||
{
|
||||
// Download campaign data from server.
|
||||
CampaignInfo info;
|
||||
info.m_data = DownloadCampaign(mwm.first);
|
||||
if (info.m_data.empty())
|
||||
if (!DownloadCampaign(mwm.first, info.m_data))
|
||||
continue;
|
||||
info.m_created = Now();
|
||||
|
||||
// Parse data and send symbols to rendering.
|
||||
auto symbols = ParseCampaign(std::move(info.m_data), mwm.first, info.m_created);
|
||||
if (symbols.empty())
|
||||
// Parse data and send symbols to rendering (or delete from rendering).
|
||||
if (!info.m_data.empty())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_campaigns.erase(countryName);
|
||||
m_info.erase(countryName);
|
||||
DeleteSymbolsFromRendering(mwm.first);
|
||||
auto symbols = ParseCampaign(std::move(info.m_data), mwm.first, info.m_created);
|
||||
if (symbols.empty())
|
||||
{
|
||||
DeleteSymbolsFromRendering(mwm.first);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateFeaturesCache(symbols);
|
||||
SendSymbolsToRendering(std::move(symbols));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateFeaturesCache(symbols);
|
||||
SendSymbolsToRendering(std::move(symbols));
|
||||
DeleteSymbolsFromRendering(mwm.first);
|
||||
}
|
||||
info.m_created = Now();
|
||||
|
||||
// Update run-time data.
|
||||
{
|
||||
|
|
|
@ -82,6 +82,8 @@ private:
|
|||
|
||||
void FillSupportedTypes();
|
||||
|
||||
bool DownloadCampaign(MwmSet::MwmId const & mwmId, std::vector<uint8_t> & bytes);
|
||||
|
||||
GetMwmsByRectFn m_getMwmsByRectFn;
|
||||
GetMwmIdByName m_getMwmIdByNameFn;
|
||||
|
||||
|
@ -98,16 +100,32 @@ private:
|
|||
df::CustomSymbols m_symbolsCache;
|
||||
std::mutex m_symbolsCacheMutex;
|
||||
|
||||
std::set<FeatureID> m_featuresCache;
|
||||
mutable std::mutex m_featuresCacheMutex;
|
||||
|
||||
ftypes::HashSetMatcher<uint32_t> m_supportedTypes;
|
||||
|
||||
struct BackoffStats
|
||||
{
|
||||
BackoffStats() = default;
|
||||
BackoffStats(Timestamp lastDownloading, std::chrono::seconds currentTimeout,
|
||||
uint8_t attemptsCount)
|
||||
: m_lastDownloading(lastDownloading)
|
||||
, m_currentTimeout(currentTimeout)
|
||||
, m_attemptsCount(attemptsCount)
|
||||
{}
|
||||
|
||||
Timestamp m_lastDownloading = {};
|
||||
std::chrono::seconds m_currentTimeout = std::chrono::seconds(0);
|
||||
uint8_t m_attemptsCount = 0;
|
||||
};
|
||||
std::map<MwmSet::MwmId, BackoffStats> m_failedDownloads;
|
||||
|
||||
local_ads::Statistics m_statistics;
|
||||
|
||||
bool m_isRunning = false;
|
||||
std::condition_variable m_condition;
|
||||
std::set<Request> m_requestedCampaigns;
|
||||
std::mutex m_mutex;
|
||||
threads::SimpleThread m_thread;
|
||||
|
||||
local_ads::Statistics m_statistics;
|
||||
|
||||
std::set<FeatureID> m_featuresCache;
|
||||
mutable std::mutex m_featuresCacheMutex;
|
||||
|
||||
ftypes::HashSetMatcher<uint32_t> m_supportedTypes;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue