[core] synchronous cross reference url calculation after booking

This commit is contained in:
Arsentiy Milchakov 2019-05-21 20:45:23 +03:00 committed by mpimenov
parent fa59cb2a6a
commit 7f550f91f8
8 changed files with 69 additions and 203 deletions

View file

@ -10,7 +10,7 @@ class DataSource;
namespace search
{
class CityFinder;
class CityFinder;
}
class CrossReferenceDelegate : public cross_reference::Api::Delegate

View file

@ -577,8 +577,9 @@ Framework::Framework(FrameworkParams const & params)
GetPowerManager().Subscribe(this);
GetPowerManager().Load();
m_crossReferenceApi->SetDelegate(make_unique<CrossReferenceDelegate>(m_model.GetDataSource(),
*m_cityFinder));
m_crossReferenceApi->SetDelegate(
make_unique<CrossReferenceDelegate>(m_model.GetDataSource(), *m_cityFinder));
eye::Eye::Instance().Subscribe(m_crossReferenceApi.get());
}
Framework::~Framework()

View file

@ -404,22 +404,23 @@ void Eye::RegisterMapObjectEvent(MapObject const & mapObject, MapObject::Event::
});
}
void Eye::RegisterCrossReferenceAfterBookingShown()
void Eye::RegisterCrossReferenceAfterBookingShown(std::string const & cityId)
{
auto const info = m_info.Get();
auto editableInfo = std::make_shared<Info>(*info);
auto const now = Clock::now();
editableInfo->m_crossReferences.m_lastTimeShownAfterBooking = now;
editableInfo->m_crossReferences.m_lastTimeShownAfterBookingCityId = cityId;
if (!Save(editableInfo))
return;
GetPlatform().RunTask(Platform::Thread::Gui, [this, now]
GetPlatform().RunTask(Platform::Thread::Gui, [this, now, cityId]
{
for (auto subscriber : m_subscribers)
{
subscriber->OnCrossReferenceAfterBookingShown(now);
subscriber->OnCrossReferenceAfterBookingShown(now, cityId);
}
});
}
@ -505,11 +506,11 @@ void Eye::Event::MapObjectEvent(MapObject const & mapObject, MapObject::Event::T
}
// static
void Eye::Event::CrossReferenceAfterBookingShown()
void Eye::Event::CrossReferenceAfterBookingShown(std::string const & cityId)
{
GetPlatform().RunTask(Platform::Thread::File, []
GetPlatform().RunTask(Platform::Thread::File, [cityId]
{
Instance().RegisterCrossReferenceAfterBookingShown();
Instance().RegisterCrossReferenceAfterBookingShown(cityId);
});
}
} // namespace eye

View file

@ -24,7 +24,7 @@ public:
virtual void OnDiscoveryItemClicked(Discovery::Event event) {}
virtual void OnLayerShown(Layer const & layer) {}
virtual void OnMapObjectEvent(MapObject const & poi) {}
virtual void OnCrossReferenceAfterBookingShown(Time const & time) {}
virtual void OnCrossReferenceAfterBookingShown(Time const & time, std::string const & cityId) {}
};
// Note This class IS thread-safe.
@ -48,7 +48,7 @@ public:
static void LayerShown(Layer::Type type);
static void MapObjectEvent(MapObject const & mapObject, MapObject::Event::Type type,
m2::PointD const & userPos);
static void CrossReferenceAfterBookingShown();
static void CrossReferenceAfterBookingShown(std::string const & cityId);
};
static Eye & Instance();
@ -77,7 +77,7 @@ private:
void RegisterLayerShown(Layer::Type type);
void RegisterMapObjectEvent(MapObject const & mapObject, MapObject::Event::Type type,
m2::PointD const & userPos);
void RegisterCrossReferenceAfterBookingShown();
void RegisterCrossReferenceAfterBookingShown(std::string const & cityId);
base::AtomicSharedPtr<Info> m_info;
std::vector<Subscriber *> m_subscribers;

View file

@ -267,6 +267,7 @@ struct CrossReferences
visitor(m_lastTimeShownAfterBooking, "lastTimeShownAfterBooking"))
Time m_transitionToBookingTime;
Time m_lastTimeShownAfterBooking;
std::string m_lastTimeShownAfterBookingCityId;
};
using MapObjects = m4::Tree<MapObject>;

View file

