forked from organicmaps/organicmaps-tmp
Pull request #4498 review fixes
This commit is contained in:
parent
a65d86ebcf
commit
5666583532
15 changed files with 281 additions and 313 deletions
|
@ -52,6 +52,10 @@ else
|
|||
#define BOOKING_SECRET ""
|
||||
#define UBER_SERVER_TOKEN ""
|
||||
#define UBER_CLIENT_ID ""
|
||||
#define TRACKING_REALTIME_HOST ""
|
||||
#define TRACKING_REALTIME_PORT 0
|
||||
#define TRACKING_HISTORICAL_HOST ""
|
||||
#define TRACKING_HISTORICAL_PORT 0
|
||||
' > "$PRIVATE_HEADER"
|
||||
echo 'ext {
|
||||
spropStoreFile = "../tools/android/debug.keystore"
|
||||
|
|
|
@ -156,6 +156,17 @@ void CancelQuery(weak_ptr<search::ProcessorHandle> & handle)
|
|||
queryHandle->Cancel();
|
||||
handle.reset();
|
||||
}
|
||||
|
||||
class StubSocket final : public platform::Socket
|
||||
{
|
||||
public:
|
||||
// Socket overrides
|
||||
bool Open(string const & host, uint16_t port) override { return false; }
|
||||
void Close() override {}
|
||||
bool Read(uint8_t * data, uint32_t count) override { return false; }
|
||||
bool Write(uint8_t const * data, uint32_t count) override { return false; }
|
||||
void SetTimeout(uint32_t milliseconds) override {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
pair<MwmSet::MwmId, MwmSet::RegResult> Framework::RegisterMap(
|
||||
|
@ -236,7 +247,7 @@ bool Framework::IsTrackingReporterEnabled() const
|
|||
return false;
|
||||
|
||||
bool allowStat = false;
|
||||
settings::Get(tracking::Reporter::kAllowKey, allowStat);
|
||||
UNUSED_VALUE(settings::Get(tracking::Reporter::kEnabledSettingsKey, allowStat));
|
||||
return allowStat;
|
||||
}
|
||||
|
||||
|
@ -330,7 +341,7 @@ Framework::Framework()
|
|||
, m_storage(platform::migrate::NeedMigrate() ? COUNTRIES_OBSOLETE_FILE : COUNTRIES_FILE)
|
||||
, m_bmManager(*this)
|
||||
, m_isRenderingEnabled(true)
|
||||
, m_trackingReporter(platform::createMockSocket(), tracking::Reporter::kPushDelayMs)
|
||||
, m_trackingReporter(make_unique<StubSocket>(), tracking::Reporter::kPushDelayMs)
|
||||
, m_displacementModeManager([this](bool show) {
|
||||
int const mode = show ? dp::displacement::kHotelMode : dp::displacement::kDefaultMode;
|
||||
CallDrapeFunction(bind(&df::DrapeEngine::SetDisplacementMode, _1, mode));
|
||||
|
|
|
@ -105,4 +105,3 @@ SOURCES += \
|
|||
preferred_languages.cpp \
|
||||
servers_list.cpp \
|
||||
settings.cpp \
|
||||
socket.cpp \
|
||||
|
|
|
@ -10,10 +10,12 @@ SOURCES += \
|
|||
scoped_dir.cpp \
|
||||
scoped_file.cpp \
|
||||
scoped_mwm.cpp \
|
||||
test_socket.cpp \
|
||||
writable_dir_changer.cpp \
|
||||
|
||||
HEADERS += \
|
||||
scoped_dir.hpp \
|
||||
scoped_file.hpp \
|
||||
scoped_mwm.hpp \
|
||||
test_socket.hpp \
|
||||
writable_dir_changer.hpp \
|
||||
|
|
67
platform/platform_tests_support/test_socket.cpp
Normal file
67
platform/platform_tests_support/test_socket.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "test_socket.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/chrono.hpp"
|
||||
|
||||
namespace platform
|
||||
{
|
||||
namespace tests_support
|
||||
{
|
||||
TestSocket::~TestSocket() { m_isConnected = false; }
|
||||
|
||||
bool TestSocket::Open(string const & host, uint16_t port)
|
||||
{
|
||||
if (m_isConnected)
|
||||
return false;
|
||||
|
||||
m_isConnected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestSocket::Close() { m_isConnected = false; }
|
||||
|
||||
bool TestSocket::Read(uint8_t * data, uint32_t count)
|
||||
{
|
||||
if (!m_isConnected)
|
||||
return false;
|
||||
|
||||
lock_guard<mutex> lg(m_inputMutex);
|
||||
|
||||
if (m_input.size() < count)
|
||||
return false;
|
||||
|
||||
copy(m_input.begin(), m_input.end(), data);
|
||||
m_input.erase(m_input.begin(), m_input.begin() + count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestSocket::Write(uint8_t const * data, uint32_t count)
|
||||
{
|
||||
if (!m_isConnected)
|
||||
return false;
|
||||
|
||||
{
|
||||
lock_guard<mutex> lg(m_outputMutex);
|
||||
m_output.insert(m_output.end(), data, data + count);
|
||||
}
|
||||
m_outputCondition.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestSocket::SetTimeout(uint32_t milliseconds) { m_timeoutMs = milliseconds; }
|
||||
|
||||
size_t TestSocket::ReadServer(vector<uint8_t> & destination)
|
||||
{
|
||||
unique_lock<mutex> lock(m_outputMutex);
|
||||
m_outputCondition.wait_for(lock, milliseconds(m_timeoutMs),
|
||||
[this]() { return !m_output.empty(); });
|
||||
|
||||
size_t const outputSize = m_output.size();
|
||||
destination.insert(destination.end(), m_output.begin(), m_output.end());
|
||||
m_output.clear();
|
||||
return outputSize;
|
||||
}
|
||||
} // namespace tests_support
|
||||
} // namespace platform
|
44
platform/platform_tests_support/test_socket.hpp
Normal file
44
platform/platform_tests_support/test_socket.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "platform/socket.hpp"
|
||||
|
||||
#include "std/atomic.hpp"
|
||||
#include "std/condition_variable.hpp"
|
||||
#include "std/cstdint.hpp"
|
||||
#include "std/deque.hpp"
|
||||
#include "std/mutex.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
namespace platform
|
||||
{
|
||||
namespace tests_support
|
||||
{
|
||||
class TestSocket final : public Socket
|
||||
{
|
||||
public:
|
||||
// Socket overrides:
|
||||
~TestSocket();
|
||||
bool Open(string const & host, uint16_t port) override;
|
||||
void Close() override;
|
||||
bool Read(uint8_t * data, uint32_t count) override;
|
||||
bool Write(uint8_t const * data, uint32_t count) override;
|
||||
void SetTimeout(uint32_t milliseconds) override;
|
||||
|
||||
// Simulates server reading.
|
||||
// Waits for some data or timeout.
|
||||
// Returns size of read data.
|
||||
size_t ReadServer(vector<uint8_t> & destination);
|
||||
|
||||
private:
|
||||
atomic<bool> m_isConnected = {false};
|
||||
atomic<uint32_t> m_timeoutMs = {100};
|
||||
|
||||
deque<uint8_t> m_input;
|
||||
mutex m_inputMutex;
|
||||
|
||||
vector<uint8_t> m_output;
|
||||
mutex m_outputMutex;
|
||||
condition_variable m_outputCondition;
|
||||
};
|
||||
} // namespace tests_support
|
||||
} // namespace platform
|
|
@ -1,122 +0,0 @@
|
|||
#include "socket.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/deque.hpp"
|
||||
#include "std/mutex.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
class MockSocket final : public platform::Socket
|
||||
{
|
||||
public:
|
||||
// Socket overrides
|
||||
bool Open(string const & host, uint16_t port) override { return false; }
|
||||
void Close() override {}
|
||||
bool Read(uint8_t * data, uint32_t count) override { return false; }
|
||||
bool Write(uint8_t const * data, uint32_t count) override { return false; }
|
||||
void SetTimeout(uint32_t milliseconds) override {}
|
||||
};
|
||||
|
||||
class TestSocketImpl final : public platform::TestSocket
|
||||
{
|
||||
public:
|
||||
// Socket overrides
|
||||
~TestSocketImpl();
|
||||
bool Open(string const & host, uint16_t port) override;
|
||||
void Close() override;
|
||||
bool Read(uint8_t * data, uint32_t count) override;
|
||||
bool Write(uint8_t const * data, uint32_t count) override;
|
||||
void SetTimeout(uint32_t milliseconds) override;
|
||||
|
||||
// TestSocket overrides
|
||||
bool HasInput() const override;
|
||||
bool HasOutput() const override;
|
||||
void WriteServer(uint8_t const * data, uint32_t count) override;
|
||||
size_t ReadServer(vector<uint8_t> & destination) override;
|
||||
|
||||
private:
|
||||
bool m_isConnected = false;
|
||||
|
||||
deque<uint8_t> m_input;
|
||||
mutable mutex m_inputMutex;
|
||||
|
||||
vector<uint8_t> m_output;
|
||||
mutable mutex m_outputMutex;
|
||||
};
|
||||
|
||||
TestSocketImpl::~TestSocketImpl() { m_isConnected = false; }
|
||||
|
||||
bool TestSocketImpl::Open(string const & host, uint16_t port)
|
||||
{
|
||||
m_isConnected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestSocketImpl::Close() { m_isConnected = false; }
|
||||
bool TestSocketImpl::Read(uint8_t * data, uint32_t count)
|
||||
{
|
||||
if (!m_isConnected)
|
||||
return false;
|
||||
|
||||
lock_guard<mutex> lg(m_inputMutex);
|
||||
|
||||
if (m_input.size() < count)
|
||||
return false;
|
||||
|
||||
copy(m_input.begin(), m_input.end(), data);
|
||||
m_input.erase(m_input.begin(), m_input.begin() + count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestSocketImpl::Write(uint8_t const * data, uint32_t count)
|
||||
{
|
||||
if (!m_isConnected)
|
||||
return false;
|
||||
|
||||
lock_guard<mutex> lg(m_outputMutex);
|
||||
m_output.insert(m_output.end(), data, data + count);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestSocketImpl::SetTimeout(uint32_t milliseconds) {}
|
||||
bool TestSocketImpl::HasInput() const
|
||||
{
|
||||
lock_guard<mutex> lg(m_inputMutex);
|
||||
return !m_input.empty();
|
||||
}
|
||||
|
||||
bool TestSocketImpl::HasOutput() const
|
||||
{
|
||||
lock_guard<mutex> lg(m_outputMutex);
|
||||
return !m_output.empty();
|
||||
}
|
||||
|
||||
void TestSocketImpl::WriteServer(uint8_t const * data, uint32_t count)
|
||||
{
|
||||
ASSERT(m_isConnected, ());
|
||||
|
||||
lock_guard<mutex> lg(m_inputMutex);
|
||||
m_input.insert(m_input.end(), data, data + count);
|
||||
}
|
||||
|
||||
size_t TestSocketImpl::ReadServer(vector<uint8_t> & destination)
|
||||
{
|
||||
lock_guard<mutex> lg(m_outputMutex);
|
||||
|
||||
size_t const outputSize = m_output.size();
|
||||
if (outputSize == 0)
|
||||
return 0;
|
||||
|
||||
destination.insert(destination.end(), m_output.begin(), m_output.end());
|
||||
m_output.clear();
|
||||
return outputSize;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace platform
|
||||
{
|
||||
unique_ptr<Socket> createMockSocket() { return make_unique<MockSocket>(); }
|
||||
unique_ptr<TestSocket> createTestSocket() { return make_unique<TestSocketImpl>(); }
|
||||
} // namespace platform
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "std/string.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
namespace platform
|
||||
{
|
||||
|
@ -26,21 +25,5 @@ public:
|
|||
virtual void SetTimeout(uint32_t milliseconds) = 0;
|
||||
};
|
||||
|
||||
class TestSocket : public Socket
|
||||
{
|
||||
public:
|
||||
virtual bool HasInput() const = 0;
|
||||
virtual bool HasOutput() const = 0;
|
||||
|
||||
// Simulate server writing
|
||||
virtual void WriteServer(uint8_t const * data, uint32_t count) = 0;
|
||||
|
||||
// Simulate server reading
|
||||
// returns size of read data
|
||||
virtual size_t ReadServer(vector<uint8_t> & destination) = 0;
|
||||
};
|
||||
|
||||
unique_ptr<Socket> createSocket();
|
||||
unique_ptr<Socket> createMockSocket();
|
||||
unique_ptr<TestSocket> createTestSocket();
|
||||
} // namespace platform
|
||||
|
|
|
@ -9,15 +9,11 @@ uint32_t constexpr kSocketTimeoutMs = 10000;
|
|||
|
||||
namespace tracking
|
||||
{
|
||||
// static
|
||||
const char Connection::kHost[] = "gps.host"; // TODO change to real host value
|
||||
uint16_t Connection::kPort = 666; // TODO change to real port value
|
||||
|
||||
Connection::Connection(unique_ptr<platform::Socket> socket, string const & host, uint16_t port,
|
||||
bool isHistorical)
|
||||
: m_socket(move(socket)), m_host(host), m_port(port)
|
||||
: m_socket(move(socket)), m_host(host), m_port(port), m_isHistorical(isHistorical)
|
||||
{
|
||||
ASSERT(m_socket.get() != nullptr, ());
|
||||
ASSERT(m_socket.get(), ());
|
||||
|
||||
m_socket->SetTimeout(kSocketTimeoutMs);
|
||||
}
|
||||
|
@ -35,9 +31,9 @@ bool Connection::Send(boost::circular_buffer<DataPoint> const & points)
|
|||
ASSERT(m_buffer.empty(), ());
|
||||
|
||||
MemWriter<decltype(m_buffer)> writer(m_buffer);
|
||||
coding::TrafficGPSEncoder::SerializeDataPoints(coding::TrafficGPSEncoder::kLatestVersion, writer,
|
||||
points);
|
||||
bool isSuccess = m_socket->Write(m_buffer.data(), m_buffer.size());
|
||||
using coding::TrafficGPSEncoder;
|
||||
TrafficGPSEncoder::SerializeDataPoints(TrafficGPSEncoder::kLatestVersion, writer, points);
|
||||
bool const isSuccess = m_socket->Write(m_buffer.data(), m_buffer.size());
|
||||
m_buffer.clear();
|
||||
return isSuccess;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "boost/circular_buffer.hpp"
|
||||
|
||||
#include "coding/traffic.hpp"
|
||||
|
||||
#include "std/cstdint.hpp"
|
||||
#include "std/string.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
#include "boost/circular_buffer.hpp"
|
||||
|
||||
namespace platform
|
||||
{
|
||||
class Socket;
|
||||
|
@ -18,9 +21,6 @@ using DataPoint = coding::TrafficGPSEncoder::DataPoint;
|
|||
class Connection final
|
||||
{
|
||||
public:
|
||||
static const char kHost[];
|
||||
static uint16_t kPort;
|
||||
|
||||
Connection(unique_ptr<platform::Socket> socket, string const & host, uint16_t port,
|
||||
bool isHistorical);
|
||||
bool Reconnect();
|
||||
|
@ -30,6 +30,7 @@ private:
|
|||
unique_ptr<platform::Socket> m_socket;
|
||||
string const m_host;
|
||||
uint16_t const m_port;
|
||||
bool const m_isHistorical;
|
||||
vector<uint8_t> m_buffer;
|
||||
};
|
||||
} // namespace tracking
|
||||
|
|
|
@ -1,87 +1,60 @@
|
|||
#include "reporter.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
#include "base/thread.hpp"
|
||||
#include "base/timer.hpp"
|
||||
|
||||
#include "boost/circular_buffer.hpp"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
#include "platform/socket.hpp"
|
||||
|
||||
#include "std/mutex.hpp"
|
||||
#include "std/vector.hpp"
|
||||
#include "base/logging.hpp"
|
||||
#include "base/timer.hpp"
|
||||
|
||||
#include "tracking/connection.hpp"
|
||||
#include "std/target_os.hpp"
|
||||
|
||||
using namespace tracking;
|
||||
#include "private.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
double constexpr kMinDelaySeconds = 1.0;
|
||||
double constexpr kReconnectDelaySeconds = 60.0;
|
||||
size_t constexpr kRealTimeBufferSize = 60;
|
||||
|
||||
class WorkerImpl final : public Reporter::Worker
|
||||
{
|
||||
public:
|
||||
WorkerImpl(unique_ptr<platform::Socket> socket, size_t pushDelayMs);
|
||||
void Run();
|
||||
|
||||
// Worker overrides
|
||||
void AddLocation(location::GpsInfo const & info);
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void FetchInput();
|
||||
bool SendPoints();
|
||||
|
||||
volatile bool m_stop = false;
|
||||
Connection m_realtimeSender;
|
||||
size_t m_pushDelayMs;
|
||||
bool m_wasConnected = false;
|
||||
double m_lastConnectTryTime = 0.0;
|
||||
vector<tracking::DataPoint> m_input;
|
||||
mutex m_inputMutex;
|
||||
boost::circular_buffer<DataPoint> m_points;
|
||||
double m_lastGpsTime = 0.0;
|
||||
};
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
namespace tracking
|
||||
{
|
||||
// static
|
||||
const char Reporter::kAllowKey[] = "AllowStat";
|
||||
// Apple and Android applications use different keys for settings.ini.
|
||||
// Keys saved for existing users, so can' fix it easy, need migration.
|
||||
// Use this hack until change to special traffic key.
|
||||
#if defined(OMIM_OS_IPHONE)
|
||||
const char Reporter::kEnabledSettingsKey[] = "StatisticsEnabled";
|
||||
#elif defined(OMIM_OS_ANDROID)
|
||||
const char Reporter::kEnabledSettingsKey[] = "AllowStat";
|
||||
#else
|
||||
const char Reporter::kEnabledSettingsKey[] = "AllowStat";
|
||||
#endif
|
||||
|
||||
Reporter::Reporter(unique_ptr<platform::Socket> socket, size_t pushDelayMs)
|
||||
{
|
||||
WorkerImpl * worker = new WorkerImpl(move(socket), pushDelayMs);
|
||||
m_worker = worker;
|
||||
threads::SimpleThread thread([worker]
|
||||
{
|
||||
worker->Run();
|
||||
delete worker;
|
||||
});
|
||||
thread.detach();
|
||||
}
|
||||
// static
|
||||
milliseconds const Reporter::kPushDelayMs = milliseconds(10000);
|
||||
|
||||
Reporter::~Reporter() { m_worker->Stop(); }
|
||||
|
||||
void Reporter::AddLocation(location::GpsInfo const & info) { m_worker->AddLocation(info); }
|
||||
} // namespace tracking
|
||||
|
||||
namespace
|
||||
{
|
||||
WorkerImpl::WorkerImpl(unique_ptr<platform::Socket> socket, size_t pushDelayMs)
|
||||
: m_realtimeSender(move(socket), Connection::kHost, Connection::kPort, false)
|
||||
, m_pushDelayMs(pushDelayMs)
|
||||
Reporter::Reporter(unique_ptr<platform::Socket> socket, milliseconds pushDelay)
|
||||
: m_realtimeSender(move(socket), TRACKING_REALTIME_HOST, TRACKING_REALTIME_PORT, false)
|
||||
, m_pushDelay(pushDelay)
|
||||
, m_points(kRealTimeBufferSize)
|
||||
, m_thread([this]{Run();})
|
||||
{
|
||||
}
|
||||
|
||||
void WorkerImpl::AddLocation(location::GpsInfo const & info)
|
||||
Reporter::~Reporter()
|
||||
{
|
||||
lock_guard<mutex> lg(m_inputMutex);
|
||||
{
|
||||
lock_guard<mutex> lg(m_mutex);
|
||||
m_isFinished = true;
|
||||
}
|
||||
m_cv.notify_one();
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
void Reporter::AddLocation(location::GpsInfo const & info)
|
||||
{
|
||||
lock_guard<mutex> lg(m_mutex);
|
||||
|
||||
if (info.m_timestamp < m_lastGpsTime + kMinDelaySeconds)
|
||||
return;
|
||||
|
@ -90,37 +63,34 @@ void WorkerImpl::AddLocation(location::GpsInfo const & info)
|
|||
m_input.push_back(DataPoint(info.m_timestamp, ms::LatLon(info.m_latitude, info.m_longitude)));
|
||||
}
|
||||
|
||||
void WorkerImpl::Run()
|
||||
void Reporter::Run()
|
||||
{
|
||||
LOG(LINFO, ("Tracking Reporter started"));
|
||||
|
||||
my::HighResTimer timer;
|
||||
unique_lock<mutex> lock(m_mutex);
|
||||
|
||||
while (!m_stop)
|
||||
while (!m_isFinished)
|
||||
{
|
||||
uint64_t const startMs = timer.ElapsedMillis();
|
||||
auto const startTime = steady_clock::now();
|
||||
|
||||
FetchInput();
|
||||
// Fetch input.
|
||||
m_points.insert(m_points.end(), m_input.begin(), m_input.end());
|
||||
m_input.clear();
|
||||
|
||||
lock.unlock();
|
||||
if (SendPoints())
|
||||
m_points.clear();
|
||||
lock.lock();
|
||||
|
||||
uint64_t const passedMs = timer.ElapsedMillis() - startMs;
|
||||
if (passedMs < m_pushDelayMs)
|
||||
threads::Sleep(m_pushDelayMs - passedMs);
|
||||
auto const passedMs = duration_cast<milliseconds>(steady_clock::now() - startTime);
|
||||
if (passedMs < m_pushDelay)
|
||||
m_cv.wait_for(lock, m_pushDelay - passedMs, [this]{return m_isFinished;});
|
||||
}
|
||||
|
||||
LOG(LINFO, ("Tracking Reporter finished"));
|
||||
}
|
||||
|
||||
void WorkerImpl::Stop() { m_stop = true; }
|
||||
void WorkerImpl::FetchInput()
|
||||
{
|
||||
lock_guard<mutex> lg(m_inputMutex);
|
||||
m_points.insert(m_points.end(), m_input.begin(), m_input.end());
|
||||
m_input.clear();
|
||||
}
|
||||
|
||||
bool WorkerImpl::SendPoints()
|
||||
bool Reporter::SendPoints()
|
||||
{
|
||||
if (m_points.empty())
|
||||
return true;
|
||||
|
@ -131,11 +101,11 @@ bool WorkerImpl::SendPoints()
|
|||
if (m_wasConnected)
|
||||
return true;
|
||||
|
||||
double currentTime = my::Timer::LocalTime();
|
||||
if (currentTime < m_lastConnectTryTime + kReconnectDelaySeconds)
|
||||
double const currentTime = my::Timer::LocalTime();
|
||||
if (currentTime < m_lastConnectionAttempt + kReconnectDelaySeconds)
|
||||
return false;
|
||||
|
||||
m_lastConnectTryTime = currentTime;
|
||||
m_lastConnectionAttempt = currentTime;
|
||||
|
||||
m_wasConnected = m_realtimeSender.Reconnect();
|
||||
if (!m_wasConnected)
|
||||
|
@ -144,4 +114,4 @@ bool WorkerImpl::SendPoints()
|
|||
m_wasConnected = m_realtimeSender.Send(m_points);
|
||||
return m_wasConnected;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace tracking
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "tracking/connection.hpp"
|
||||
|
||||
#include "base/thread.hpp"
|
||||
|
||||
#include "std/chrono.hpp"
|
||||
#include "std/condition_variable.hpp"
|
||||
#include "std/mutex.hpp"
|
||||
#include "std/unique_ptr.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
#include "boost/circular_buffer.hpp"
|
||||
|
||||
namespace location
|
||||
{
|
||||
|
@ -17,22 +27,30 @@ namespace tracking
|
|||
class Reporter final
|
||||
{
|
||||
public:
|
||||
static size_t constexpr kPushDelayMs = 10000;
|
||||
static const char kAllowKey[];
|
||||
static milliseconds const kPushDelayMs;
|
||||
static const char kEnabledSettingsKey[];
|
||||
|
||||
Reporter(unique_ptr<platform::Socket> socket, size_t pushDelayMs);
|
||||
Reporter(unique_ptr<platform::Socket> socket, milliseconds pushDelay);
|
||||
~Reporter();
|
||||
|
||||
void AddLocation(location::GpsInfo const & info);
|
||||
|
||||
class Worker
|
||||
{
|
||||
public:
|
||||
virtual void AddLocation(location::GpsInfo const & info) = 0;
|
||||
virtual void Stop() = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
Worker * m_worker;
|
||||
};
|
||||
void Run();
|
||||
bool SendPoints();
|
||||
|
||||
Connection m_realtimeSender;
|
||||
milliseconds m_pushDelay;
|
||||
bool m_wasConnected = false;
|
||||
double m_lastConnectionAttempt = 0.0;
|
||||
// Input buffer for incoming points. Worker thread steals it contents.
|
||||
vector<DataPoint> m_input;
|
||||
// Last collected points, sends periodically to server.
|
||||
boost::circular_buffer<DataPoint> m_points;
|
||||
double m_lastGpsTime = 0.0;
|
||||
bool m_isFinished = false;
|
||||
mutex m_mutex;
|
||||
condition_variable m_cv;
|
||||
threads::SimpleThread m_thread;
|
||||
};
|
||||
} // namespace tracking
|
||||
|
|
57
tracking/tracking_tests/reporter_test.cpp
Normal file
57
tracking/tracking_tests/reporter_test.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "tracking/reporter.hpp"
|
||||
|
||||
#include "coding/traffic.hpp"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
#include "platform/platform_tests_support/test_socket.hpp"
|
||||
#include "platform/socket.hpp"
|
||||
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "base/math.hpp"
|
||||
#include "base/thread.hpp"
|
||||
|
||||
#include "std/cmath.hpp"
|
||||
|
||||
using namespace tracking;
|
||||
using namespace platform::tests_support;
|
||||
|
||||
namespace
|
||||
{
|
||||
void TransferLocation(Reporter & reporter, TestSocket & testSocket, double timestamp,
|
||||
double latidute, double longtitude)
|
||||
{
|
||||
location::GpsInfo gpsInfo;
|
||||
gpsInfo.m_timestamp = timestamp;
|
||||
gpsInfo.m_latitude = latidute;
|
||||
gpsInfo.m_longitude = longtitude;
|
||||
reporter.AddLocation(gpsInfo);
|
||||
|
||||
vector<uint8_t> buffer;
|
||||
size_t const readSize = testSocket.ReadServer(buffer);
|
||||
TEST_GREATER(readSize, 0, ());
|
||||
|
||||
vector<coding::TrafficGPSEncoder::DataPoint> points;
|
||||
MemReader memReader(buffer.data(), buffer.size());
|
||||
ReaderSource<MemReader> src(memReader);
|
||||
coding::TrafficGPSEncoder::DeserializeDataPoints(coding::TrafficGPSEncoder::kLatestVersion, src,
|
||||
points);
|
||||
|
||||
TEST_EQUAL(points.size(), 1, ());
|
||||
auto const & point = points[0];
|
||||
TEST_EQUAL(point.m_timestamp, timestamp, ());
|
||||
TEST(my::AlmostEqualAbs(point.m_latLon.lat, latidute, 0.001), ());
|
||||
TEST(my::AlmostEqualAbs(point.m_latLon.lon, longtitude, 0.001), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(Reporter_TransferLocations)
|
||||
{
|
||||
auto socket = make_unique<TestSocket>();
|
||||
TestSocket & testSocket = *socket.get();
|
||||
|
||||
Reporter reporter(move(socket), milliseconds(10) /* pushDelay */);
|
||||
TransferLocation(reporter, testSocket, 1.0, 2.0, 3.0);
|
||||
TransferLocation(reporter, testSocket, 4.0, 5.0, 6.0);
|
||||
TransferLocation(reporter, testSocket, 7.0, 8.0, 9.0);
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
#include "base/thread.hpp"
|
||||
#include "coding/traffic.hpp"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
#include "platform/socket.hpp"
|
||||
|
||||
#include "std/cmath.hpp"
|
||||
|
||||
#include "testing/testing.hpp"
|
||||
|
||||
#include "tracking/reporter.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <class Condition>
|
||||
bool WaitCondition(Condition condition, size_t durationMs = 1000)
|
||||
{
|
||||
size_t sleepMs = 10;
|
||||
size_t cyclesLimit = durationMs / sleepMs;
|
||||
for (size_t i = 0; i < cyclesLimit; ++i)
|
||||
{
|
||||
threads::Sleep(sleepMs);
|
||||
if (condition())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
using namespace tracking;
|
||||
|
||||
UNIT_TEST(Reporter_TransferLocation)
|
||||
{
|
||||
unique_ptr<platform::TestSocket> socket = platform::createTestSocket();
|
||||
platform::TestSocket * testSocket = socket.get();
|
||||
|
||||
Reporter reporter(move(socket), 10);
|
||||
|
||||
location::GpsInfo gpsInfo;
|
||||
gpsInfo.m_timestamp = 3.0;
|
||||
gpsInfo.m_latitude = 4.0;
|
||||
gpsInfo.m_longitude = 5.0;
|
||||
reporter.AddLocation(gpsInfo);
|
||||
|
||||
TEST(WaitCondition([testSocket] { return testSocket->HasOutput(); }), ());
|
||||
|
||||
vector<uint8_t> buffer;
|
||||
testSocket->ReadServer(buffer);
|
||||
|
||||
vector<coding::TrafficGPSEncoder::DataPoint> points;
|
||||
MemReader memReader(buffer.data(), buffer.size());
|
||||
ReaderSource<MemReader> src(memReader);
|
||||
coding::TrafficGPSEncoder::DeserializeDataPoints(coding::TrafficGPSEncoder::kLatestVersion, src,
|
||||
points);
|
||||
|
||||
TEST_EQUAL(points.size(), 1, ());
|
||||
coding::TrafficGPSEncoder::DataPoint const & point = points[0];
|
||||
TEST_EQUAL(point.m_timestamp, 3, ());
|
||||
TEST(abs(point.m_latLon.lat - 4.0) < 0.001, ());
|
||||
TEST(abs(point.m_latLon.lon - 5.0) < 0.001, ());
|
||||
}
|
|
@ -7,7 +7,7 @@ ROOT_DIR = ../..
|
|||
|
||||
INCLUDEPATH *= $$ROOT_DIR/3party/jansson/src
|
||||
|
||||
DEPENDENCIES = base coding geometry platform routing stats_client tracking
|
||||
DEPENDENCIES = routing tracking platform_tests_support platform coding geometry base stats_client
|
||||
|
||||
include($$ROOT_DIR/common.pri)
|
||||
|
||||
|
@ -26,4 +26,4 @@ win*|linux* {
|
|||
|
||||
SOURCES += \
|
||||
$$ROOT_DIR/testing/testingmain.cpp \
|
||||
reporter_tests.cpp \
|
||||
reporter_test.cpp
|
||||
|
|
Loading…
Add table
Reference in a new issue