HEAD request for check traffic update

This commit is contained in:
Sergey Yershov 2016-12-07 17:38:47 +03:00
parent fc8189106a
commit d67c82407e
6 changed files with 115 additions and 41 deletions

View file

@ -227,9 +227,13 @@ void TrafficManager::ThreadRoutine()
{
for (auto const & mwm : mwms)
{
auto const & mwmInfo = mwm.GetInfo();
if (!mwmInfo)
continue;
traffic::TrafficInfo info(mwm, m_currentDataVersion);
if (info.ReceiveTrafficData())
if (info.ReceiveTrafficData(m_trafficETags[mwm]))
{
OnTrafficDataResponse(move(info));
}

View file

@ -20,6 +20,7 @@
#include "std/map.hpp"
#include "std/mutex.hpp"
#include "std/set.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"
namespace df
@ -141,6 +142,10 @@ private:
vector<MwmSet::MwmId> m_lastMwmsByRect;
set<MwmSet::MwmId> m_activeMwms;
// The ETag or entity tag is part of HTTP, the protocol for the World Wide Web.
// It is one of several mechanisms that HTTP provides for web cache validation,
// which allows a client to make conditional requests.
map<MwmSet::MwmId, string> m_trafficETags;
vector<MwmSet::MwmId> m_requestedMwms;
mutex m_mutex;

View file

@ -75,6 +75,8 @@ string MakeRemoteURL(string const & name, uint64_t version)
ss << UrlEncode(name) << TRAFFIC_FILE_EXTENSION;
return ss.str();
}
char const kETag[] = "Etag";
} // namespace
// TrafficInfo::RoadSegmentId -----------------------------------------------------------------
@ -133,10 +135,10 @@ void TrafficInfo::SetTrafficKeysForTesting(vector<RoadSegmentId> const & keys)
m_availability = Availability::IsAvailable;
}
bool TrafficInfo::ReceiveTrafficData()
bool TrafficInfo::ReceiveTrafficData(string & etag)
{
vector<SpeedGroup> values;
if (!ReceiveTrafficValues(values))
if (!ReceiveTrafficValues(etag, values))
return false;
return UpdateTrafficData(values);
@ -396,48 +398,28 @@ bool TrafficInfo::ReceiveTrafficKeys()
return true;
}
bool TrafficInfo::ReceiveTrafficValues(vector<SpeedGroup> & values)
bool TrafficInfo::ReceiveTrafficValues(string & etag, vector<SpeedGroup> & values)
{
auto const & info = m_mwmId.GetInfo();
if (!info)
return false;
string const url = MakeRemoteURL(info->GetCountryName(), info->GetVersion());
uint64_t const version = info->GetVersion();
string const url = MakeRemoteURL(info->GetCountryName(), version);
if (url.empty())
return false;
vector<uint8_t> contents;
int errorCode;
if (!ReadRemoteFile(url, contents, errorCode))
{
if (errorCode == 404)
{
string const result(reinterpret_cast<char*>(contents.data()), contents.size());
int64_t version = 0;
strings::to_int64(result.c_str(), version);
if (version > info->GetVersion() && version <= m_currentDataVersion)
m_availability = Availability::ExpiredData;
else if (version > m_currentDataVersion)
m_availability = Availability::ExpiredApp;
else
m_availability = Availability::NoData;
}
else
{
m_availability = Availability::Unknown;
alohalytics::LogEvent(
"$TrafficNetworkError",
alohalytics::TStringMap({{"code", strings::to_string(errorCode)}}));
}
return false;
}
platform::HttpClient request(url);
request.LoadHeaders(true);
request.SetRawHeader("If-None-Match", etag);
if (!request.RunHttpRequest() || request.ErrorCode() != 200)
return ProcessFailure(request, version);
try
{
string const & response = request.ServerResponse();
vector<uint8_t> contents(response.cbegin(), response.cend());
DeserializeTrafficValues(contents, values);
}
catch (Reader::Exception const & e)
@ -453,6 +435,12 @@ bool TrafficInfo::ReceiveTrafficValues(vector<SpeedGroup> & values)
return false;
}
// Update ETag for this MWM.
auto const & headers = request.GetHeaders();
auto const it = headers.find(kETag);
if (it != headers.end())
etag = it->second;
m_availability = Availability::IsAvailable;
return true;
}
@ -480,13 +468,45 @@ bool TrafficInfo::UpdateTrafficData(vector<SpeedGroup> const & values)
return true;
}
bool TrafficInfo::ProcessFailure(platform::HttpClient const & request, uint64_t const mwmVersion)
{
switch (request.ErrorCode())
{
case 404: /* Not Found */
{
int64_t version = 0;
strings::to_int64(request.ServerResponse().c_str(), version);
if (version > mwmVersion && version <= m_currentDataVersion)
m_availability = Availability::ExpiredData;
else if (version > m_currentDataVersion)
m_availability = Availability::ExpiredApp;
else
m_availability = Availability::NoData;
return false;
}
case 304: /* Not Modified */
{
m_availability = Availability::IsAvailable;
return true;
}
}
m_availability = Availability::Unknown;
alohalytics::LogEvent(
"$TrafficNetworkError",
alohalytics::TStringMap({{"code", strings::to_string(request.ErrorCode())}}));
return false;
}
string DebugPrint(TrafficInfo::RoadSegmentId const & id)
{
string const dir =
id.m_dir == TrafficInfo::RoadSegmentId::kForwardDirection ? "Forward" : "Backward";
id.m_dir == TrafficInfo::RoadSegmentId::kForwardDirection ? "Forward" : "Backward";
ostringstream oss;
oss << "RoadSegmentId ["
<< " fid = " << id.m_fid << " idx = " << id.m_idx << " dir = " << dir << " ]";
<< " fid = " << id.m_fid << " idx = " << id.m_idx << " dir = " << dir << " ]";
return oss.str();
}
} // namespace traffic

