void cMojangAPI::LoadCachesFromDisk(void) { try { // Open up the SQLite DB: SQLite::Database db("MojangAPI.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); db.exec("CREATE TABLE IF NOT EXISTS UUIDToProfile (UUID, PlayerName, Textures, TexturesSignature, DateTime)"); // Clean up old 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"); while (stmt.executeStep()) { AString PlayerName = stmt.getColumn(0); AString UUID = stmt.getColumn(1); Int64 DateTime = stmt.getColumn(2); UUID = MakeUUIDShort(UUID); m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, UUID, "", "", DateTime); m_UUIDToName[UUID] = sProfile(PlayerName, UUID, "", "", DateTime); } } { SQLite::Statement stmt(db, "SELECT PlayerName, UUID, Textures, TexturesSignature, DateTime FROM UUIDToProfile"); while (stmt.executeStep()) { AString PlayerName = stmt.getColumn(0); AString UUID = stmt.getColumn(1); AString Textures = stmt.getColumn(2); AString TexturesSignature = stmt.getColumn(2); Int64 DateTime = stmt.getColumn(4); UUID = MakeUUIDShort(UUID); m_UUIDToProfile[UUID] = sProfile(PlayerName, UUID, Textures, TexturesSignature, DateTime); } } } catch (const SQLite::Exception & ex) { LOGINFO("Loading MojangAPI cache failed: %s", ex.what()); } }
void cMojangAPI::LoadCachesFromDisk(void) { try { // Open up the SQLite DB: SQLite::Database db("MojangAPI.sqlite", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS PlayerNameToUUID (PlayerName, UUID, DateTime)"); db.exec("CREATE TABLE IF NOT EXISTS UUIDToProfile (UUID, PlayerName, Textures, TexturesSignature, DateTime)"); // Retrieve all entries: { SQLite::Statement stmt(db, "SELECT PlayerName, UUID, DateTime FROM PlayerNameToUUID"); while (stmt.executeStep()) { AString PlayerName = stmt.getColumn(0); AString StringUUID = stmt.getColumn(1); Int64 DateTime = stmt.getColumn(2); cUUID UUID; if (!UUID.FromString(StringUUID)) { continue; // Invalid UUID } m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, UUID, "", "", DateTime); m_UUIDToName[UUID] = sProfile(PlayerName, UUID, "", "", DateTime); } } { SQLite::Statement stmt(db, "SELECT PlayerName, UUID, Textures, TexturesSignature, DateTime FROM UUIDToProfile"); while (stmt.executeStep()) { AString PlayerName = stmt.getColumn(0); AString StringUUID = stmt.getColumn(1); AString Textures = stmt.getColumn(2); AString TexturesSignature = stmt.getColumn(2); Int64 DateTime = stmt.getColumn(4); cUUID UUID; if (!UUID.FromString(StringUUID)) { continue; // Invalid UUID } m_UUIDToProfile[UUID] = sProfile(PlayerName, UUID, Textures, TexturesSignature, DateTime); } } } catch (const SQLite::Exception & ex) { LOGINFO("Loading MojangAPI cache failed: %s", ex.what()); } }
void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const AString & a_UUID) { AString UUID = MakeUUIDShort(a_UUID); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToName); m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now); } }
void cMojangAPI::AddPlayerNameToUUIDMapping(const AString & a_PlayerName, const cUUID & a_UUID) { Int64 Now = time(nullptr); { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, a_UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToName); m_UUIDToName[a_UUID] = sProfile(a_PlayerName, a_UUID, "", "", Now); } NotifyNameUUID(a_PlayerName, a_UUID); }
void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const AString & a_UUID, const Json::Value & a_Properties) { AString UUID = MakeUUIDShort(a_UUID); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToName); m_UUIDToName[UUID] = sProfile(a_PlayerName, UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToProfile); m_UUIDToProfile[UUID] = sProfile(a_PlayerName, UUID, a_Properties, Now); } }
void cMojangAPI::AddPlayerProfile(const AString & a_PlayerName, const cUUID & a_UUID, const Json::Value & a_Properties) { Int64 Now = time(nullptr); { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(a_PlayerName)] = sProfile(a_PlayerName, a_UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToName); m_UUIDToName[a_UUID] = sProfile(a_PlayerName, a_UUID, "", "", Now); } { cCSLock Lock(m_CSUUIDToProfile); m_UUIDToProfile[a_UUID] = sProfile(a_PlayerName, a_UUID, a_Properties, Now); } NotifyNameUUID(a_PlayerName, a_UUID); }
BOOL COutlookFrame::DestroyWindow() { CString sProfile(_T("BarState")); m_wndControlBar.SaveState(sProfile); SaveBarState(sProfile); // DestroyWindow will destroy all childs so let's tell it to Inteface. if (m_pInterface != NULL) { m_pInterface->ResetView(); } return CProjectFrame::DestroyWindow(); }
int COutlookFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CProjectFrame::OnCreate(lpCreateStruct) == -1) return -1; EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar, AFX_IDW_DOCKBAR_TOP); RecalcLayout(); // essential CRect rect; m_wndToolBar.GetWindowRect(&rect); rect.OffsetRect(1, 0); DockControlBar(&m_wndOutlookToolBar, AFX_IDW_DOCKBAR_TOP, &rect); if (!m_wndControlBar.Create(_T("Control Bar"), this, 10)) { TRACE0("Failed to create control bar\n"); return false; } m_wndControlBar.SetBarStyle(m_wndControlBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); m_wndControlBar.SetSCBStyle(m_wndControlBar.GetSCBStyle() | SCBS_SHOWEDGES | SCBS_SIZECHILD); m_wndControlBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); DockControlBar(&m_wndControlBar, AFX_IDW_DOCKBAR_LEFT); CString sProfile(_T("BarState")); if (VerifyBarState(sProfile)) { m_wndControlBar.LoadState(sProfile); LoadBarState(sProfile); } return 0; }
void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) { ASSERT(a_UUID.size() == 32); // Check if already present: { if (m_UUIDToProfile.find(a_UUID) != m_UUIDToProfile.end()) { return; } } // Create the request address: AString Address = m_UUIDToProfileAddress; ReplaceString(Address, "%UUID%", a_UUID); // Create the HTTP request: AString Request; Request += "GET " + Address + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_UUIDToProfileServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Length: 0\r\n"; Request += "\r\n"; // Get the response from the server: AString Response; if (!SecureRequest(m_UUIDToProfileServer, Request, Response)) { return; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; Json::Value root; if (!reader.parse(Response, root, false) || !root.isObject()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } /* Example response: { "id": "b1caf24202a841a78055a079c460eee7", "name": "xoft", "properties": [ { "name": "textures", "value": "eyJ0aW1lc3RhbXAiOjE0MDcwNzAzMjEyNzEsInByb2ZpbGVJZCI6ImIxY2FmMjQyMDJhODQxYTc4MDU1YTA3OWM0NjBlZWU3IiwicHJvZmlsZU5hbWUiOiJ4b2Z0IiwiaXNQdWJsaWMiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9iNzc5YmFiZjVhNTg3Zjk0OGFkNjc0N2VhOTEyNzU0MjliNjg4Mjk1YWUzYzA3YmQwZTJmNWJmNGQwNTIifX19", "signature": "XCty+jGEF39hEPrPhYNnCX087kPaoCjYruzYI/DS4nkL5hbjnkSM5Rh15hnUyv/FHhC8OF5rif3D1tQjtMI19KSVaXoUFXpbJM8/+PB8GDgEbX8Fc3u9nYkzOcM/xfxdYsFAdFhLQMkvase/BZLSuPhdy9DdI+TCrO7xuSTZfYmmwVuWo3w5gCY+mSIAnqltnOzaOOTcly75xvO0WYpVk7nJdnR2tvSi0wfrQPDrIg/uzhX7p0SnDqijmBU4QaNez/TNKiFxy69dAzt0RSotlQzqkDbyVKhhv9a4eY8h3pXi4UMftKEj4FAKczxLImkukJXuOn5NN15/Q+le0rJVBC60/xjKIVzltEsMN6qjWD0lQjey7WEL+4pGhCVuWY5KzuZjFvgqszuJTFz7lo+bcHiceldJtea8/fa02eTRObZvdLxbWC9ZfFY0IhpOVKfcLdno/ddDMNMQMi5kMrJ8MZZ/PcW1w5n7MMGWPGCla1kOaC55AL0QYSMGRVEZqgU9wXI5M7sHGZKGM4mWxkbEJYBkpI/p3GyxWgV6v33ZWlsz65TqlNrR1gCLaoFCm7Sif8NqPBZUAONHYon0roXhin/DyEanS93WV6i6FC1Wisscjq2AcvnOlgTo/5nN/1QsMbjNumuMGo37sqjRqlXoPb8zEUbAhhztYuJjEfQ2Rd8=" } ] } */ // Store the returned result into caches: AString PlayerName = root.get("name", "").asString(); if (PlayerName.empty()) { // No valid playername, bail out return; } Json::Value Properties = root.get("properties", ""); Int64 Now = time(NULL); { cCSLock Lock(m_CSUUIDToProfile); m_UUIDToProfile[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); } { cCSLock Lock(m_CSUUIDToName); m_UUIDToName[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); } { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now); } }
void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { // Create a list of names to query, by removing those that are already cached: AStringVector NamesToQuery; NamesToQuery.reserve(a_PlayerNames.size()); { cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { if (m_NameToUUID.find(*itr) == m_NameToUUID.end()) { NamesToQuery.push_back(*itr); } } // for itr - a_PlayerNames[] } // Lock(m_CSNameToUUID) while (!NamesToQuery.empty()) { // Create the request body - a JSON containing up to MAX_PER_QUERY playernames: Json::Value root; int Count = 0; AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) { Json::Value req(*itr); root.append(req); } // for itr - a_PlayerNames[] NamesToQuery.erase(NamesToQuery.begin(), itr); Json::FastWriter Writer; AString RequestBody = Writer.write(root); // Create the HTTP request: AString Request; Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_NameToUUIDServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Type: application/json\r\n"; Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); Request += "\r\n"; Request += RequestBody; // Get the response from the server: AString Response; if (!SecureRequest(m_NameToUUIDServer, Request, Response)) { continue; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; if (!reader.parse(Response, root, false) || !root.isArray()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Store the returned results into cache: size_t JsonCount = root.size(); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } // cCSLock (m_CSNameToUUID) // Also cache the UUIDToName: { cCSLock Lock(m_CSUUIDToName); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_UUIDToName[JsonUUID] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } } // while (!NamesToQuery.empty()) }