Skip to content

Commit

Permalink
Use glaze for secrets and coincenter info
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Nov 20, 2024
1 parent 1d25e51 commit 9523e32
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 72 deletions.
88 changes: 38 additions & 50 deletions src/api-objects/src/apikeysprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
#include "accountowner.hpp"
#include "apikey.hpp"
#include "cct_exception.hpp"
#include "cct_json-container.hpp"
#include "cct_log.hpp"
#include "cct_string.hpp"
#include "exchangename.hpp"
#include "exchangesecretsinfo.hpp"
#include "file.hpp"
#include "read-json.hpp"
#include "runmodes.hpp"
#include "secret-schema.hpp"

namespace cct::api {
namespace {
Expand Down Expand Up @@ -73,61 +74,48 @@ APIKeysProvider::APIKeysPerExchange APIKeysProvider::ParseAPIKeys(std::string_vi
const ExchangeSecretsInfo& exchangeSecretsInfo,
settings::RunMode runMode) {
APIKeysProvider::APIKeysPerExchange apiKeysPerExchange;

if (exchangeSecretsInfo.allExchangesWithoutSecrets()) {
log::info("Not loading private keys, using only public exchanges");
} else {
std::string_view secretFileName = GetSecretFileName(runMode);
File secretsFile(dataDir, File::Type::kSecret, secretFileName,
settings::AreTestKeysRequested(runMode) ? File::IfError::kThrow : File::IfError::kNoThrow);
json::container jsonData = secretsFile.readAllJson();
bool atLeastOneKeyFound = false;
for (auto& [publicExchangeName, keyObj] : jsonData.items()) {
const auto& exchangesWithoutSecrets = exchangeSecretsInfo.exchangesWithoutSecrets();
if (std::ranges::find(exchangesWithoutSecrets, ExchangeName(publicExchangeName)) !=
exchangesWithoutSecrets.end()) {
log::info("Not loading {} private keys as requested", publicExchangeName);
return apiKeysPerExchange;
}

std::string_view secretFileName = GetSecretFileName(runMode);
const auto throwOrNoThrow = settings::AreTestKeysRequested(runMode) ? File::IfError::kThrow : File::IfError::kNoThrow;
File secretsFile(dataDir, File::Type::kSecret, secretFileName, throwOrNoThrow);

schema::APIKeysPerExchangeMap apiKeysPerExchangeMap;

ReadJsonOrThrow(secretsFile.readAll(), apiKeysPerExchangeMap);

const auto& exchangesWithoutSecrets = exchangeSecretsInfo.exchangesWithoutSecrets();

bool atLeastOneKeyFound = false;
for (auto& [exchangeNameEnum, apiKeys] : apiKeysPerExchangeMap) {
auto publicExchangeName = kSupportedExchanges[static_cast<int>(exchangeNameEnum)];
if (std::ranges::any_of(exchangesWithoutSecrets, [exchangeNameEnum](const auto& exchangeName) {
return exchangeName.exchangeNameEnum() == exchangeNameEnum;
})) {
log::debug("Not loading {} private keys as requested", publicExchangeName);
continue;
}

for (auto& [keyName, apiKey] : apiKeys) {
if (apiKey.key.empty() || apiKey.priv.empty()) {
log::error("Wrong format for secret.json file. It should contain at least fields 'key' and 'private'");
continue;
}
ExchangeNameEnum exchangeNameEnum = static_cast<ExchangeNameEnum>(
std::find(std::begin(kSupportedExchanges), std::end(kSupportedExchanges), publicExchangeName) -
std::begin(kSupportedExchanges));

for (auto& [name, keySecretObj] : keyObj.items()) {
auto keyIt = keySecretObj.find("key");
auto privateIt = keySecretObj.find("private");
if (keyIt == keySecretObj.end() || privateIt == keySecretObj.end()) {
log::error("Wrong format for secret.json file. It should contain at least fields 'key' and 'private'");
continue;
}
string passphrase;
auto passphraseIt = keySecretObj.find("passphrase");
if (passphraseIt != keySecretObj.end()) {
passphrase = std::move(passphraseIt->get_ref<string&>());
}
std::string_view ownerEnName;
std::string_view ownerKoName;
auto accountOwnerPartIt = keySecretObj.find("accountOwner");
if (accountOwnerPartIt != keySecretObj.end()) {
auto ownerEnNameIt = accountOwnerPartIt->find("enName");
if (ownerEnNameIt != accountOwnerPartIt->end()) {
ownerEnName = ownerEnNameIt->get<std::string_view>();
}
auto ownerKoNameIt = accountOwnerPartIt->find("koName");
if (ownerKoNameIt != accountOwnerPartIt->end()) {
ownerKoName = ownerKoNameIt->get<std::string_view>();
}
}

apiKeysPerExchange[static_cast<int>(exchangeNameEnum)].emplace_back(
publicExchangeName, name, std::move(keyIt->get_ref<string&>()), std::move(privateIt->get_ref<string&>()),
std::move(passphrase), AccountOwner(ownerEnName, ownerKoName));
atLeastOneKeyFound = true;
}
}
if (!atLeastOneKeyFound) {
log::warn("No private api keys file '{}' found. Only public exchange queries will be supported", secretFileName);

apiKeysPerExchange[static_cast<int>(exchangeNameEnum)].emplace_back(
publicExchangeName, keyName, std::move(apiKey.key), std::move(apiKey.priv), std::move(apiKey.passphrase),
AccountOwner(apiKey.accountOwner.enName, apiKey.accountOwner.koName));

atLeastOneKeyFound = true;
}
}
if (!atLeastOneKeyFound) {
log::warn("No private api keys file '{}' found. Only public exchange queries will be supported", secretFileName);
}

return apiKeysPerExchange;
}
Expand Down
2 changes: 1 addition & 1 deletion src/basic-objects/include/market.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ struct from<JSON, ::cct::Market> {
static void op(auto &&value, is_context auto &&, It &&it, End &&end) noexcept {
// used as a value. As a key, the first quote will not be present.
auto endIt = std::find(*it == '"' ? ++it : it, end, '"');
value = std::string_view(it, endIt);
value = ::cct::Market(std::string_view(it, endIt));
it = ++endIt;
}
};
Expand Down
43 changes: 43 additions & 0 deletions src/basic-objects/test/market_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <gtest/gtest.h>

#include "cct_exception.hpp"
#include "cct_json-serialization.hpp"
#include "currencycode.hpp"

namespace cct {
Expand Down Expand Up @@ -65,4 +66,46 @@ TEST(MarketTest, StrLen) {
market = Market("1INCH", "EUR", Market::Type::kFiatConversionMarket);
EXPECT_EQ(market.strLen(), 10);
}

struct Foo {
bool operator==(const Foo &) const noexcept = default;

Market market;
};

TEST(MarketTest, JsonSerializationValue) {
Foo foo{Market{"DOGE", "BTC"}};

string buffer;
auto res = json::write<json::opts{.raw_string = true}>(foo, buffer); // NOLINT(readability-implicit-bool-conversion)

EXPECT_FALSE(res);

EXPECT_EQ(buffer, R"({"market":"DOGE-BTC"})");
}

using MarketMap = std::map<Market, bool>;

TEST(MarketTest, JsonSerializationKey) {
MarketMap map{{Market{"DOGE", "BTC"}, true}, {Market{"BTC", "ETH"}, false}};

string buffer;
auto res = json::write<json::opts{.raw_string = true}>(map, buffer); // NOLINT(readability-implicit-bool-conversion)

EXPECT_FALSE(res);

EXPECT_EQ(buffer, R"({"BTC-ETH":false,"DOGE-BTC":true})");
}

TEST(MarketTest, JsonDeserialization) {
Foo foo;

// NOLINTNEXTLINE(readability-implicit-bool-conversion)
auto ec = json::read<json::opts{.raw_string = true}>(foo, R"({"market":"DOGE-ETH"})");

ASSERT_FALSE(ec);

EXPECT_EQ(foo, Foo{Market("DOGE", "ETH")});
}

} // namespace cct
32 changes: 11 additions & 21 deletions src/objects/src/coincenterinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
#include <utility>

#include "cct_exception.hpp"
#include "cct_json-container.hpp"
#include "cct_log.hpp"
#include "cct_string.hpp"
#include "currencycode.hpp"
#include "general-config.hpp"
#include "loadconfiguration.hpp"
#include "logginginfo.hpp"
#include "monitoringinfo.hpp"
#include "read-json.hpp"
#include "reader.hpp"
#include "runmodes.hpp"
#include "toupperlower-string.hpp"
Expand All @@ -28,26 +28,17 @@
namespace cct {

namespace {
CoincenterInfo::CurrencyEquivalentAcronymMap ComputeCurrencyEquivalentAcronymMap(
const Reader& currencyAcronymsTranslatorReader) {
json::container jsonData = currencyAcronymsTranslatorReader.readAllJson();

CoincenterInfo::CurrencyEquivalentAcronymMap ComputeCurrencyEquivalentAcronymMap(const Reader& reader) {
CoincenterInfo::CurrencyEquivalentAcronymMap map;
map.reserve(jsonData.size());
for (const auto& [key, value] : jsonData.items()) {
log::trace("Currency {} <=> {}", key, value.get<std::string_view>());
map.insert_or_assign(CurrencyCode(key), value.get<std::string_view>());
}
ReadJsonOrThrow(reader.readAll(), map);
return map;
}

CoincenterInfo::StableCoinsMap ComputeStableCoinsMap(const Reader& stableCoinsReader) {
json::container jsonData = stableCoinsReader.readAllJson();
CoincenterInfo::StableCoinsMap ret;
for (const auto& [key, value] : jsonData.items()) {
log::trace("Stable Crypto {} <=> {}", key, value.get<std::string_view>());
ret.emplace(key, value.get<std::string_view>());
}
return ret;
CoincenterInfo::StableCoinsMap ComputeStableCoinsMap(const Reader& reader) {
CoincenterInfo::StableCoinsMap map;
ReadJsonOrThrow(reader.readAll(), map);
return map;
}

#ifdef CCT_ENABLE_PROMETHEUS
Expand All @@ -73,12 +64,11 @@ CoincenterInfo::CoincenterInfo(settings::RunMode runMode, const LoadConfiguratio
? new MetricGatewayType(monitoringInfo)
: nullptr),
_monitoringInfo(std::move(monitoringInfo)) {
json::container jsonData = currencyPrefixesReader.readAllJson();
for (auto& [prefix, acronym_prefix] : jsonData.items()) {
log::trace("Currency prefix {} <=> {}", prefix, acronym_prefix.get<std::string_view>());
ReadJsonOrThrow(currencyPrefixesReader.readAll(), _currencyPrefixAcronymMap);
for (auto& [prefix, acronym_prefix] : _currencyPrefixAcronymMap) {
log::trace("Currency prefix {} <=> {}", prefix, acronym_prefix);
_minPrefixLen = std::min(_minPrefixLen, static_cast<int>(prefix.length()));
_maxPrefixLen = std::max(_maxPrefixLen, static_cast<int>(prefix.length()));
_currencyPrefixAcronymMap.insert_or_assign(ToUpper(prefix), std::move(acronym_prefix.get_ref<string&>()));
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/schema/include/read-json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ constexpr auto kJsonOptions =

template <json::opts opts = kJsonOptions>
void ReadJsonOrThrow(std::string_view strContent, auto &outObject) {
if (strContent.empty()) {
return;
}

auto ec = json::read<opts>(outObject, strContent);

if (ec) {
Expand Down
38 changes: 38 additions & 0 deletions src/schema/include/secret-schema.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <unordered_map>

#include "cct_const.hpp"
#include "cct_json-serialization.hpp"
#include "cct_string.hpp"

namespace cct::schema {

struct AccountOwner {
string enName;
string koName;

using trivially_relocatable = is_trivially_relocatable<string>::type;
};

struct APIKey {
string key;
string priv; // private is a reserved keyword - we override the json field name below
string passphrase;
AccountOwner accountOwner;

using trivially_relocatable = is_trivially_relocatable<string>::type;
};

using APIKeys = std::unordered_map<string, APIKey>;

using APIKeysPerExchangeMap = std::unordered_map<ExchangeNameEnum, APIKeys>;

} // namespace cct::schema

template <>
struct glz::meta<::cct::schema::APIKey> {
using V = ::cct::schema::APIKey;
static constexpr auto value =
object("key", &V::key, "private", &V::priv, "passphrase", &V::passphrase, "accountOwner", &V::accountOwner);
};

0 comments on commit 9523e32

Please sign in to comment.