1
0

cMojangAPI: Added periodical refreshes.

This commit is contained in:
Mattes D 2014-10-05 20:03:21 +02:00
parent 89713e23e4
commit 3d2d8a096b
2 changed files with 132 additions and 19 deletions

View File

@ -11,6 +11,8 @@
#include "json/json.h" #include "json/json.h"
#include "PolarSSL++/BlockingSslClientSocket.h" #include "PolarSSL++/BlockingSslClientSocket.h"
#include "../RankManager.h" #include "../RankManager.h"
#include "../OSSupport/IsThread.h"
#include "../Root.h"
@ -151,6 +153,41 @@ cMojangAPI::sProfile::sProfile(
////////////////////////////////////////////////////////////////////////////////
// cMojangAPI::cUpdateThread:
class cMojangAPI::cUpdateThread :
public cIsThread
{
typedef cIsThread super;
public:
cUpdateThread() :
super("cMojangAPI::cUpdateThread")
{
}
~cUpdateThread()
{
m_evtNotify.Set();
Stop();
}
protected:
cEvent m_evtNotify;
virtual void Execute(void) override
{
do
{
cRoot::Get()->GetMojangAPI().Update();
} while (!m_evtNotify.Wait(60 * 60 * 1000)); // Repeat every 60 minutes
}
} ;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cMojangAPI: // cMojangAPI:
@ -159,7 +196,8 @@ cMojangAPI::cMojangAPI(void) :
m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS), m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS),
m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER), m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER),
m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS), m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS),
m_RankMgr(NULL) m_RankMgr(NULL),
m_UpdateThread(new cUpdateThread())
{ {
} }
@ -183,6 +221,7 @@ void cMojangAPI::Start(cIniFile & a_SettingsIni)
m_UUIDToProfileServer = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER); m_UUIDToProfileServer = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileServer", DEFAULT_UUID_TO_PROFILE_SERVER);
m_UUIDToProfileAddress = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS); m_UUIDToProfileAddress = a_SettingsIni.GetValueSet("MojangAPI", "UUIDToProfileAddress", DEFAULT_UUID_TO_PROFILE_ADDRESS);
LoadCachesFromDisk(); LoadCachesFromDisk();
m_UpdateThread->Start();
} }
@ -465,21 +504,7 @@ void cMojangAPI::LoadCachesFromDisk(void)
db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)");
db.exec("CREATE TABLE IF NOT EXISTS UUIDToProfile (UUID, PlayerName, Textures, TexturesSignature, DateTime)"); db.exec("CREATE TABLE IF NOT EXISTS UUIDToProfile (UUID, PlayerName, Textures, TexturesSignature, DateTime)");
// Clean up old entries: // Retrieve all entries:
{
SQLite::Statement stmt(db, "DELETE FROM PlayerNameToUUID WHERE DateTime < ?");
Int64 LimitDateTime = time(NULL) - MAX_AGE;
stmt.bind(1, LimitDateTime);
stmt.exec();
}
{
SQLite::Statement stmt(db, "DELETE FROM UUIDToProfile WHERE DateTime < ?");
Int64 LimitDateTime = time(NULL) - MAX_AGE;
stmt.bind(1, LimitDateTime);
stmt.exec();
}
// Retrieve all remaining entries:
{ {
SQLite::Statement stmt(db, "SELECT PlayerName, UUID, DateTime FROM PlayerNameToUUID"); SQLite::Statement stmt(db, "SELECT PlayerName, UUID, DateTime FROM PlayerNameToUUID");
while (stmt.executeStep()) while (stmt.executeStep())
@ -596,18 +621,27 @@ void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames)
} // for itr - a_PlayerNames[] } // for itr - a_PlayerNames[]
} // Lock(m_CSNameToUUID) } // Lock(m_CSNameToUUID)
while (!NamesToQuery.empty()) QueryNamesToUUIDs(NamesToQuery);
}
void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
{
while (!a_NamesToQuery.empty())
{ {
// Create the request body - a JSON containing up to MAX_PER_QUERY playernames: // Create the request body - a JSON containing up to MAX_PER_QUERY playernames:
Json::Value root; Json::Value root;
int Count = 0; int Count = 0;
AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); AStringVector::iterator itr = a_NamesToQuery.begin(), end = a_NamesToQuery.end();
for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count)
{ {
Json::Value req(*itr); Json::Value req(*itr);
root.append(req); root.append(req);
} // for itr - a_PlayerNames[] } // for itr - a_PlayerNames[]
NamesToQuery.erase(NamesToQuery.begin(), itr); a_NamesToQuery.erase(a_NamesToQuery.begin(), itr);
Json::FastWriter Writer; Json::FastWriter Writer;
AString RequestBody = Writer.write(root); AString RequestBody = Writer.write(root);
@ -705,12 +739,22 @@ void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID)
// Check if already present: // Check if already present:
{ {
cCSLock Lock(m_CSUUIDToProfile);
if (m_UUIDToProfile.find(a_UUID) != m_UUIDToProfile.end()) if (m_UUIDToProfile.find(a_UUID) != m_UUIDToProfile.end())
{ {
return; return;
} }
} }
QueryUUIDToProfile(a_UUID);
}
void cMojangAPI::QueryUUIDToProfile(const AString & a_UUID)
{
// Create the request address: // Create the request address:
AString Address = m_UUIDToProfileAddress; AString Address = m_UUIDToProfileAddress;
ReplaceString(Address, "%UUID%", a_UUID); ReplaceString(Address, "%UUID%", a_UUID);
@ -817,3 +861,51 @@ void cMojangAPI::NotifyNameUUID(const AString & a_PlayerName, const AString & a_
void cMojangAPI::Update(void)
{
Int64 LimitDateTime = time(NULL) - MAX_AGE;
// Re-query all playernames that are stale:
AStringVector PlayerNames;
{
cCSLock Lock(m_CSNameToUUID);
for (cProfileMap::const_iterator itr = m_NameToUUID.begin(), end = m_NameToUUID.end(); itr != end; ++itr)
{
if (itr->second.m_DateTime < LimitDateTime)
{
PlayerNames.push_back(itr->first);
}
} // for itr - m_NameToUUID[]
}
if (!PlayerNames.empty())
{
LOG("cMojangAPI: Updating name-to-uuid cache for %u names", (unsigned)PlayerNames.size());
QueryNamesToUUIDs(PlayerNames);
}
// Re-query all profiles that are stale:
AStringVector ProfileUUIDs;
{
cCSLock Lock(m_CSUUIDToProfile);
for (cProfileMap::const_iterator itr = m_UUIDToProfile.begin(), end = m_UUIDToProfile.end(); itr != end; ++itr)
{
if (itr->second.m_DateTime < LimitDateTime)
{
ProfileUUIDs.push_back(itr->first);
}
} // for itr - m_UUIDToProfile[]
}
if (!ProfileUUIDs.empty())
{
LOG("cMojangAPI: Updating uuid-to-profile cache for %u uuids", (unsigned)ProfileUUIDs.size());
for (AStringVector::const_iterator itr = ProfileUUIDs.begin(), end = ProfileUUIDs.end(); itr != end; ++itr)
{
QueryUUIDToProfile(*itr);
}
}
}

View File

@ -93,6 +93,10 @@ public:
void SetRankManager(cRankManager * a_RankManager) { m_RankMgr = a_RankManager; } void SetRankManager(cRankManager * a_RankManager) { m_RankMgr = a_RankManager; }
protected: protected:
/** The thread that periodically checks for stale data and re-queries it from the server. */
class cUpdateThread;
/** Holds data for a single player profile. */ /** Holds data for a single player profile. */
struct sProfile struct sProfile
{ {
@ -177,6 +181,9 @@ protected:
/** Protects m_RankMgr agains simultaneous multi-threaded access. */ /** Protects m_RankMgr agains simultaneous multi-threaded access. */
cCriticalSection m_CSRankMgr; cCriticalSection m_CSRankMgr;
/** The thread that periodically updates the stale data in the DB from the Mojang servers. */
SharedPtr<cUpdateThread> m_UpdateThread;
/** Loads the caches from a disk storage. */ /** Loads the caches from a disk storage. */
@ -189,15 +196,29 @@ protected:
Names that are not valid are not added into the cache. Names that are not valid are not added into the cache.
ASSUMEs that a_PlayerNames contains lowercased player names. */ ASSUMEs that a_PlayerNames contains lowercased player names. */
void CacheNamesToUUIDs(const AStringVector & a_PlayerNames); void CacheNamesToUUIDs(const AStringVector & a_PlayerNames);
/** Queries all the specified names and stores them into the m_PlayerNameToUUID cache.
Names that are not valid are not added into the cache.
ASSUMEs that a_PlayerNames contans lowercased player names.
For performance reasons takes a non-const reference and modifies the list given to it, until empty. */
void QueryNamesToUUIDs(AStringVector & a_PlayerNames);
/** Makes sure the specified UUID is in the m_UUIDToProfile cache. If missing, downloads it from Mojang API servers. /** Makes sure the specified UUID is in the m_UUIDToProfile cache. If missing, downloads it from Mojang API servers.
UUIDs that are not valid will not be added into the cache. UUIDs that are not valid will not be added into the cache.
ASSUMEs that a_UUID is a lowercased short UUID. */ ASSUMEs that a_UUID is a lowercased short UUID. */
void CacheUUIDToProfile(const AString & a_UUID); void CacheUUIDToProfile(const AString & a_UUID);
/** Queries the specified UUID's profile and stores it in the m_UUIDToProfile cache. If already present, updates the cache entry.
UUIDs that are not valid will not be added into the cache.
ASSUMEs that a_UUID is a lowercased short UUID. */
void QueryUUIDToProfile(const AString & a_UUID);
/** Called for each name-uuid pairing that is discovered. /** Called for each name-uuid pairing that is discovered.
If assigned, notifies the m_RankManager of the event. */ If assigned, notifies the m_RankManager of the event. */
void NotifyNameUUID(const AString & a_PlayerName, const AString & a_PlayerUUID); void NotifyNameUUID(const AString & a_PlayerName, const AString & a_PlayerUUID);
/** Updates the stale values in the DB from the Mojang servers. Called from the cUpdateThread, blocks on the HTTPS API calls. */
void Update(void);
} ; // tolua_export } ; // tolua_export