From 53da4259b42ee24fc5c662514cb533529939ad1b Mon Sep 17 00:00:00 2001 From: Arsentiy Milchakov Date: Fri, 7 Oct 2016 12:35:43 +0300 Subject: [PATCH] async changed to detached threads --- map/framework.cpp | 3 +- .../partners_api_tests/uber_tests.cpp | 57 +++---- partners_api/uber_api.cpp | 148 ++++++++++-------- partners_api/uber_api.hpp | 35 +++-- 4 files changed, 134 insertions(+), 109 deletions(-) diff --git a/map/framework.cpp b/map/framework.cpp index 3f64d250b3..daff132424 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -2561,7 +2561,8 @@ void Framework::AllowAutoZoom(bool allowAutoZoom) bool const isPedestrianRoute = m_currentRouterType == RouterType::Pedestrian; bool const isUberRoute = m_currentRouterType == RouterType::Uber; - CallDrapeFunction(bind(&df::DrapeEngine::AllowAutoZoom, _1, allowAutoZoom && !isPedestrianRoute && !isUberRoute)); + CallDrapeFunction(bind(&df::DrapeEngine::AllowAutoZoom, _1, + allowAutoZoom && !isPedestrianRoute && !isUberRoute)); } void Framework::SaveAutoZoom(bool allowAutoZoom) diff --git a/partners_api/partners_api_tests/uber_tests.cpp b/partners_api/partners_api_tests/uber_tests.cpp index ea2e9cbdea..850f1333d7 100644 --- a/partners_api/partners_api_tests/uber_tests.cpp +++ b/partners_api/partners_api_tests/uber_tests.cpp @@ -1,10 +1,8 @@ #include "testing/testing.hpp" -#include "geometry/latlon.hpp" - #include "partners_api/uber_api.hpp" -#include "base/logging.hpp" +#include "geometry/latlon.hpp" #include "3party/jansson/myjansson.hpp" @@ -23,7 +21,7 @@ UNIT_TEST(Uber_GetTimes) auto const timesArray = json_object_get(timeRoot.get(), "times"); TEST(json_is_array(timesArray), ()); - TEST(json_array_size(timesArray) > 0, ()); + TEST_GREATER(json_array_size(timesArray), 0, ()); auto const timeSize = json_array_size(timesArray); for (size_t i = 0; i < timeSize; ++i) @@ -39,7 +37,7 @@ UNIT_TEST(Uber_GetTimes) } catch (my::Json::Exception const & e) { - LOG(LERROR, (e.Msg())); + TEST(false, (e.Msg())); } string estimated = strings::to_string(estimatedTime); @@ -58,7 +56,7 @@ UNIT_TEST(Uber_GetPrices) auto const pricesArray = json_object_get(priceRoot.get(), "prices"); TEST(json_is_array(pricesArray), ()); - TEST(json_array_size(pricesArray) > 0, ()); + TEST_GREATER(json_array_size(pricesArray), 0, ()); auto const pricesSize = json_array_size(pricesArray); for (size_t i = 0; i < pricesSize; ++i) @@ -85,7 +83,7 @@ UNIT_TEST(Uber_GetPrices) } catch (my::Json::Exception const & e) { - LOG(LERROR, (e.Msg())); + TEST(false, (e.Msg())); } TEST(!productId.empty(), ()); @@ -94,34 +92,39 @@ UNIT_TEST(Uber_GetPrices) } } -UNIT_TEST(Uber_SmokeTest) +UNIT_TEST(Uber_ProductMaker) { + size_t reqId = 1; ms::LatLon from(38.897724, -77.036531); ms::LatLon to(38.862416, -76.883316); - uber::Api uberApi; - size_t reqId = 0; - size_t returnedId = 0; - vector returnedProducts; - reqId = uberApi.GetAvailableProducts( - from, to, [&returnedId, &returnedProducts](vector const & products, size_t const requestId) - { - returnedId = requestId; - returnedProducts = products; + uber::ProductMaker maker; - testing::StopEventLoop(); + maker.Reset(reqId); + maker.SetTimes(reqId, uber::RawApi::GetEstimatedTime(from)); + maker.SetPrices(reqId, uber::RawApi::GetEstimatedPrice(from, to)); + maker.MakeProducts(reqId, [reqId](vector const & products, size_t const requestId) + { + TEST(!products.empty(), ()); + TEST_EQUAL(requestId, reqId, ()); + + for (auto const & product : products) + { + TEST(!product.m_productId.empty() && + !product.m_name.empty() && + !product.m_time.empty() && + !product.m_price.empty(),()); + } }); - testing::RunEventLoop(); + ++reqId; - TEST(!returnedProducts.empty(), ()); - TEST_EQUAL(returnedId, reqId, ()); + maker.Reset(reqId); + maker.SetTimes(reqId, uber::RawApi::GetEstimatedTime(from)); + maker.SetPrices(reqId, uber::RawApi::GetEstimatedPrice(from, to)); - for (auto const & product : returnedProducts) + maker.MakeProducts(reqId + 1, [reqId](vector const & products, size_t const requestId) { - TEST(!product.m_productId.empty() && - !product.m_name.empty() && - !product.m_time.empty() && - !product.m_price.empty(),()); - } + TEST(false, ()); + }); } diff --git a/partners_api/uber_api.cpp b/partners_api/uber_api.cpp index edb8908e3c..22e1b6388d 100644 --- a/partners_api/uber_api.cpp +++ b/partners_api/uber_api.cpp @@ -6,6 +6,7 @@ #include "base/assert.hpp" #include "base/logging.hpp" +#include "base/thread.hpp" #include "std/chrono.hpp" #include "std/future.hpp" @@ -18,8 +19,6 @@ using namespace platform; namespace { -uint32_t const kHttpMinWait = 10; - string RunSimpleHttpRequest(string const & url) { HttpClient request(url); @@ -98,49 +97,6 @@ void FillProducts(json_t const * time, json_t const * price, vector const & runFlag, - uber::ProductsCallback const fn) -{ - auto time = async(launch::async, uber::RawApi::GetEstimatedTime, ref(from)); - auto price = async(launch::async, uber::RawApi::GetEstimatedPrice, ref(from), ref(to)); - - vector products; - - if (!WaitForFeature(time, kHttpMinWait, runFlag) || !WaitForFeature(price, kHttpMinWait, runFlag)) - { - return; - } - - try - { - string timeStr = time.get(); - string priceStr = price.get(); - - if (timeStr.empty() || priceStr.empty()) - { - LOG(LWARNING, ("Time or price is empty, time:", timeStr, "; price:", priceStr)); - return; - } - - my::Json timeRoot(timeStr.c_str()); - my::Json priceRoot(priceStr.c_str()); - auto const timesArray = json_object_get(timeRoot.get(), "times"); - auto const pricesArray = json_object_get(priceRoot.get(), "prices"); - if (CheckUberAnswer(timesArray) && CheckUberAnswer(pricesArray)) - { - FillProducts(timesArray, pricesArray, products); - } - } - catch (my::Json::Exception const & e) - { - LOG(LERROR, (e.Msg())); - products.clear(); - } - - fn(products, requestId); -} } // namespace namespace uber @@ -176,21 +132,92 @@ string RawApi::GetEstimatedPrice(ms::LatLon const & from, ms::LatLon const & to) return RunSimpleHttpRequest(url.str()); } -Api::~Api() +void ProductMaker::Reset(size_t const requestId) { - ResetThread(); + lock_guard lock(m_mutex); + + m_requestId = requestId; + m_times.reset(); + m_prices.reset(); +} + +void ProductMaker::SetTimes(size_t const requestId, string const & times) +{ + lock_guard lock(m_mutex); + + if (requestId != m_requestId) + return; + + m_times = make_unique(times); +} + +void ProductMaker::SetPrices(size_t const requestId, string const & prices) +{ + lock_guard lock(m_mutex); + + if (requestId != m_requestId) + return; + + m_prices = make_unique(prices); +} + +void ProductMaker::MakeProducts(size_t const requestId, ProductsCallback const & fn) +{ + lock_guard lock(m_mutex); + + if (requestId != m_requestId || !m_times || !m_prices) + return; + + vector products; + + if (m_times->empty() || m_prices->empty()) + { + LOG(LWARNING, ("Time or price is empty, time:", *m_times, "; price:", *m_prices)); + fn(products, m_requestId); + return; + } + + try + { + my::Json timesRoot(m_times->c_str()); + my::Json pricesRoot(m_prices->c_str()); + auto const timesArray = json_object_get(timesRoot.get(), "times"); + auto const pricesArray = json_object_get(pricesRoot.get(), "prices"); + if (CheckUberAnswer(timesArray) && CheckUberAnswer(pricesArray)) + { + FillProducts(timesArray, pricesArray, products); + } + } + catch (my::Json::Exception const & e) + { + LOG(LERROR, (e.Msg())); + products.clear(); + } + + fn(products, requestId); } size_t Api::GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to, ProductsCallback const & fn) { static size_t requestId = 0; - ResetThread(); - m_runFlag = true; - m_thread = make_unique(GetAvailableProductsAsync, from, to, - ++requestId, ref(m_runFlag), fn); + size_t reqId = ++requestId; - return requestId; + m_maker->Reset(reqId); + + threads::SimpleThread([this, from, reqId, fn]() + { + m_maker->SetTimes(reqId, uber::RawApi::GetEstimatedTime(from)); + m_maker->MakeProducts(reqId, fn); + }).detach(); + + threads::SimpleThread([this, from, to, reqId, fn]() + { + m_maker->SetPrices(reqId, uber::RawApi::GetEstimatedPrice(from, to)); + m_maker->MakeProducts(reqId, fn); + }).detach(); + + return reqId; } // static @@ -199,22 +226,9 @@ string Api::GetRideRequestLink(string const & productId, ms::LatLon const & from { stringstream url; url << "uber://?client_id=" << UBER_CLIENT_ID << "&action=setPickup&product_id=" << productId - << "&pickup[latitude]=" << static_cast(from.lat) - << "&pickup[longitude]=" << static_cast(from.lon) - << "&dropoff[latitude]=" << static_cast(to.lat) - << "&dropoff[longitude]=" << static_cast(to.lon); + << "&pickup[latitude]=" << from.lat << "&pickup[longitude]=" << from.lon + << "&dropoff[latitude]=" << to.lat << "&dropoff[longitude]=" << to.lon; return url.str(); } - -void Api::ResetThread() -{ - m_runFlag = false; - - if (m_thread) - { - m_thread->join(); - m_thread.reset(); - } -} } // namespace uber diff --git a/partners_api/uber_api.hpp b/partners_api/uber_api.hpp index d16144caa1..faf5fc5292 100644 --- a/partners_api/uber_api.hpp +++ b/partners_api/uber_api.hpp @@ -1,22 +1,20 @@ #pragma once -#include "base/thread.hpp" - -#include "std/atomic.hpp" #include "std/function.hpp" #include "std/mutex.hpp" +#include "std/shared_ptr.hpp" #include "std/string.hpp" #include "std/unique_ptr.hpp" #include "std/vector.hpp" namespace ms { - class LatLon; +class LatLon; } // namespace ms namespace downloader { - class HttpRequest; +class HttpRequest; } // namespace downloader namespace uber @@ -54,25 +52,34 @@ struct Product /// @requestId - identificator which was provided to GetAvailableProducts to identify request. using ProductsCallback = function const & products, size_t const requestId)>; +/// Class which used for making products from http requests results. +class ProductMaker +{ +public: + void Reset(size_t const requestId); + void SetTimes(size_t const requestId, string const & times); + void SetPrices(size_t const requestId, string const & prices); + void MakeProducts(size_t const requestId, ProductsCallback const & fn); + +private: + size_t m_requestId; + unique_ptr m_times; + unique_ptr m_prices; + mutex m_mutex; +}; + class Api { public: - ~Api(); /// Requests list of available products from Uber. Returns request identificator immediately. size_t GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to, - ProductsCallback const & fn); + ProductsCallback const & fn); /// Returns link which allows you to launch the Uber app. static string GetRideRequestLink(string const & productId, ms::LatLon const & from, ms::LatLon const & to); private: - void ResetThread(); - unique_ptr m_thread; - - atomic m_runFlag; + shared_ptr m_maker = make_shared(); }; } // namespace uber - - -