diff --git a/editor/user_stats.cpp b/editor/user_stats.cpp index 76788e0e75..cad45ce733 100644 --- a/editor/user_stats.cpp +++ b/editor/user_stats.cpp @@ -24,6 +24,11 @@ UserStats::UserStats(string const & userName) m_updateStatus = Update(); } +UserStats::UserStats(string const & userName, uint32_t rating, uint32_t changesCount) + : m_userName(userName), m_changesCount(changesCount), m_rank(rating), m_updateStatus(true) +{ +} + bool UserStats::IsChangesCountInitialized() const { return m_changesCount != kUninitialized; diff --git a/editor/user_stats.hpp b/editor/user_stats.hpp index 38f714bdcd..91c1dc8410 100644 --- a/editor/user_stats.hpp +++ b/editor/user_stats.hpp @@ -9,6 +9,7 @@ class UserStats { public: explicit UserStats(string const & userName); + explicit UserStats(string const & userName, uint32_t rating, uint32_t changesCount); bool IsChangesCountInitialized() const; bool IsRankInitialized() const; diff --git a/map/framework.cpp b/map/framework.cpp index 928f090264..b7f38102b7 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -410,6 +410,13 @@ Framework::Framework() editor.LoadMapEdits(); m_model.GetIndex().AddObserver(editor); + + LOG(LINFO, ("Editor initialized")); + + if(!LoadUserStatsFromSettings()) + LOG(LINFO, ("There is no cached stats in settings")); + else + LOG(LINFO, ("User stats was loaded successfully")); } Framework::~Framework() @@ -2895,11 +2902,81 @@ bool Framework::RollBackChanges(FeatureID const & fid) return rolledBack; } +namespace +{ +char const kSettingsUserName[] = "LoginedUser"; +char const kSettingsRating[] = "UserEditorRating"; +char const kSettingsChangesCount[] = "UserEditorChangsCount"; +} // namespace + +shared_ptr Framework::GetUserStats(string const & userName) const +{ + lock_guard g(m_userStatsMutex); + if (m_userName == userName) + return m_userStats; + return nullptr; +} + +void Framework::UpdateUserStats(string const & userName, TOnStatsUpdated const & fn) +{ + { + lock_guard g(m_userStatsMutex); + + auto nothingToUpdate = m_userStats && m_userName == userName; + nothingToUpdate = nothingToUpdate && difftime(time(nullptr), m_latsUpdate) <= 60 * 60 * 60; + + if (nothingToUpdate) + return GetPlatform().RunOnGuiThread(fn); + + m_userName = userName; + } + + thread([this, &fn, userName]() + { + if (UpdateUserStats(userName)) + { + lock_guard g(m_userStatsMutex); + if (m_userName == userName) + GetPlatform().RunOnGuiThread(fn); + } + }).detach(); +} + bool Framework::UpdateUserStats(string const & userName) { - auto userStats = make_unique(userName); + auto userStats = make_shared(userName); if (!userStats->GetUpdateStatus()) return false; + + lock_guard g(m_userStatsMutex); + if (m_userName != userName) + return false; + m_latsUpdate = time(nullptr); m_userStats = move(userStats); + SaveUserStatsToSettings(); return true; } + +bool Framework::LoadUserStatsFromSettings() +{ + uint32_t rating, changesCount; + if (!settings::Get(kSettingsUserName, m_userName) || + !settings::Get(kSettingsChangesCount, changesCount) || + !settings::Get(kSettingsRating, rating)) + { + return false; + } + + m_userStats = make_shared(m_userName, rating, changesCount); + return true; +} + +void Framework::SaveUserStatsToSettings() +{ + if (!m_userStats) + return; + + settings::Set(kSettingsUserName, m_userName); + settings::Set(kSettingsRating, m_userStats->GetRank()); + settings::Set(kSettingsChangesCount, m_userStats->GetChangesCount()); +} diff --git a/map/framework.hpp b/map/framework.hpp index b804ac06d8..418115350b 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -43,6 +43,7 @@ #include "base/thread_checker.hpp" #include "std/list.hpp" +#include "std/mutex.hpp" // TODO(mgsergio): remove when m_UserStatsMutex is gone. #include "std/shared_ptr.hpp" #include "std/target_os.hpp" #include "std/unique_ptr.hpp" @@ -675,15 +676,30 @@ private: public: //@{ - //User statistics. - editor::UserStats const * GetUserStats() const { return m_userStats.get(); } - /// Sends a synchronous request to the server and updates user's stats. - /// @returns true on success. - bool UpdateUserStats(string const & userName); - void DropUserStats() { m_userStats = nullptr; } + // TODO(mgsergio): move mutexed logic out from framework. + // User statistics. + + // A callback type to be passed in UpdateUserStats. + using TOnStatsUpdated = function; + + // TODO(mgsergio): Comment to this function. + shared_ptr GetUserStats(string const & userName) const; + + // Reads user stats from server or gets it from cache calls reader on success. + void UpdateUserStats(string const & userName, TOnStatsUpdated const & fn); private: - unique_ptr m_userStats; + /// Sends a synchronous request to the server and updates user's stats. + bool UpdateUserStats(string const & userName); + + bool LoadUserStatsFromSettings(); + /// Not thread-safe, use synchonization. + void SaveUserStatsToSettings(); + + shared_ptr m_userStats; + string m_userName; + time_t m_latsUpdate{}; + mutable mutex m_userStatsMutex; //@} DECLARE_THREAD_CHECKER(m_threadChecker);