summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAotrix <[email protected]>2026-04-19 18:16:14 +0200
committerAotrix <[email protected]>2026-04-19 18:16:14 +0200
commitcc436cb44c60ef2485321e1e22b3ea0a59ee22af (patch)
treeb04464945278bcdc8915d8b3676b504a95e3f701
parent8837de4783b25255b6a1799be210c9e580dd2d4f (diff)
TokenPool now works
-rw-r--r--battleNetApi/include/apiUrl.hpp18
-rw-r--r--battleNetApi/include/hearthstoneApi.hpp2
-rw-r--r--battleNetApi/include/token.hpp2
-rw-r--r--battleNetApi/include/tokenPool.hpp7
-rw-r--r--battleNetApi/src/apiUrl.cpp22
-rw-r--r--battleNetApi/src/hearthstoneApi.cpp5
-rw-r--r--battleNetApi/src/main.cpp6
-rw-r--r--battleNetApi/src/tokenPool.cpp17
-rw-r--r--battleNetApi/tests/tests.cpp33
9 files changed, 77 insertions, 35 deletions
diff --git a/battleNetApi/include/apiUrl.hpp b/battleNetApi/include/apiUrl.hpp
index 881e593..e936b6c 100644
--- a/battleNetApi/include/apiUrl.hpp
+++ b/battleNetApi/include/apiUrl.hpp
@@ -1,4 +1,5 @@
#pragma once
+#include <cstdint>
#include <string>
#include <unordered_map>
@@ -10,12 +11,27 @@ class ApiUrl {
void setLocale(const std::string &iLocale);
void setGameMode(const std::string &iGameMode);
void setPage(const std::string &iPage);
+ void setPage(uint64_t iPage);
void setPageSize(const std::string &iPageSize);
- void setValue(const std::string &iKey, const std::string &iValue);
+ void setPageSize(uint64_t iPageSize);
+
+ bool hasRegion() const;
+ bool hasLocale() const;
+ bool hasGameMode() const;
+ bool hasPage() const;
+ bool hasPageSize() const;
+
std::string text() const;
private:
+ static constexpr std::string kLOCALE_KEY{"locale"};
+ static constexpr std::string kGAME_MODE_KEY{"gameMode"};
+ static constexpr std::string kPAGE_KEY{"page"};
+ static constexpr std::string kPAGE_SIZE_KEY{"pageSize"};
std::string mContentType;
std::string mRegion;
std::unordered_map<std::string, std::string> aParameters;
+
+ void setValue(const std::string &iKey, const std::string &iValue);
+ bool hasValue(const std::string &iKey) const;
};
diff --git a/battleNetApi/include/hearthstoneApi.hpp b/battleNetApi/include/hearthstoneApi.hpp
index f2bdf04..59cd336 100644
--- a/battleNetApi/include/hearthstoneApi.hpp
+++ b/battleNetApi/include/hearthstoneApi.hpp
@@ -11,7 +11,7 @@ class HearthstoneApi {
static json makeApiRequest(const ApiUrl &iApiUrl, const std::string &iTokenText);
static std::vector<json> makeApiRequest(const std::vector<ApiUrl> &iApiUrls, const std::string &iTokenText);
static std::vector<json> makeApiRequest(const std::vector<std::string> &iUrls, const std::string &iTokenText);
- static json downloadCards(ApiUrl &iApiUrl, Token &iToken);
+ static json downloadCards(ApiUrl iApiUrl, const Token &iToken);
private:
static std::string authorizationHeader(const std::string &iTokenText);
diff --git a/battleNetApi/include/token.hpp b/battleNetApi/include/token.hpp
index 23d1f49..bcb4926 100644
--- a/battleNetApi/include/token.hpp
+++ b/battleNetApi/include/token.hpp
@@ -5,7 +5,7 @@
class Token {
public:
- Token(const std::string &iTokenFilePath);
+ explicit Token(const std::string &iTokenFilePath);
std::string text() const;
const bool hasExpired() const;
void updateToken();
diff --git a/battleNetApi/include/tokenPool.hpp b/battleNetApi/include/tokenPool.hpp
index 6f5dffc..0b1e4cc 100644
--- a/battleNetApi/include/tokenPool.hpp
+++ b/battleNetApi/include/tokenPool.hpp
@@ -3,7 +3,7 @@
#include <queue>
#include <token.hpp>
-static std::queue<Token> mTokenContainer;
+static std::queue<Token> aTokenContainer;
class TokenPool {
private:
@@ -14,6 +14,7 @@ class TokenPool {
TokenPool &operator=(TokenPool &&) = delete;
public:
- static void fillTokenSource(const std::string &iJsonPath);
- static std::optional<std::string> unusedToken();
+ static void feedTokenSource(const std::span<std::string> &iJsonPaths);
+ static void feedTokenSource(const std::string &iJsonPath);
+ static std::optional<Token> availableToken();
};
diff --git a/battleNetApi/src/apiUrl.cpp b/battleNetApi/src/apiUrl.cpp
index ac8171b..1f11add 100644
--- a/battleNetApi/src/apiUrl.cpp
+++ b/battleNetApi/src/apiUrl.cpp
@@ -1,4 +1,5 @@
#include "apiUrl.hpp"
+#include <cstdint>
#include <format>
ApiUrl::ApiUrl(const std::string &iContentType, const std::string &iRegion)
@@ -12,35 +13,36 @@ void ApiUrl::setLocale(const std::string &iLocale) {
if (not iLocale.empty()) {
//!< The locale to reflect in localized data, e.g. "fr_FR" or "ko_KR"
//!< If you do not supply a value, all translations are returned.
- const std::string kKey{"locale"};
- setValue(kKey, iLocale);
+ setValue(kLOCALE_KEY, iLocale);
}
}
void ApiUrl::setGameMode(const std::string &iGameMode) {
if (not iGameMode.empty()) {
//!< A recognized game mode, e.g. "constructed"
//!< @see https://community.developer.battle.net/documentation/hearthstone/guides/game-modes
- const std::string kKey{"gameMode"};
- setValue(kKey, iGameMode);
+ setValue(kGAME_MODE_KEY, iGameMode);
}
}
void ApiUrl::setPage(const std::string &iPage) {
if (not iPage.empty()) {
//!< The page to retrieve, e.g. "9"
- const std::string kKey{"page"};
- setValue(kKey, iPage);
+ setValue(kPAGE_KEY, iPage);
}
}
+void ApiUrl::setPage(uint64_t iPage) { setPage(std::to_string(iPage)); }
void ApiUrl::setPageSize(const std::string &iPageSize) {
if (not iPageSize.empty()) {
//!< The number of results to choose per page, e.g. "40"
- const std::string kKey{"pageSize"};
- setValue(kKey, iPageSize);
+ setValue(kPAGE_SIZE_KEY, iPageSize);
}
}
-
+void ApiUrl::setPageSize(uint64_t iPageSize) { return setPageSize(std::to_string(iPageSize)); }
+bool ApiUrl::hasLocale() const { return hasValue(kLOCALE_KEY); }
+bool ApiUrl::hasGameMode() const { return hasValue(kGAME_MODE_KEY); }
+bool ApiUrl::hasPage() const { return hasValue(kPAGE_KEY); }
+bool ApiUrl::hasPageSize() const { return hasValue(kPAGE_SIZE_KEY); }
void ApiUrl::setValue(const std::string &iKey, const std::string &iValue) { aParameters[iKey] = iValue; }
-
+bool ApiUrl::hasValue(const std::string &iKey) const { return aParameters.count(iKey) > 0; }
std::string ApiUrl::text() const {
std::string aFormattedParameters;
for (const auto &[key, value] : aParameters) {
diff --git a/battleNetApi/src/hearthstoneApi.cpp b/battleNetApi/src/hearthstoneApi.cpp
index d6becc1..133f38d 100644
--- a/battleNetApi/src/hearthstoneApi.cpp
+++ b/battleNetApi/src/hearthstoneApi.cpp
@@ -104,7 +104,10 @@ std::vector<json> HearthstoneApi::makeApiRequest(const std::vector<std::string>
return aJsonOutputs;
}
-json HearthstoneApi::downloadCards(ApiUrl &iApiUrl, Token &iToken) {
+json HearthstoneApi::downloadCards(ApiUrl iApiUrl, const Token &iToken) {
+ if (iApiUrl.hasPage()) {
+ return makeApiRequest(iApiUrl, iToken.text());
+ }
iApiUrl.setPage("1");
std::vector<std::string> aRequests;
diff --git a/battleNetApi/src/main.cpp b/battleNetApi/src/main.cpp
index 4a5594c..2b6596a 100644
--- a/battleNetApi/src/main.cpp
+++ b/battleNetApi/src/main.cpp
@@ -21,7 +21,7 @@ class DefaultDownloadMethod : public DownloadMethod {
aApiUrl.setLocale("fr_FR");
aApiUrl.setGameMode("constructed");
aApiUrl.setPageSize("100");
- std::optional<Token> aToken{TokenPool::unusedToken()};
+ std::optional<Token> aToken{TokenPool::availableToken()};
if (aToken.has_value()) {
HearthstoneApi::downloadCards(aApiUrl, aToken.value());
}
@@ -51,12 +51,12 @@ int main(int argc, char *argv[]) {
DownloaderContext aDownloaderContext;
std::string aOutputJsonPath;
if (argc < 4) {
- TokenPool::fillTokenSource("tests/resources/credentials.json");
+ TokenPool::feedTokenSource("tests/resources/credentials.json");
aDownloaderContext.setDownloadMethod(std::make_unique<DefaultDownloadMethod>());
aOutputJsonPath = "tests/output/list_of_cards.json";
} else {
std::string aCredentialsFilePath{argv[1]};
- TokenPool::fillTokenSource(aCredentialsFilePath);
+ TokenPool::feedTokenSource(aCredentialsFilePath);
aOutputJsonPath = argv[2];
}
std::ofstream aOutputJsonFile(aOutputJsonPath);
diff --git a/battleNetApi/src/tokenPool.cpp b/battleNetApi/src/tokenPool.cpp
index f8a6256..08770e8 100644
--- a/battleNetApi/src/tokenPool.cpp
+++ b/battleNetApi/src/tokenPool.cpp
@@ -1,13 +1,18 @@
#include <tokenPool.hpp>
-std::optional<std::string> TokenPool::unusedToken() {
- if (mTokenContainer.empty()) {
+std::optional<Token> TokenPool::availableToken() {
+ if (aTokenContainer.empty()) {
return std::nullopt;
}
- Token aOutputToken{mTokenContainer.front()};
- mTokenContainer.pop();
- return aOutputToken.text();
+ Token aOutputToken{aTokenContainer.front()};
+ aTokenContainer.pop();
+ return aOutputToken;
}
-void TokenPool::fillTokenSource(const std::string &iJsonPath) { // mTokenContainer.emplace(Token(iJsonPath));
+void TokenPool::feedTokenSource(const std::string &iJsonPath) { aTokenContainer.emplace(iJsonPath); }
+
+void TokenPool::feedTokenSource(const std::span<std::string> &iJsonPaths) {
+ for (const std::string &iJsonPath : iJsonPaths) {
+ feedTokenSource(iJsonPath);
+ }
}
diff --git a/battleNetApi/tests/tests.cpp b/battleNetApi/tests/tests.cpp
index e669506..5efb1f0 100644
--- a/battleNetApi/tests/tests.cpp
+++ b/battleNetApi/tests/tests.cpp
@@ -31,12 +31,13 @@ TEST_CASE("Retrieve number of cards", "[countCards]") {
aApiUrl.setLocale("fr_FR");
aApiUrl.setGameMode("constructed");
aApiUrl.setPageSize("1");
- TokenPool::fillTokenSource("tests/resources/credentials.json");
- const json kResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::unusedToken().value());
+ TokenPool::feedTokenSource("tests/resources/credentials.json");
+ const json kResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::availableToken().value().text());
REQUIRE(kResponse.size() > 0);
REQUIRE(kResponse.contains("pageCount"));
std::uint64_t kNumberOfCards{kResponse["pageCount"]};
- REQUIRE(kNumberOfCards == 6048);
+ std::uint64_t kExpectedNumberOfCards{6178};
+ REQUIRE(kNumberOfCards == kExpectedNumberOfCards);
}
TEST_CASE("Retrieve page once", "[retrievePageOnce]") {
@@ -48,8 +49,8 @@ TEST_CASE("Retrieve page once", "[retrievePageOnce]") {
aApiUrl.setLocale("fr_FR");
aApiUrl.setGameMode("constructed");
aApiUrl.setPageSize("16");
- TokenPool::fillTokenSource("tests/resources/credentials.json");
- const json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::unusedToken().value());
+ TokenPool::feedTokenSource("tests/resources/credentials.json");
+ const json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::availableToken().value().text());
REQUIRE(kApiResponse["cards"].size() == 16);
}
@@ -63,8 +64,8 @@ TEST_CASE("Retrieve pages 10 times without parallelization", "[retrievePagesNoPa
aApiUrl.setGameMode("constructed");
aApiUrl.setPageSize("16");
aApiUrl.setPage("1");
- TokenPool::fillTokenSource("tests/resources/credentials.json");
- std::string kTokenText{TokenPool::unusedToken().value()};
+ TokenPool::feedTokenSource("tests/resources/credentials.json");
+ std::string kTokenText{TokenPool::availableToken().value().text()};
json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, kTokenText);
// Retrieve number of pages
@@ -91,8 +92,8 @@ TEST_CASE("Retrieve pages 10 times with parallelization", "[retrievePagesParalle
aApiUrl.setPageSize("16");
aApiUrl.setPage("1");
std::vector<std::string> aRequests;
- TokenPool::fillTokenSource("tests/resources/credentials.json");
- std::string kTokenText{TokenPool::unusedToken().value()};
+ TokenPool::feedTokenSource("tests/resources/credentials.json");
+ std::string kTokenText{TokenPool::availableToken().value().text()};
json kFirstPageJson = HearthstoneApi::makeApiRequest(aApiUrl, kTokenText);
int kNumberOfPages{kFirstPageJson["pageCount"]};
@@ -124,3 +125,17 @@ TEST_CASE("Merge two card lists from two page requests", "[Merge pages]") {
std::ofstream aOutputJson("build/output_pages_merge.json");
aOutputJson << aMergedCards.dump(4);
}
+
+TEST_CASE("Retrieve a single page with HearthstoneApi::downloadCards", "[retrievePageOnceHearthstoneApi]") {
+ const std::string kContentType{"cards"};
+ const std::string kRegion{"eu"};
+ ApiUrl aApiUrl(kContentType, kRegion);
+ aApiUrl.setPage(3);
+ TokenPool::feedTokenSource("tests/resources/credentials.json");
+ json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::availableToken().value().text());
+ const json::size_type kExpectedNumberOfCards{kApiResponse["cards"].size()};
+ TokenPool::feedTokenSource("tests/resources/credentials.json");
+ kApiResponse = HearthstoneApi::downloadCards(aApiUrl, TokenPool::availableToken().value());
+ const json::size_type kCurrentNumberOfCards{kApiResponse["cards"].size()};
+ REQUIRE(kCurrentNumberOfCards == kExpectedNumberOfCards);
+}