View file

@ -9,6 +9,11 @@
#include "std/shared_ptr.hpp"
#include "std/vector.hpp"
namespace platform
{
class HttpClient;
}
namespace traffic
{
// This class is responsible for providing the real-time
@ -74,10 +79,13 @@ public:
static TrafficInfo BuildForTesting(Coloring && coloring);
void SetTrafficKeysForTesting(vector<RoadSegmentId> const & keys);
// Fetches the latest traffic data from the server and updates the coloring.
// Fetches the latest traffic data from the server and updates the coloring and ETag.
// Construct the url by passing an MwmId.
// The ETag or entity tag is part of HTTP, the protocol for the World Wide Web.
// It is one of several mechanisms that HTTP provides for web cache validation,
// which allows a client to make conditional requests.
// *NOTE* This method must not be called on the UI thread.
bool ReceiveTrafficData();
bool ReceiveTrafficData(string & etag);
// Returns the latest known speed group by a feature segment's id
// or SpeedGroup::Unknown if there is no information about the segment.
@ -119,11 +127,13 @@ private:
// Returns true and updates m_coloring if the values are read successfully and
// their number is equal to the number of keys.
// Otherwise, returns false and does not change m_coloring.
bool ReceiveTrafficValues(vector<SpeedGroup> & values);
bool ReceiveTrafficValues(string & etag, vector<SpeedGroup> & values);
// Updates the coloring and changes the availability status if needed.
bool UpdateTrafficData(vector<SpeedGroup> const & values);
bool ProcessFailure(platform::HttpClient const & request, uint64_t const mwmVersion);
// The mapping from feature segments to speed groups (see speed_groups.hpp).
Coloring m_coloring;

View file

@ -44,21 +44,24 @@ UNIT_TEST(TrafficInfo_RemoteFile)
auto const & r =
mwmSet.Register(platform::LocalCountryFile::MakeForTesting("traffic_data_test"));
TrafficInfo trafficInfo(r.first, r.first.GetInfo()->GetVersion());
TEST(trafficInfo.ReceiveTrafficData(), ());
string etag;
TEST(trafficInfo.ReceiveTrafficData(etag), ());
}
{
TestMwmSet mwmSet;
auto const & r =
mwmSet.Register(platform::LocalCountryFile::MakeForTesting("traffic_data_test2"));
TrafficInfo trafficInfo(r.first, r.first.GetInfo()->GetVersion());
TEST(!trafficInfo.ReceiveTrafficData(), ());
string etag;
TEST(!trafficInfo.ReceiveTrafficData(etag), ());
}
{
TestMwmSet mwmSet;
auto const & r =
mwmSet.Register(platform::LocalCountryFile::MakeForTesting("traffic_data_test", 101010));
TrafficInfo trafficInfo(r.first, r.first.GetInfo()->GetVersion());
TEST(trafficInfo.ReceiveTrafficData(), ());
string etag;
TEST(trafficInfo.ReceiveTrafficData(etag), ());
}
}

View file

