async changed to detached threads

This commit is contained in:
Arsentiy Milchakov 2016-10-07 12:35:43 +03:00
parent 4e99e7b9fc
commit 53da4259b4
4 changed files with 134 additions and 109 deletions

View file

@ -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)

View file

@ -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<uber::Product> returnedProducts;
reqId = uberApi.GetAvailableProducts(
from, to, [&returnedId, &returnedProducts](vector<uber::Product> 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<uber::Product> 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<uber::Product> 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, ());
});
}

View file

@ -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<uber::Produc
p.m_price.empty();
}), products.end());
}
void GetAvailableProductsAsync(ms::LatLon const from, ms::LatLon const to,
size_t const requestId, atomic<bool> 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<uber::Product> 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<mutex> lock(m_mutex);
m_requestId = requestId;
m_times.reset();
m_prices.reset();
}
void ProductMaker::SetTimes(size_t const requestId, string const & times)
{
lock_guard<mutex> lock(m_mutex);
if (requestId != m_requestId)
return;
m_times = make_unique<string>(times);
}
void ProductMaker::SetPrices(size_t const requestId, string const & prices)
{
lock_guard<mutex> lock(m_mutex);
if (requestId != m_requestId)
return;
m_prices = make_unique<string>(prices);
}
void ProductMaker::MakeProducts(size_t const requestId, ProductsCallback const & fn)
{
lock_guard<mutex> lock(m_mutex);
if (requestId != m_requestId || !m_times || !m_prices)
return;
vector<uber::Product> 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<threads::SimpleThread>(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<float>(from.lat)
<< "&pickup[longitude]=" << static_cast<float>(from.lon)
<< "&dropoff[latitude]=" << static_cast<float>(to.lat)
<< "&dropoff[longitude]=" << static_cast<float>(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

View file

@ -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<void(vector<Product> 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<string> m_times;
unique_ptr<string> 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<threads::SimpleThread> m_thread;
atomic<bool> m_runFlag;
shared_ptr<ProductMaker> m_maker = make_shared<ProductMaker>();
};
} // namespace uber