Skip to content

Commit

Permalink
[Bithumb API] - Support integral values for 'status' return code. Whe…
Browse files Browse the repository at this point in the history
…n service is not available, it's possible to have '503' returned as integral instead of string.
  • Loading branch information
sjanel committed May 27, 2024
1 parent 0b375dd commit b4c509c
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 40 deletions.
6 changes: 5 additions & 1 deletion src/api/exchanges/include/bithumbpublicapi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ class CommonAPI;
class BithumbPublic : public ExchangePublic {
public:
static constexpr std::string_view kExchangeName = "bithumb";
static constexpr std::string_view kStatusOKStr = "0000";
static constexpr auto kStatusOK = 0;
static constexpr auto kStatusUnexpectedError = -1;
static constexpr auto kStatusNotPresentError = -2;

static int64_t StatusCodeFromJsonResponse(const json& jsonResponse);

BithumbPublic(const CoincenterInfo& config, FiatConverter& fiatConverter, CommonAPI& commonAPI);

Expand Down
22 changes: 7 additions & 15 deletions src/api/exchanges/src/bithumbprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,27 +259,18 @@ bool CheckOrderErrors(std::string_view endpoint, std::string_view msg, json& dat
return false;
}

int64_t ErrCodeFromQueryResponse(const json& queryResponse) {
auto statusCodeIt = queryResponse.find("status");
if (statusCodeIt != queryResponse.end()) {
return FromString<int64_t>(statusCodeIt->get<std::string_view>());
}
return 0;
}

json PrivateQueryProcessWithRetries(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view endpoint,
CurlOptions&& opts) {
RequestRetry requestRetry(curlHandle, std::move(opts));

json ret = requestRetry.queryJson(
endpoint,
[endpoint](json& ret) {
int64_t errorCode = ErrCodeFromQueryResponse(ret);
if (errorCode == 0) {
const auto errorCode = BithumbPublic::StatusCodeFromJsonResponse(ret);
if (errorCode == 0 || errorCode == BithumbPublic::kStatusNotPresentError) {
return RequestRetry::Status::kResponseOK;
}

// "5300" for instance. "0000" stands for: request OK
std::string_view msg;
auto messageIt = ret.find("message");
if (messageIt != ret.end()) {
Expand Down Expand Up @@ -354,12 +345,13 @@ BithumbPrivate::BithumbPrivate(const CoincenterInfo& config, BithumbPublic& bith
}

bool BithumbPrivate::validateApiKey() {
json result = PrivateQuery(_curlHandle, _apiKey, "/info/balance", CurlPostData());
if (result.is_discarded()) {
const json jsonResponse = PrivateQuery(_curlHandle, _apiKey, "/info/balance", CurlPostData());
if (jsonResponse.is_discarded()) {
return false;
}
auto statusIt = result.find("status");
return statusIt != result.end() && statusIt->get<std::string_view>() == BithumbPublic::kStatusOKStr;
const auto statusCode = BithumbPublic::StatusCodeFromJsonResponse(jsonResponse);
log::info("{} status code: {}", exchangeName(), statusCode);
return statusCode == BithumbPublic::kStatusOK;
}

BalancePortfolio BithumbPrivate::queryAccountBalance(const BalanceOptions& balanceOptions) {
Expand Down
63 changes: 39 additions & 24 deletions src/api/exchanges/src/bithumbpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,33 @@
namespace cct::api {
namespace {

json PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, CurrencyCode base,
CurrencyCode quote = CurrencyCode(), std::string_view urlOpts = "") {
string methodUrl(endpoint);
auto ComputeMethodUrl(std::string_view endpoint, CurrencyCode base, CurrencyCode quote, std::string_view urlOpts) {
string methodUrl;
methodUrl.reserve(endpoint.size() + base.size() +
static_cast<string::size_type>(quote.isDefined()) * (quote.size() + 1U) +
static_cast<string::size_type>(!urlOpts.empty()) * (urlOpts.size() + 1U));
methodUrl.append(endpoint);
base.appendStrTo(methodUrl);
if (!quote.isNeutral()) {
if (quote.isDefined()) {
methodUrl.push_back('_');
quote.appendStrTo(methodUrl);
}
if (!urlOpts.empty()) {
methodUrl.push_back('?');
methodUrl.append(urlOpts);
}
return methodUrl;
}

json PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, CurrencyCode base,
CurrencyCode quote = CurrencyCode(), std::string_view urlOpts = "") {
RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet));

json jsonResponse = requestRetry.queryJson(methodUrl, [](const json& jsonResponse) {
const auto errorIt = jsonResponse.find("status");
if (errorIt != jsonResponse.end()) {
const std::string_view statusCode = errorIt->get<std::string_view>(); // "5300" for instance
if (statusCode != BithumbPublic::kStatusOKStr) { // "0000" stands for: request OK
log::warn("Full Bithumb json error ({}): '{}'", statusCode, jsonResponse.dump());
return RequestRetry::Status::kResponseError;
}
json jsonResponse = requestRetry.queryJson(ComputeMethodUrl(endpoint, base, quote, urlOpts), [](const json& data) {
const auto statusCode = BithumbPublic::StatusCodeFromJsonResponse(data);
if (statusCode != BithumbPublic::kStatusOK) {
log::warn("Full Bithumb json error ({}): '{}'", statusCode, data.dump());
return RequestRetry::Status::kResponseError;
}
return RequestRetry::Status::kResponseOK;
});
Expand Down Expand Up @@ -99,22 +103,33 @@ BithumbPublic::BithumbPublic(const CoincenterInfo& config, FiatConverter& fiatCo
CachedResultOptions(exchangeConfig().getAPICallUpdateFrequency(kTradedVolume), _cachedResultVault),
_curlHandle) {}

int64_t BithumbPublic::StatusCodeFromJsonResponse(const json& jsonResponse) {
const auto statusIt = jsonResponse.find("status");
if (statusIt == jsonResponse.end()) {
return kStatusNotPresentError;
}
if (statusIt->is_string()) {
return FromString<int64_t>(statusIt->get<std::string_view>());
}
if (statusIt->is_number_integer()) {
return statusIt->get<int64_t>();
}
log::error("Unexpected 'status' value type - not a number nor a string");
return kStatusUnexpectedError;
}

bool BithumbPublic::healthCheck() {
static constexpr bool kAllowExceptions = false;
json result = json::parse(_curlHandle.query("/public/assetsstatus/BTC", CurlOptions(HttpRequestType::kGet)), nullptr,
kAllowExceptions);
if (result.is_discarded()) {

const json jsonResponse = json::parse(
_curlHandle.query("/public/assetsstatus/BTC", CurlOptions(HttpRequestType::kGet)), nullptr, kAllowExceptions);
if (jsonResponse.is_discarded()) {
log::error("{} health check response is badly formatted", _name);
return false;
}
auto statusIt = result.find("status");
if (statusIt == result.end()) {
log::error("Unexpected answer from {} status: {}", _name, result.dump());
return false;
}
std::string_view statusStr = statusIt->get<std::string_view>();
log::info("{} status: {}", _name, statusStr);
return statusStr == kStatusOKStr;
const auto statusCode = BithumbPublic::StatusCodeFromJsonResponse(jsonResponse);
log::info("{} status code: {}", _name, statusCode);
return statusCode == kStatusOK;
}

MarketSet BithumbPublic::queryTradableMarkets() {
Expand Down Expand Up @@ -175,7 +190,7 @@ MarketOrderBookMap GetOrderBooks(CurlHandle& curlHandle, const CoincenterInfo& c
std::optional<int> optDepth = std::nullopt) {
MarketOrderBookMap ret;
// 'all' seems to work as default for all public methods
CurrencyCode base("all");
CurrencyCode base("ALL");
CurrencyCode quote;
const bool singleMarketQuote = optM.has_value();
if (optM) {
Expand Down
1 change: 1 addition & 0 deletions src/engine/src/coincenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ int Coincenter::process(const CoincenterCommands &coincenterCommands) {
TimePoint lastCommandTime;
for (int repeatPos = 0; repeatPos != nbRepeats && g_signalStatus == 0; ++repeatPos) {
const auto earliestTimeNextCommand = lastCommandTime + repeatTime;

lastCommandTime = Clock::now();

if (earliestTimeNextCommand > lastCommandTime) {
Expand Down

0 comments on commit b4c509c

Please sign in to comment.