@ -12,6 +12,14 @@
672292AB1DE2F673005BA3A7 /* libalohalitics.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 672292AA1DE2F673005BA3A7 /* libalohalitics.a */; };
672292AD1DE2F683005BA3A7 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 672292AC1DE2F683005BA3A7 /* libz.tbd */; };
672292AF1DE2FF0F005BA3A7 /* libindexer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 672292AE1DE2FF0F005BA3A7 /* libindexer.a */; };
674231CD1DFAB03800913FEB /* libgeometry.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231CC1DFAB03800913FEB /* libgeometry.a */; };
674231D31DFAB04C00913FEB /* libeditor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231CE1DFAB04C00913FEB /* libeditor.a */; };
674231D41DFAB04C00913FEB /* liboauthcpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231CF1DFAB04C00913FEB /* liboauthcpp.a */; };
674231D51DFAB04C00913FEB /* libopening_hours.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231D01DFAB04C00913FEB /* libopening_hours.a */; };
674231D61DFAB04C00913FEB /* libprotobuf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231D11DFAB04C00913FEB /* libprotobuf.a */; };
674231D71DFAB04C00913FEB /* libpugixml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231D21DFAB04C00913FEB /* libpugixml.a */; };
674231D91DFAB06100913FEB /* libjansson.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231D81DFAB06100913FEB /* libjansson.a */; };
674231DB1DFAB08C00913FEB /* librouting.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 674231DA1DFAB08C00913FEB /* librouting.a */; };
67BECB5F1DDA44FD00FC4E99 /* speed_groups.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67BECB5B1DDA44FD00FC4E99 /* speed_groups.cpp */; };
67BECB601DDA44FD00FC4E99 /* speed_groups.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 67BECB5C1DDA44FD00FC4E99 /* speed_groups.hpp */; };
67BECB611DDA44FD00FC4E99 /* traffic_info.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67BECB5D1DDA44FD00FC4E99 /* traffic_info.cpp */; };
@ -30,6 +38,14 @@
672292AA1DE2F673005BA3A7 /* libalohalitics.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libalohalitics.a; path = "../../../omim-build/xcode/Debug/libalohalitics.a"; sourceTree = "<group>"; };
672292AC1DE2F683005BA3A7 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
672292AE1DE2FF0F005BA3A7 /* libindexer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libindexer.a; path = "../../../omim-build/xcode/Debug/libindexer.a"; sourceTree = "<group>"; };
674231CC1DFAB03800913FEB /* libgeometry.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgeometry.a; path = "../../../omim-build/xcode/Debug/libgeometry.a"; sourceTree = "<group>"; };
674231CE1DFAB04C00913FEB /* libeditor.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libeditor.a; path = "../../../omim-build/xcode/Debug/libeditor.a"; sourceTree = "<group>"; };
674231CF1DFAB04C00913FEB /* liboauthcpp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liboauthcpp.a; path = "../../../omim-build/xcode/Debug/liboauthcpp.a"; sourceTree = "<group>"; };
674231D01DFAB04C00913FEB /* libopening_hours.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopening_hours.a; path = "../../../omim-build/xcode/Debug/libopening_hours.a"; sourceTree = "<group>"; };
674231D11DFAB04C00913FEB /* libprotobuf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libprotobuf.a; path = "../../../omim-build/xcode/Debug/libprotobuf.a"; sourceTree = "<group>"; };
674231D21DFAB04C00913FEB /* libpugixml.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpugixml.a; path = "../../../omim-build/xcode/Debug/libpugixml.a"; sourceTree = "<group>"; };
674231D81DFAB06100913FEB /* libjansson.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libjansson.a; path = "../../../omim-build/xcode/Debug/libjansson.a"; sourceTree = "<group>"; };
674231DA1DFAB08C00913FEB /* librouting.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = librouting.a; path = "../../../omim-build/xcode/Debug/librouting.a"; sourceTree = "<group>"; };
67BECB4A1DDA43AF00FC4E99 /* libtraffic.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtraffic.a; sourceTree = BUILT_PRODUCTS_DIR; };
67BECB581DDA43FB00FC4E99 /* common-debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-debug.xcconfig"; path = "../common-debug.xcconfig"; sourceTree = "<group>"; };
67BECB591DDA440100FC4E99 /* common-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-release.xcconfig"; path = "../common-release.xcconfig"; sourceTree = "<group>"; };
@ -58,6 +74,14 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
674231DB1DFAB08C00913FEB /* librouting.a in Frameworks */,
674231D91DFAB06100913FEB /* libjansson.a in Frameworks */,
674231D31DFAB04C00913FEB /* libeditor.a in Frameworks */,
674231D41DFAB04C00913FEB /* liboauthcpp.a in Frameworks */,
674231D51DFAB04C00913FEB /* libopening_hours.a in Frameworks */,
674231D61DFAB04C00913FEB /* libprotobuf.a in Frameworks */,
674231D71DFAB04C00913FEB /* libpugixml.a in Frameworks */,
674231CD1DFAB03800913FEB /* libgeometry.a in Frameworks */,
672292AF1DE2FF0F005BA3A7 /* libindexer.a in Frameworks */,
672292AD1DE2F683005BA3A7 /* libz.tbd in Frameworks */,
672292AB1DE2F673005BA3A7 /* libalohalitics.a in Frameworks */,
@ -120,6 +144,14 @@
67BECB831DDA474400FC4E99 /* Frameworks */ = {
isa = PBXGroup;
children = (
674231DA1DFAB08C00913FEB /* librouting.a */,
674231D81DFAB06100913FEB /* libjansson.a */,
674231CE1DFAB04C00913FEB /* libeditor.a */,
674231CF1DFAB04C00913FEB /* liboauthcpp.a */,
674231D01DFAB04C00913FEB /* libopening_hours.a */,
674231D11DFAB04C00913FEB /* libprotobuf.a */,
674231D21DFAB04C00913FEB /* libpugixml.a */,
674231CC1DFAB03800913FEB /* libgeometry.a */,
672292AE1DE2FF0F005BA3A7 /* libindexer.a */,
672292AC1DE2F683005BA3A7 /* libz.tbd */,
672292AA1DE2F673005BA3A7 /* libalohalitics.a */,