@ -143,9 +143,10 @@ void Api::SetDelegate(std::unique_ptr<Delegate> delegate)
void Api::OnEnterForeground()
{
settings::TryGet("BookingCrossReferenceIsAwaiting", m_bookingCrossReferenceIsAwaiting);
m_bookingCrossReferenceAwaitingForId.clear();
settings::TryGet("BookingCrossReferenceAwaitingForId", m_bookingCrossReferenceAwaitingForId);
if (!m_bookingCrossReferenceIsAwaiting)
if (m_bookingCrossReferenceAwaitingForId.empty())
return;
auto const eyeInfo = eye::Eye::Instance().GetInfo();
@ -155,74 +156,28 @@ void Api::OnEnterForeground()
if (timeSinceLastTransitionToBooking < kMinMinutesCountAfterBooking ||
timeSinceLastTransitionToBooking > kMaxMinutesCountAfterBooking)
{
m_bookingCrossReferenceIsAwaiting = false;
settings::Set("BookingCrossReferenceIsAwaiting", false);
settings::Delete("BookingCrossReferenceAwaitingForId");
m_bookingCrossReferenceAwaitingForId.clear();
}
}
bool Api::NeedToShow() const
{
if (!m_bookingCrossReferenceIsAwaiting)
if (m_bookingCrossReferenceAwaitingForId.empty())
return false;
return NeedToShowImpl(eye::Eye::Instance().GetInfo());
}
void Api::GetCrossReferenceLinkAfterBooking(AfterBookingCallback const & cb) const
std::string Api::GetCrossReferenceLinkAfterBooking() const
{
CHECK(m_delegate, ());
auto const eyeInfo = eye::Eye::Instance().GetInfo();
if (!m_bookingCrossReferenceIsAwaiting || !NeedToShowImpl(eyeInfo))
{
GetPlatform().RunTask(Platform::Thread::Gui, [cb]() { cb({}); });
return;
}
if (m_bookingCrossReferenceAwaitingForId.empty() || !NeedToShowImpl(eyeInfo))
return "";
GetPlatform().RunTask(Platform::Thread::Background, [this, eyeInfo, cb]()
{
auto const targetTime = eyeInfo->m_crossReferences.m_transitionToBookingTime;
m2::PointD pos;
auto const found =
eyeInfo->m_mapObjects.FindNode([&pos, targetTime](eye::MapObject const & mapObject)
{
if (mapObject.GetEvents().empty())
return false;
auto const typeIt = std::find(kSupportedBookingTypes.cbegin(),
kSupportedBookingTypes.cend(), mapObject.GetBestType());
if (typeIt == kSupportedBookingTypes.cend())
return false;
for (auto const & event : mapObject.GetEvents())
{
switch (event.m_type)
{
case eye::MapObject::Event::Type::BookingBook:
case eye::MapObject::Event::Type::BookingMore:
case eye::MapObject::Event::Type::BookingReviews:
case eye::MapObject::Event::Type::BookingDetails:
{
if (event.m_eventTime == targetTime)
{
pos = mapObject.GetPos();
return true;
}
}
default: continue;
}
}
return false;
});
auto const osmId = found ? m_delegate->GetCityOsmId(pos) : "";
auto const resultUrl =
osmId.empty() ? "" : MakeCityGalleryUrl(m_baseUrl, osmId, languages::GetCurrentNorm());
GetPlatform().RunTask(Platform::Thread::Gui, [cb, resultUrl]() { cb(resultUrl); });
});
return MakeCityGalleryUrl(m_baseUrl, m_bookingCrossReferenceAwaitingForId,
languages::GetCurrentNorm());
}
void Api::GetCrossReferenceCityGallery(std::string const & osmId,
@ -238,4 +193,35 @@ void Api::GetCrossReferenceCityGallery(m2::PointD const & point,
GetCrossReferenceCityGalleryImpl(m_baseUrl, m_delegate->GetCityOsmId(point), cb);
}
void Api::OnMapObjectEvent(eye::MapObject const & mapObject)
{
CHECK(!mapObject.GetEvents().empty(), ());
auto const typeIt = std::find(kSupportedBookingTypes.cbegin(), kSupportedBookingTypes.cend(),
mapObject.GetBestType());
if (typeIt == kSupportedBookingTypes.cend())
return;
m2::PointD pos;
bool found = false;
switch (mapObject.GetEvents().back().m_type)
{
case eye::MapObject::Event::Type::BookingBook:
case eye::MapObject::Event::Type::BookingMore:
case eye::MapObject::Event::Type::BookingReviews:
case eye::MapObject::Event::Type::BookingDetails:
{
pos = mapObject.GetPos();
found = true;
}
default: /* do nothing */;
}
auto const osmId = found ? m_delegate->GetCityOsmId(pos) : "";
if (!osmId.empty())
settings::Set("BookingCrossReferenceAwaitingForId", osmId);
}
} // namespace cross_reference

View file

@ -1,5 +1,7 @@
#pragma once
#include "metrics/eye.hpp"
#include "geometry/point2d.hpp"
#include <functional>
@ -39,10 +41,9 @@ public:
std::string const & lang, std::string & result);
};
using AfterBookingCallback = std::function<void(std::string const & url)>;
using CityGalleryCallback = std::function<void(CityGallery const & gallery)>;
class Api
class Api : public eye::Subscriber
{
public:
class Delegate
@ -58,16 +59,18 @@ public:
void SetDelegate(std::unique_ptr<Delegate> delegate);
void OnEnterForeground();
bool NeedToShow() const;
void GetCrossReferenceLinkAfterBooking(AfterBookingCallback const & cb) const;
std::string GetCrossReferenceLinkAfterBooking() const;
void GetCrossReferenceCityGallery(std::string const & osmId,
CityGalleryCallback const & cb) const;
void GetCrossReferenceCityGallery(m2::PointD const & point,
CityGalleryCallback const & cb) const;
void GetCrossReferenceCityGallery(m2::PointD const & point, CityGalleryCallback const & cb) const;
// eye::Subscriber overrides:
void OnMapObjectEvent(eye::MapObject const & poi) override;
private:
std::unique_ptr<Delegate> m_delegate;
std::string m_baseUrl;
bool m_bookingCrossReferenceIsAwaiting = false;
std::string m_bookingCrossReferenceAwaitingForId;
};
} // namespace cross_reference

View file

@ -69,7 +69,7 @@ UNIT_CLASS_TEST(ScopedEyeWithAsyncGuiThread, CrossReference_NeedToShow)
}
EyeForTesting::SetInfo(info);
settings::Set("BookingCrossReferenceIsAwaiting", true);
settings::Set("BookingCrossReferenceAwaitingForId", kTestOsmId);
api.OnEnterForeground();
TEST_EQUAL(api.NeedToShow(), false, ());
@ -94,7 +94,7 @@ UNIT_CLASS_TEST(ScopedEyeWithAsyncGuiThread, CrossReference_NeedToShow)
info.m_crossReferences.m_transitionToBookingTime = Clock::now() - std::chrono::hours(2);
EyeForTesting::SetInfo(info);
settings::Set("BookingCrossReferenceIsAwaiting", true);
settings::Set("BookingCrossReferenceAwaitingForId", kTestOsmId);
api.OnEnterForeground();
TEST_EQUAL(api.NeedToShow(), false, ());
@ -129,139 +129,13 @@ UNIT_CLASS_TEST(ScopedEyeWithAsyncGuiThread, CrossReference_NeedToShow)
info.m_crossReferences.m_transitionToBookingTime = Clock::now() - std::chrono::minutes(6);
EyeForTesting::SetInfo(info);
settings::Set("BookingCrossReferenceIsAwaiting", true);
settings::Set("BookingCrossReferenceAwaitingForId", kTestOsmId);
api.OnEnterForeground();
TEST_EQUAL(api.NeedToShow(), true, ());
}
UNIT_CLASS_TEST(ScopedEyeWithAsyncGuiThread, CrossReference_GetCrossReferenceLinkAfterBooking)
{
cross_reference::Api api;
api.SetDelegate(std::make_unique<DelegateForTesting>());
Info info;
{
MapObject poi;
poi.SetBestType("tourism-hotel");
poi.SetPos({53.652007, 108.143443});
MapObject::Event eventInfo;
eventInfo.m_eventTime = Clock::now() - std::chrono::hours((24 * 30 * 3) + 1);
eventInfo.m_userPos = {72.045507, 81.408095};
eventInfo.m_type = MapObject::Event::Type::Open;
poi.GetEditableEvents().emplace_back(eventInfo);
eventInfo.m_eventTime =
Clock::now() - (std::chrono::hours(24 * 30 * 3) + std::chrono::seconds(1));
eventInfo.m_userPos = {72.045400, 81.408200};
eventInfo.m_type = MapObject::Event::Type::AddToBookmark;
poi.GetEditableEvents().emplace_back(eventInfo);
eventInfo.m_eventTime = Clock::now() - std::chrono::hours(24 * 30 * 3);
eventInfo.m_userPos = {72.045450, 81.408201};
eventInfo.m_type = MapObject::Event::Type::RouteToCreated;
poi.GetEditableEvents().emplace_back(eventInfo);
info.m_mapObjects.Add(poi);
}
EyeForTesting::SetInfo(info);
settings::Set("BookingCrossReferenceIsAwaiting", true);
api.OnEnterForeground();
std::string result{};
api.GetCrossReferenceLinkAfterBooking([&result](std::string const & url)
{
result = url;
testing::Notify();
});
testing::Wait();
TEST(result.empty(), ());
auto eventTime = Clock::now() - std::chrono::hours(2);
{
MapObject poi;
poi.SetBestType("tourism-hotel");
poi.SetPos({53.652005, 108.143448});
MapObject::Event eventInfo;
eventInfo.m_eventTime = Clock::now() - std::chrono::hours(24 * 30 * 3);
eventInfo.m_userPos = {53.016347, 158.683327};
eventInfo.m_type = MapObject::Event::Type::Open;
poi.GetEditableEvents().emplace_back(eventInfo);
eventInfo.m_eventTime = eventTime;
eventInfo.m_userPos = {53.016347, 158.683327};
eventInfo.m_type = MapObject::Event::Type::BookingBook;
poi.GetEditableEvents().emplace_back(eventInfo);
info.m_mapObjects.Add(poi);
}
info.m_crossReferences.m_transitionToBookingTime = Clock::now() - std::chrono::hours(2);
EyeForTesting::SetInfo(info);
settings::Set("BookingCrossReferenceIsAwaiting", true);
api.OnEnterForeground();
result = {};
api.GetCrossReferenceLinkAfterBooking([&result](std::string const & url)
{
result = url;
testing::Notify();
});
testing::Wait();
TEST(result.empty(), ());
eventTime = Clock::now() - std::chrono::minutes(6);
{
MapObject poi;
poi.SetBestType("tourism-hotel");
poi.SetPos({53.653005, 108.143548});
MapObject::Event eventInfo;
eventInfo.m_eventTime = Clock::now() - std::chrono::hours(24 * 20 * 3);
eventInfo.m_userPos = {53.016347, 158.683327};
eventInfo.m_type = MapObject::Event::Type::Open;
poi.GetEditableEvents().emplace_back(eventInfo);
eventInfo.m_eventTime = eventTime;
eventInfo.m_userPos = {53.016347, 158.683327};
eventInfo.m_type = MapObject::Event::Type::BookingReviews;
poi.GetEditableEvents().emplace_back(eventInfo);
eventInfo.m_eventTime = Clock::now() - std::chrono::minutes(3);
eventInfo.m_userPos = {53.016347, 158.683327};
eventInfo.m_type = MapObject::Event::Type::Open;
poi.GetEditableEvents().emplace_back(eventInfo);
eventInfo.m_eventTime = Clock::now() - std::chrono::minutes(1);
eventInfo.m_userPos = {53.016347, 158.683327};
eventInfo.m_type = MapObject::Event::Type::RouteToCreated;
poi.GetEditableEvents().emplace_back(eventInfo);
info.m_mapObjects.Add(poi);
}
info.m_crossReferences.m_transitionToBookingTime = eventTime;
EyeForTesting::SetInfo(info);
settings::Set("BookingCrossReferenceIsAwaiting", true);
api.OnEnterForeground();
result = {};
api.GetCrossReferenceLinkAfterBooking([&result](std::string const & url)
{
result = url;
testing::Notify();
});
testing::Wait();
TEST_NOT_EQUAL(result.find(kTestOsmId, 0), std::string::npos, ());
}
UNIT_CLASS_TEST(ScopedEyeWithAsyncGuiThread, CrossReference_GetCrossReferenceCityGallery)
{
{}
cross_reference::Api api("http://localhost:34568/gallery/city/");
api.SetDelegate(std::make_unique<DelegateForTesting>());