From a3193379b5b7d11996b978585c3fc971d97a7ac7 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Thu, 17 Dec 2020 14:12:26 -0800 Subject: [PATCH 01/18] feat: execution management coinbase --- .../CMakeLists.txt | 3 +- .../src/execution_management_simple/main.cpp | 37 +++- include/ccapi_cpp/ccapi_macro.h | 27 +++ include/ccapi_cpp/ccapi_request.h | 6 +- include/ccapi_cpp/ccapi_session.h | 6 + include/ccapi_cpp/ccapi_session_configs.h | 2 + include/ccapi_cpp/ccapi_subscription.h | 6 +- include/ccapi_cpp/ccapi_util.h | 142 +++++++++++--- .../ccapi_execution_management_service.h | 69 ++++++- ...xecution_management_service_binance_base.h | 77 ++------ ...pi_execution_management_service_coinbase.h | 185 ++++++++++++++++++ .../service/ccapi_market_data_service.h | 4 +- 12 files changed, 448 insertions(+), 116 deletions(-) create mode 100644 include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h diff --git a/example/src/execution_management_simple/CMakeLists.txt b/example/src/execution_management_simple/CMakeLists.txt index 06f19479..4b07ccc7 100644 --- a/example/src/execution_management_simple/CMakeLists.txt +++ b/example/src/execution_management_simple/CMakeLists.txt @@ -1,5 +1,6 @@ set(NAME execution_management_simple) project(${NAME}) add_definitions(-DENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_definitions(-DENABLE_EXCHANGE_BINANCE_US) +add_definitions(-DENABLE_EXCHANGE_COINBASE) +add_definitions(-DENABLE_LOG_TRACE) add_executable(${NAME} main.cpp) diff --git a/example/src/execution_management_simple/main.cpp b/example/src/execution_management_simple/main.cpp index 7a7311b6..d3f306dd 100644 --- a/example/src/execution_management_simple/main.cpp +++ b/example/src/execution_management_simple/main.cpp @@ -1,6 +1,23 @@ #include "ccapi_cpp/ccapi_session.h" namespace ccapi { -Logger* Logger::logger = nullptr; // This line is needed. +class ExampleLogger final: public Logger { + public: + virtual void logMessage(Logger::Severity severity, std::thread::id threadId, + std::chrono::system_clock::time_point time, + std::string fileName, int lineNumber, + std::string message) override { + std::lock_guard lock(m); + std::cout << threadId << ": [" << UtilTime::getISOTimestamp(time) << "] {" + << fileName << ":" << lineNumber << "} " + << Logger::severityToString(severity) << std::string(8, ' ') << message + << std::endl; +// lock.unlock(); + } + private: + std::mutex m; +}; +ExampleLogger exampleLogger; +Logger* Logger::logger = &exampleLogger; class MyEventHandler : public EventHandler { public: bool processEvent(const Event& event, Session *session) override { @@ -18,14 +35,14 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } std::string mode(argv[1]); - std::string key = UtilSystem::getEnvAsString("BINANCE_US_API_KEY"); + std::string key = UtilSystem::getEnvAsString("COINBASE_API_KEY"); if (key.empty()) { - std::cerr << "Please set environment variable BINANCE_US_API_KEY" << std::endl; + std::cerr << "Please set environment variable COINBASE_API_KEY" << std::endl; return EXIT_FAILURE; } - std::string secret = UtilSystem::getEnvAsString("BINANCE_US_API_SECRET"); + std::string secret = UtilSystem::getEnvAsString("COINBASE_API_SECRET"); if (secret.empty()) { - std::cerr << "Please set environment variable BINANCE_US_API_SECRET" << std::endl; + std::cerr << "Please set environment variable COINBASE_API_SECRET" << std::endl; return EXIT_FAILURE; } SessionOptions sessionOptions; @@ -39,7 +56,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::CREATE_ORDER, "binance-us", argv[2]); + Request request(Request::Operation::CREATE_ORDER, "coinbase", argv[2]); request.appendParam({ {"SIDE", strcmp(argv[3], "buy") == 0 ? "BUY" : "SELL"}, {"QUANTITY", argv[4]}, @@ -53,7 +70,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::CANCEL_ORDER, "binance-us", argv[2]); + Request request(Request::Operation::CANCEL_ORDER, "coinbase", argv[2]); request.appendParam({ {"ORDER_ID", argv[3]} }); @@ -65,7 +82,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::GET_ORDER, "binance-us", argv[2]); + Request request(Request::Operation::GET_ORDER, "coinbase", argv[2]); request.appendParam({ {"ORDER_ID", argv[3]} }); @@ -77,7 +94,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::GET_OPEN_ORDERS, "binance-us", argv[2]); + Request request(Request::Operation::GET_OPEN_ORDERS, "coinbase", argv[2]); session.sendRequest(request); } else if (mode == "cancel_open_orders") { if (argc != 3) { @@ -86,7 +103,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::CANCEL_OPEN_ORDERS, "binance-us", argv[2]); + Request request(Request::Operation::CANCEL_OPEN_ORDERS, "coinbase", argv[2]); session.sendRequest(request); } std::this_thread::sleep_for(std::chrono::seconds(10)); diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index c9c34b3e..88050f15 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -139,6 +139,9 @@ #ifndef CCAPI_EM_ORDER_LIMIT_PRICE #define CCAPI_EM_ORDER_LIMIT_PRICE "LIMIT_PRICE" #endif +#ifndef CCAPI_EM_ACCOUNT_ID +#define CCAPI_EM_ACCOUNT_ID "ACCOUNT_ID" +#endif #ifndef CCAPI_EM_ORDER_ID #define CCAPI_EM_ORDER_ID "ORDER_ID" #endif @@ -174,6 +177,12 @@ #ifndef CCAPI_CORRELATION_ID_GENERATED_LENGTH #define CCAPI_CORRELATION_ID_GENERATED_LENGTH 32 #endif +#ifndef CCAPI_CREDENTIAL_DISPLAY_LENGTH +#define CCAPI_CREDENTIAL_DISPLAY_LENGTH 4 +#endif +#ifndef CCAPI_COINBASE_URL_REST_BASE +#define CCAPI_COINBASE_URL_REST_BASE "https://api.pro.coinbase.com" +#endif #ifndef CCAPI_BINANCE_US_URL_REST_BASE #define CCAPI_BINANCE_US_URL_REST_BASE "https://api.binance.us" #endif @@ -192,6 +201,18 @@ #ifndef CCAPI_BINANCE_FUTURES_CREATE_ORDER_TARGET #define CCAPI_BINANCE_FUTURES_CREATE_ORDER_TARGET "/fapi/v1/order" #endif +#ifndef CCAPI_HUOBI_URL_REST_BASE +#define CCAPI_HUOBI_URL_REST_BASE "https://api.huobi.pro" +#endif +#ifndef CCAPI_COINBASE_API_KEY +#define CCAPI_COINBASE_API_KEY "COINBASE_API_KEY" +#endif +#ifndef CCAPI_COINBASE_API_SECRET +#define CCAPI_COINBASE_API_SECRET "COINBASE_API_SECRET" +#endif +#ifndef CCAPI_COINBASE_API_PASSPHRASE +#define CCAPI_COINBASE_API_PASSPHRASE "COINBASE_API_PASSPHRASE" +#endif #ifndef CCAPI_BINANCE_US_API_KEY #define CCAPI_BINANCE_US_API_KEY "BINANCE_US_API_KEY" #endif @@ -210,4 +231,10 @@ #ifndef CCAPI_BINANCE_FUTURES_API_SECRET #define CCAPI_BINANCE_FUTURES_API_SECRET "BINANCE_FUTURES_API_SECRET" #endif +#ifndef CCAPI_HUOBI_API_KEY +#define CCAPI_HUOBI_API_KEY "HOUBI_API_KEY" +#endif +#ifndef CCAPI_HUOBI_API_SECRET +#define CCAPI_HUOBI_API_SECRET "HUOBI_API_SECRET" +#endif #endif // INCLUDE_CCAPI_CPP_CCAPI_MACRO_H_ diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index 80fb5ccf..afc85fa5 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -52,9 +52,13 @@ class Request final { } } std::string toString() const { + std::map shortCredential; + for (const auto& x : credential) { + shortCredential.insert(std::make_pair(x.first, UtilString::firstNCharacter(x.second, CCAPI_CREDENTIAL_DISPLAY_LENGTH))); + } std::string output = "Request [exchange = " + exchange + ", instrument = " + instrument + ", serviceName = "+serviceName+", correlationId = " + correlationId +", paramList = "+ccapi::toString(paramList)+ ", credential = " - + ccapi::toString(credential) + ", operation = " + operationToString(operation) + "]"; + + ccapi::toString(shortCredential) + ", operation = " + operationToString(operation) + "]"; return output; } const std::string& getCorrelationId() const { diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 05ca117c..98f9e51c 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -36,6 +36,9 @@ #endif #endif #ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef ENABLE_EXCHANGE_COINBASE +#include "ccapi_cpp/service/ccapi_execution_management_service_coinbase.h" +#endif #ifdef ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_us.h" #endif @@ -133,6 +136,9 @@ class Session final { #endif #endif #ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef ENABLE_EXCHANGE_COINBASE + this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_COINBASE] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +#endif #ifdef ENABLE_EXCHANGE_BINANCE_US this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_US] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif diff --git a/include/ccapi_cpp/ccapi_session_configs.h b/include/ccapi_cpp/ccapi_session_configs.h index 4e8789ba..504dc56b 100644 --- a/include/ccapi_cpp/ccapi_session_configs.h +++ b/include/ccapi_cpp/ccapi_session_configs.h @@ -216,9 +216,11 @@ class SessionConfigs final { } } this->urlRestBase = { + { CCAPI_EXCHANGE_NAME_COINBASE, CCAPI_COINBASE_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE_US, CCAPI_BINANCE_US_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE, CCAPI_BINANCE_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE_FUTURES, CCAPI_BINANCE_FUTURES_URL_REST_BASE}, + { CCAPI_EXCHANGE_NAME_HUOBI, CCAPI_HUOBI_URL_REST_BASE}, }; } std::map > invertInstrumentSymbolMap(std::map > exchangeInstrumentSymbolMap) { diff --git a/include/ccapi_cpp/ccapi_subscription.h b/include/ccapi_cpp/ccapi_subscription.h index 03665acf..c4282e0c 100644 --- a/include/ccapi_cpp/ccapi_subscription.h +++ b/include/ccapi_cpp/ccapi_subscription.h @@ -30,10 +30,14 @@ class Subscription final { } } std::string toString() const { + std::map shortCredential; + for (const auto& x : credential) { + shortCredential.insert(std::make_pair(x.first, UtilString::firstNCharacter(x.second, CCAPI_CREDENTIAL_DISPLAY_LENGTH))); + } std::string output = "Subscription [exchange = " + exchange + ", instrument = " + instrument + ", field = " + field + ", optionMap = " + ccapi::toString(optionMap) + ", correlationId = " + correlationId + ", credential = " - + ccapi::toString(credential) + ", serviceName = " + serviceName + "]"; + + ccapi::toString(shortCredential) + ", serviceName = " + serviceName + "]"; return output; } const std::string& getCorrelationId() const { diff --git a/include/ccapi_cpp/ccapi_util.h b/include/ccapi_cpp/ccapi_util.h index 0cab685e..11e75e79 100644 --- a/include/ccapi_cpp/ccapi_util.h +++ b/include/ccapi_cpp/ccapi_util.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "date/date.h" #include "ccapi_cpp/ccapi_logger.h" namespace ccapi { @@ -156,11 +157,87 @@ class UtilTime final { }; class UtilAlgorithm final { public: + static std::string stringToHex(const std::string& input) { + static const char hex_digits[] = "0123456789ABCDEF"; + std::string output; + output.reserve(input.length() * 2); + for (unsigned char c : input) { + output.push_back(hex_digits[c >> 4]); + output.push_back(hex_digits[c & 15]); + } + return output; + } + static int hexValue(unsigned char hex_digit) { + static const signed char hex_values[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + int value = hex_values[hex_digit]; + if (value == -1) throw std::invalid_argument("invalid hex digit"); + return value; + } + std::string hexToString(const std::string& input) { + const auto len = input.length(); + if (len & 1) throw std::invalid_argument("odd length"); + std::string output; + output.reserve(len / 2); + for (auto it = input.begin(); it != input.end(); ) { + int hi = hexValue(*it++); + int lo = hexValue(*it++); + output.push_back(hi << 4 | lo); + } + return output; + } + static std::string base64Encode(const std::string &in) { + std::string out; + int val=0, valb=-6; + for (unsigned char c : in) { + val = (val<<8) + c; + valb += 8; + while (valb>=0) { + out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val>>valb)&0x3F]); + valb-=6; + } + } + if (valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val<<8)>>(valb+8))&0x3F]); + while (out.size()%4) out.push_back('='); + return out; + } + static std::string base64Decode(const std::string &in) { + std::string out; + std::vector T(256,-1); + for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; + int val=0, valb=-8; + for (unsigned char c : in) { + if (T[c] == -1) break; + val = (val<<6) + T[c]; + valb += 6; + if (valb>=0) { + out.push_back(char((val>>valb)&0xFF)); + valb-=8; + } + } + return out; + } static double exponentialBackoff(double initial, double multiplier, double base, double exponent) { return initial + multiplier * (pow(base, exponent) - 1); } template static uint_fast32_t crc(InputIterator first, InputIterator last); - static std::string hmacHex(std::string key, std::string msg) { + static std::string hmac(std::string key, std::string msg, bool returnHex = false) { unsigned char hash[32]; #if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) && OPENSSL_VERSION_MAJOR <= 1 && (OPENSSL_VERSION_MAJOR != 1 || OPENSSL_VERSION_MINOR < 1) HMAC_CTX hmac; @@ -179,13 +256,45 @@ class UtilAlgorithm final { HMAC_CTX_free(hmac); #endif std::stringstream ss; - ss << std::hex << std::setfill('0'); - for (int i = 0; i < len; i++) { - ss << std::hex << std::setw(2) << (unsigned int)hash[i]; + if (returnHex) { + ss << std::hex << std::setfill('0'); + for (int i = 0; i < len; i++) { + ss << std::hex << std::setw(2) << (unsigned int)hash[i]; + } + } else { + ss << std::setfill('0'); + for (int i = 0; i < len; i++) { + ss << hash[i]; + } } return (ss.str()); } }; +template uint_fast32_t UtilAlgorithm::crc(InputIterator first, InputIterator last) { + static auto const table = []() { + auto const reversed_polynomial = uint_fast32_t {0xEDB88320uL}; + // This is a function object that calculates the checksum for a value, + // then increments the value, starting from zero. + struct byte_checksum { + uint_fast32_t operator()() noexcept { + auto checksum = static_cast(n++); + for (auto i = 0; i < 8; ++i) + checksum = (checksum >> 1) ^ ((checksum & 0x1u) ? reversed_polynomial : 0); + return checksum; + } + unsigned n = 0; + }; + auto table = std::array {}; + std::generate(table.begin(), table.end(), byte_checksum {}); + return table; + }(); + // Calculate the checksum - make sure to clip to 32 bits, for systems that don't + // have a true (fast) 32-bit type. + return uint_fast32_t { 0xFFFFFFFFuL } + & ~std::accumulate(first, last, ~uint_fast32_t { 0 } & uint_fast32_t { 0xFFFFFFFFuL }, + [](uint_fast32_t checksum, std::uint_fast8_t value) + { return table[(checksum ^ value) & 0xFFu] ^ (checksum >> 8);}); +} class UtilSystem final { public: static bool getEnvAsBool(const std::string variableName, @@ -238,31 +347,6 @@ inline std::string size_tToString(const size_t &t) { ss << t; return ss.str(); } -template uint_fast32_t UtilAlgorithm::crc(InputIterator first, InputIterator last) { - static auto const table = []() { - auto const reversed_polynomial = uint_fast32_t {0xEDB88320uL}; - // This is a function object that calculates the checksum for a value, - // then increments the value, starting from zero. - struct byte_checksum { - uint_fast32_t operator()() noexcept { - auto checksum = static_cast(n++); - for (auto i = 0; i < 8; ++i) - checksum = (checksum >> 1) ^ ((checksum & 0x1u) ? reversed_polynomial : 0); - return checksum; - } - unsigned n = 0; - }; - auto table = std::array {}; - std::generate(table.begin(), table.end(), byte_checksum {}); - return table; - }(); - // Calculate the checksum - make sure to clip to 32 bits, for systems that don't - // have a true (fast) 32-bit type. - return uint_fast32_t { 0xFFFFFFFFuL } - & ~std::accumulate(first, last, ~uint_fast32_t { 0 } & uint_fast32_t { 0xFFFFFFFFuL }, - [](uint_fast32_t checksum, std::uint_fast8_t value) - { return table[(checksum ^ value) & 0xFFu] ^ (checksum >> 8);}); -} template std::string intToHex(T i) { std::stringstream stream; diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 045dea86..38b05a8b 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -266,7 +266,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro this->eventHandler(event); } else if (statusCode / 100 == 3) { if (resPtr->base().find("Location") != resPtr->base().end()) { - Url url(resPtr->base().at("Location").to_string()); + Url url(std::string(resPtr->base().at("Location"))); std::string host(url.host); if (!url.port.empty()) { host += ":"; @@ -326,7 +326,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro if (this->sessionOptions.enableOneHttpConnectionPerRequest || this->httpConnectionPool.empty()) { std::shared_ptr > streamPtr(nullptr); try { - streamPtr = this->createStream(this->serviceContextPtr->ioContextPtr, this->serviceContextPtr->sslContextPtr, this->host, this->port); + streamPtr = this->createStream(this->serviceContextPtr->ioContextPtr, this->serviceContextPtr->sslContextPtr, this->host); } catch (const beast::error_code& ec) { CCAPI_LOGGER_TRACE("fail"); this->onFailure(ec, "create stream"); @@ -345,7 +345,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro } std::shared_ptr > streamPtr(nullptr); try { - streamPtr = this->createStream(this->serviceContextPtr->ioContextPtr, this->serviceContextPtr->sslContextPtr, this->host, this->port); + streamPtr = this->createStream(this->serviceContextPtr->ioContextPtr, this->serviceContextPtr->sslContextPtr, this->host); } catch (const beast::error_code& ec) { CCAPI_LOGGER_TRACE("fail"); this->onFailure(ec, "create stream"); @@ -364,10 +364,10 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro } CCAPI_LOGGER_FUNCTION_EXIT; } - std::shared_ptr > createStream(std::shared_ptr iocPtr, std::shared_ptr ctxPtr, const std::string& host, const std::string& port) { + std::shared_ptr > createStream(std::shared_ptr iocPtr, std::shared_ptr ctxPtr, const std::string& host) { std::shared_ptr > streamPtr(new beast::ssl_stream (*iocPtr, *ctxPtr)); // Set SNI Hostname (many hosts need this to handshake successfully) - if (!SSL_set_tlsext_host_name(streamPtr->native_handle(), (host+":"+port).c_str())) { + if (!SSL_set_tlsext_host_name(streamPtr->native_handle(), host.c_str())) { beast::error_code ec {static_cast(::ERR_get_error()), net::error::get_ssl_category()}; CCAPI_LOGGER_DEBUG("error SSL_set_tlsext_host_name: " + ec.message()); throw ec; @@ -385,6 +385,8 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro auto operation = request.getOperation(); http::request req; req.set(http::field::host, this->host+":"+this->port); + req.set(beast::http::field::content_type, "application/json"); + req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); this->convertReq(request, now, req, credential, symbolId, operation); return req; } @@ -397,6 +399,52 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro } } } + std::string convertOrderStatus(const std::string& status) { + return this->orderStatusOpenSet.find(status) != this->orderStatusOpenSet.end() ? CCAPI_EM_ORDER_STATUS_OPEN + : CCAPI_EM_ORDER_STATUS_CLOSED; + } + virtual std::vector processSuccessfulTextMessage(const Request& request, const std::string& textMessage, const TimePoint& timeReceived) { + rj::Document document; + document.Parse(textMessage.c_str()); + Message message; + message.setTimeReceived(timeReceived); + message.setCorrelationIdList({request.getCorrelationId()}); + std::vector elementList; + Request::Operation operation = request.getOperation(); + switch (operation) { + case Request::Operation::CREATE_ORDER: + { + message.setType(Message::Type::CREATE_ORDER); + } + break; + case Request::Operation::CANCEL_ORDER: + { + message.setType(Message::Type::CANCEL_ORDER); + } + break; + case Request::Operation::GET_ORDER: + { + message.setType(Message::Type::GET_ORDER); + } + break; + case Request::Operation::GET_OPEN_ORDERS: + { + message.setType(Message::Type::GET_OPEN_ORDERS); + } + break; + case Request::Operation::CANCEL_OPEN_ORDERS: + { + message.setType(Message::Type::CANCEL_OPEN_ORDERS); + } + break; + default: + CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); + } + message.setElementList(this->extractOrderInfo(operation, document)); + std::vector messageList; + messageList.push_back(std::move(message)); + return messageList; + } Element extractOrderInfo(const rj::Value& x, const std::map >& extractionFieldNameMap) { Element element; for (const auto& y : extractionFieldNameMap) { @@ -410,6 +458,8 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro value = this->convertRestSymbolIdToInstrument(value); } else if (y.first == CCAPI_EM_ORDER_STATUS) { value = this->convertOrderStatus(value); + } else if (y.first == CCAPI_EM_ORDER_SIDE) { + value = UtilString::toLower(value).rfind("buy", 0) == 0 ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL; } element.insert(y.first, value); } @@ -417,8 +467,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro return element; } virtual void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) = 0; - virtual std::vector processSuccessfulTextMessage(const Request& request, const std::string& textMessage, const TimePoint& timeReceived) = 0; - virtual std::string convertOrderStatus(const std::string& status) = 0; + virtual std::vector extractOrderInfo(const Request::Operation operation, const rj::Document& document) = 0; std::string host; std::string port; tcp::resolver resolver; @@ -428,6 +477,12 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro std::string apiKeyName; std::string apiSecretName; std::map credentialDefault; + std::string createOrderTarget; + std::string cancelOrderTarget; + std::string getOrderTarget; + std::string getOpenOrdersTarget; + std::string cancelOpenOrdersTarget; + std::set orderStatusOpenSet; }; } /* namespace ccapi */ #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h index a0c94ec3..07370333 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h @@ -9,6 +9,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService ExecutionManagementServiceBinanceBase(std::function eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) : ExecutionManagementService(eventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { + this->orderStatusOpenSet = {"NEW", "PARTIALLY_FILLED"}; } virtual ~ExecutionManagementServiceBinanceBase() { } @@ -17,12 +18,12 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService void signRequest(std::string& queryString, const std::map& param, const TimePoint& now, const std::map& credential) { if (param.find("timestamp") == param.end()) { queryString += "timestamp="; - queryString += std::to_string(std::chrono::duration_cast< std::chrono::milliseconds >(now.time_since_epoch()).count()); + queryString += std::to_string(std::chrono::duration_cast(now.time_since_epoch()).count()); queryString += "&"; } queryString.pop_back(); auto apiSecret = mapGetWithDefault(credential, this->apiSecretName, {}); - std::string signature = UtilAlgorithm::hmacHex(apiSecret, queryString); + std::string signature = UtilAlgorithm::hmac(apiSecret, queryString, true); queryString += "&signature="; queryString += signature; } @@ -121,8 +122,8 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); } } - Element extractOrderInfo(const rj::Value& x) { - return ExecutionManagementService::extractOrderInfo(x, { + std::vector extractOrderInfo(const Request::Operation operation, const rj::Document& document) override { + const std::map >& extractionFieldNameMap = { {CCAPI_EM_ORDER_ID, std::make_pair("orderId", JsonDataType::INTEGER)}, {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("clientOrderId", JsonDataType::STRING)}, {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, @@ -132,71 +133,17 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService {CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::make_pair(this->isFutures ? "cumQuote" : "cummulativeQuoteQty", JsonDataType::STRING)}, {CCAPI_EM_ORDER_STATUS, std::make_pair("status", JsonDataType::STRING)}, {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("symbol", JsonDataType::STRING)} - }); - } - std::vector processSuccessfulTextMessage(const Request& request, const std::string& textMessage, const TimePoint& timeReceived) override { - rj::Document document; - document.Parse(textMessage.c_str()); - Message message; - message.setTimeReceived(timeReceived); - message.setCorrelationIdList({request.getCorrelationId()}); + }; std::vector elementList; - Request::Operation operation = request.getOperation(); - switch (operation) { - case Request::Operation::CREATE_ORDER: - { - message.setType(Message::Type::CREATE_ORDER); - elementList.emplace_back(this->extractOrderInfo(document)); - } - break; - case Request::Operation::CANCEL_ORDER: - { - message.setType(Message::Type::CANCEL_ORDER); - elementList.emplace_back(this->extractOrderInfo(document)); - } - break; - case Request::Operation::GET_ORDER: - { - message.setType(Message::Type::GET_ORDER); - elementList.emplace_back(this->extractOrderInfo(document)); - } - break; - case Request::Operation::GET_OPEN_ORDERS: - { - message.setType(Message::Type::GET_OPEN_ORDERS); - for (const auto& x : document.GetArray()) { - elementList.emplace_back(this->extractOrderInfo(x)); - } + if (document.IsObject()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(document, extractionFieldNameMap)); + } else { + for (const auto& x : document.GetArray()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(x, extractionFieldNameMap)); } - break; - case Request::Operation::CANCEL_OPEN_ORDERS: - { - message.setType(Message::Type::CANCEL_OPEN_ORDERS); - for (const auto& x : document.GetArray()) { - elementList.emplace_back(this->extractOrderInfo(x)); - } - } - break; - default: - CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); } - message.setElementList(elementList); - std::vector messageList; - messageList.push_back(std::move(message)); - return messageList; - } - std::string convertOrderStatus(const std::string& status) override { - return this->orderStatusOpenSet.find(status) != this->orderStatusOpenSet.end() ? CCAPI_EM_ORDER_STATUS_OPEN - : this->orderStatusClosedSet.find(status) != this->orderStatusClosedSet.end() ? CCAPI_EM_ORDER_STATUS_CLOSED - : CCAPI_EM_ORDER_STATUS_UNKNOWN; + return elementList; } - std::set orderStatusOpenSet = {"NEW", "PARTIALLY_FILLED"}; - std::set orderStatusClosedSet = {"FILLED", "CANCELED", "REJECTED", "EXPIRED"}; - std::string createOrderTarget; - std::string cancelOrderTarget; - std::string getOrderTarget; - std::string getOpenOrdersTarget; - std::string cancelOpenOrdersTarget; bool isFutures{}; }; } /* namespace ccapi */ diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h new file mode 100644 index 00000000..c29a4526 --- /dev/null +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h @@ -0,0 +1,185 @@ +#ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_COINBASE_H_ +#define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_COINBASE_H_ +#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef ENABLE_EXCHANGE_COINBASE +#include "ccapi_cpp/service/ccapi_execution_management_service.h" +namespace ccapi { +class ExecutionManagementServiceCoinbase final : public ExecutionManagementService { + public: + ExecutionManagementServiceCoinbase(std::function eventHandler, SessionOptions sessionOptions, + SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) + : ExecutionManagementService(eventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { + CCAPI_LOGGER_FUNCTION_ENTER; + this->name = CCAPI_EXCHANGE_NAME_COINBASE; + this->baseUrlRest = this->sessionConfigs.getUrlRestBase().at(this->name); + this->setHostFromUrl(this->baseUrlRest); + this->apiKeyName = CCAPI_COINBASE_API_KEY; + this->apiSecretName = CCAPI_COINBASE_API_SECRET; + this->apiPassphraseName = CCAPI_COINBASE_API_PASSPHRASE; + this->setupCredential({this->apiKeyName, this->apiSecretName, this->apiPassphraseName}); + this->createOrderTarget = "/orders"; + this->cancelOrderTarget = "/orders/{id}"; + this->getOrderTarget = "/orders/{id}"; + this->getOpenOrdersTarget = "/orders"; + this->cancelOpenOrdersTarget = "/orders"; + this->orderStatusOpenSet = {"open", "pending", "active"}; + CCAPI_LOGGER_FUNCTION_EXIT; + } + + protected: + void signRequest(http::request& req, const std::string& body, const std::map& param, const TimePoint& now, const std::map& credential) { + auto apiSecret = mapGetWithDefault(credential, this->apiSecretName, {}); + auto preSignedText = std::string(req.base().at("CB-ACCESS-TIMESTAMP")); + preSignedText += UtilString::toUpper(std::string(req.method_string())); + preSignedText += std::string(req.target()); + preSignedText += body; + CCAPI_LOGGER_TRACE("preSignedText = "+preSignedText); + std::string signature = UtilAlgorithm::base64Encode(UtilAlgorithm::hmac(UtilAlgorithm::base64Decode(apiSecret), preSignedText)); + req.set("CB-ACCESS-SIGN", signature); + req.body() = body; + req.prepare_payload(); + } + void appendParam(rj::Document& document, rj::Document::AllocatorType& allocator, const std::map& param, const std::map regularizationMap = {}) { + for (const auto& kv : param) { + auto key = regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first; + auto value = kv.second; + if (key == "side") { + value = value == CCAPI_EM_ORDER_SIDE_BUY ? "buy" : "sell"; + } + document.AddMember(rj::Value(key.c_str(), allocator).Move(), rj::Value(value.c_str(), allocator).Move(), allocator); + } + } + void appendSymbolId(rj::Document& document, rj::Document::AllocatorType& allocator, const std::string symbolId) { + document.AddMember("product_id", rj::Value(symbolId.c_str(), allocator).Move(), allocator); + } + void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) override { + auto apiKey = mapGetWithDefault(credential, this->apiKeyName, {}); + req.set("CB-ACCESS-KEY", apiKey); + req.set("CB-ACCESS-TIMESTAMP", std::to_string(std::chrono::duration_cast(now.time_since_epoch()).count())); + auto apiPassphrase = mapGetWithDefault(credential, this->apiPassphraseName, {}); + req.set("CB-ACCESS-PASSPHRASE", apiPassphrase); + switch (operation) { + case Request::Operation::CREATE_ORDER: + { + req.method(http::verb::post); + const std::map& param = request.getParamList().at(0); + req.target(this->createOrderTarget); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_ORDER_SIDE , "side"}, + {CCAPI_EM_ORDER_QUANTITY , "size"}, + {CCAPI_EM_ORDER_LIMIT_PRICE , "price"}, + {CCAPI_EM_CLIENT_ORDER_ID , "client_oid"} + }); + this->appendSymbolId(document, allocator, symbolId); + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + auto body = stringBuffer.GetString(); + this->signRequest(req, body, param, now, credential); + } + break; + case Request::Operation::CANCEL_ORDER: + { + req.method(http::verb::delete_); + const std::map& param = request.getParamList().at(0); + std::string id = param.find(CCAPI_EM_ORDER_ID) != param.end() ? param.at(CCAPI_EM_ORDER_ID) + : param.find(CCAPI_EM_CLIENT_ORDER_ID) != param.end() ? "client:" + param.at(CCAPI_EM_CLIENT_ORDER_ID) + : ""; + auto target = std::regex_replace(this->cancelOrderTarget, std::regex("\\{id\\}"), id); + if (!symbolId.empty()) { + target += "?product_id="; + target += symbolId; + } + CCAPI_LOGGER_TRACE("target = "+target); + req.target(target); + this->signRequest(req, "", param, now, credential); + } + break; + case Request::Operation::GET_ORDER: + { + req.method(http::verb::get); + const std::map& param = request.getParamList().at(0); + std::string id = param.find(CCAPI_EM_ORDER_ID) != param.end() ? param.at(CCAPI_EM_ORDER_ID) + : param.find(CCAPI_EM_CLIENT_ORDER_ID) != param.end() ? "client:" + param.at(CCAPI_EM_CLIENT_ORDER_ID) + : ""; + auto target = std::regex_replace(this->getOrderTarget, std::regex("\\{id\\}"), id); + CCAPI_LOGGER_TRACE("target = "+target); + req.target(target); + this->signRequest(req, "", param, now, credential); + } + break; + case Request::Operation::GET_OPEN_ORDERS: + { + req.method(http::verb::get); + const std::map& param = {}; + auto target = this->getOpenOrdersTarget; + if (!symbolId.empty()) { + target += "?product_id="; + target += symbolId; + } + CCAPI_LOGGER_TRACE("target = "+target); + req.target(target); + this->signRequest(req, "", param, now, credential); + } + break; + case Request::Operation::CANCEL_OPEN_ORDERS: + { + req.method(http::verb::delete_); + const std::map& param = {}; + auto target = this->cancelOpenOrdersTarget; + if (!symbolId.empty()) { + target += "?product_id="; + target += symbolId; + } + CCAPI_LOGGER_TRACE("target = "+target); + req.target(target); + this->signRequest(req, "", param, now, credential); + } + break; + default: + CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); + } + } + std::vector extractOrderInfo(const Request::Operation operation, const rj::Document& document) override { + const std::map >& extractionFieldNameMap = { + {CCAPI_EM_ORDER_ID, std::make_pair("id", JsonDataType::STRING)}, + {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("client_oid", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_QUANTITY, std::make_pair("size", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("price", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::make_pair("filled_size", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::make_pair("executed_value", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_STATUS, std::make_pair("status", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("product_id", JsonDataType::STRING)} + }; + std::vector elementList; + if (operation == Request::Operation::CANCEL_ORDER) { + Element element; + element.insert(CCAPI_EM_ORDER_ID, document.GetString()); + elementList.emplace_back(element); + } else if (operation == Request::Operation::CANCEL_OPEN_ORDERS) { + for (const auto& x : document.GetArray()) { + Element element; + element.insert(CCAPI_EM_ORDER_ID, x.GetString()); + elementList.emplace_back(element); + } + } else { + if (document.IsObject()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(document, extractionFieldNameMap)); + } else { + for (const auto& x : document.GetArray()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(x, extractionFieldNameMap)); + } + } + } + return elementList; + } + std::string apiPassphraseName; +}; +} /* namespace ccapi */ +#endif +#endif +#endif // INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_COINBASE_H_ diff --git a/include/ccapi_cpp/service/ccapi_market_data_service.h b/include/ccapi_cpp/service/ccapi_market_data_service.h index cba77b73..35f3b489 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service.h @@ -740,7 +740,7 @@ class MarketDataService : public Service, public std::enable_shared_from_thispreviousConflateSnapshotBidByConnectionIdChannelIdSymbolIdMap.at(wsConnection.id).at(channelId).at(symbolId) = "+toString(this->previousConflateSnapshotBidByConnectionIdChannelIdSymbolIdMap.at(wsConnection.id).at(channelId).at(symbolId))); CCAPI_LOGGER_TRACE("this->previousConflateSnapshotAskByConnectionIdChannelIdSymbolIdMap.at(wsConnection.id).at(channelId).at(symbolId) = "+toString(this->previousConflateSnapshotAskByConnectionIdChannelIdSymbolIdMap.at(wsConnection.id).at(channelId).at(symbolId))); TimePoint previousConflateTp = UtilTime::makeTimePointFromMilliseconds( - std::chrono::duration_cast(tp - TimePoint(std::chrono::seconds(0))).count() + std::chrono::duration_cast(tp.time_since_epoch()).count() / std::stoi(optionMap.at( CCAPI_CONFLATE_INTERVAL_MILLISECONDS)) * std::stoi(optionMap.at( CCAPI_CONFLATE_INTERVAL_MILLISECONDS))); @@ -837,7 +837,7 @@ class MarketDataService : public Service, public std::enable_shared_from_this(tp - TimePoint(std::chrono::seconds(0))).count() + std::chrono::duration_cast(tp.time_since_epoch()).count() / std::stoi(optionMap.at( CCAPI_CONFLATE_INTERVAL_MILLISECONDS)) * std::stoi(optionMap.at( CCAPI_CONFLATE_INTERVAL_MILLISECONDS))) : From 9111d506d3eada8919bf52a932ebfc29856ff95f Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Sun, 20 Dec 2020 20:50:15 -0800 Subject: [PATCH 02/18] feat: execution management gemini --- README.md | 2 - .../src/market_data_advanced/CMakeLists.txt | 6 +- example/src/market_data_simple/CMakeLists.txt | 4 +- .../src/sample_market_making/CMakeLists.txt | 6 +- include/ccapi_cpp/ccapi_hmac.h | 3001 +++++++++++++++++ include/ccapi_cpp/ccapi_macro.h | 9 + include/ccapi_cpp/ccapi_session.h | 6 + include/ccapi_cpp/ccapi_session_configs.h | 1 + include/ccapi_cpp/ccapi_util.h | 76 +- .../ccapi_execution_management_service.h | 4 +- ...xecution_management_service_binance_base.h | 12 +- ...pi_execution_management_service_coinbase.h | 14 +- ...capi_execution_management_service_gemini.h | 195 ++ test/unit_test/src/common/CMakeLists.txt | 2 +- test/unit_test/src/common/ccapi_hmac_test.cpp | 11 + test/unit_test/src/common/ccapi_util_test.cpp | 8 - .../binance_futures/CMakeLists.txt | 4 +- .../binance_us/CMakeLists.txt | 4 +- 18 files changed, 3289 insertions(+), 76 deletions(-) create mode 100644 include/ccapi_cpp/ccapi_hmac.h create mode 100644 include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h create mode 100644 test/unit_test/src/common/ccapi_hmac_test.cpp delete mode 100644 test/unit_test/src/common/ccapi_util_test.cpp diff --git a/README.md b/README.md index 6a6d8540..8f6c854a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ * Require C++14 and OpenSSL. * Definitions in the compiler command line: * Define service enablement macro `ENABLE_SERVICE_MARKET_DATA` and exchange enablement macros such as `ENABLE_EXCHANGE_COINBASE`, etc. These macros can be found at the top of `include/ccapi_cpp/ccapi_session.h`. - * If your OpenSSL version is older than 1.1, define macro `OPENSSL_VERSION_MAJOR` and `OPENSSL_VERSION_MINOR` (e.g. for OpenSSL 1.0.2s, define `OPENSSL_VERSION_MAJOR` to be 1 and `OPENSSL_VERSION_MINOR` to be 0). * Include directories: * include * dependency/websocketpp @@ -206,7 +205,6 @@ MyLogger myLogger; Logger* Logger::logger = &myLogger; } ``` -Add one of the following macros in the compiler command line: `ENABLE_LOG_TRACE`, `ENABLE_LOG_DEBUG`, `ENABLE_LOG_INFO`, `ENABLE_LOG_WARN`, `ENABLE_LOG_ERROR`, `ENABLE_LOG_FATAL`. ### Contributing * (Required) Submit a pull request to the master branch. * (Required) Pass Github checks: https://docs.github.com/en/rest/reference/checks. diff --git a/example/src/market_data_advanced/CMakeLists.txt b/example/src/market_data_advanced/CMakeLists.txt index 35bf4016..10324008 100644 --- a/example/src/market_data_advanced/CMakeLists.txt +++ b/example/src/market_data_advanced/CMakeLists.txt @@ -1,6 +1,6 @@ set(NAME market_data_advanced) project(${NAME}) -add_definitions(-DENABLE_SERVICE_MARKET_DATA) -add_definitions(-DENABLE_EXCHANGE_COINBASE) -add_definitions(-DENABLE_EXCHANGE_BINANCE_US) +add_compile_definitions(ENABLE_SERVICE_MARKET_DATA) +add_compile_definitions(ENABLE_EXCHANGE_COINBASE) +add_compile_definitions(ENABLE_EXCHANGE_BINANCE_US) add_executable(${NAME} main.cpp) diff --git a/example/src/market_data_simple/CMakeLists.txt b/example/src/market_data_simple/CMakeLists.txt index 751a2e12..3bf1f81b 100644 --- a/example/src/market_data_simple/CMakeLists.txt +++ b/example/src/market_data_simple/CMakeLists.txt @@ -1,5 +1,5 @@ set(NAME market_data_simple) project(${NAME}) -add_definitions(-DENABLE_SERVICE_MARKET_DATA) -add_definitions(-DENABLE_EXCHANGE_COINBASE) +add_compile_definitions(ENABLE_SERVICE_MARKET_DATA) +add_compile_definitions(ENABLE_EXCHANGE_COINBASE) add_executable(${NAME} main.cpp) diff --git a/example/src/sample_market_making/CMakeLists.txt b/example/src/sample_market_making/CMakeLists.txt index bd9a96b5..6faea68c 100644 --- a/example/src/sample_market_making/CMakeLists.txt +++ b/example/src/sample_market_making/CMakeLists.txt @@ -1,6 +1,6 @@ set(NAME sample_market_making) project(${NAME}) -add_definitions(-DENABLE_SERVICE_MARKET_DATA) -add_definitions(-DENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_definitions(-DENABLE_EXCHANGE_BINANCE_US) +add_compile_definitions(ENABLE_SERVICE_MARKET_DATA) +add_compile_definitions(ENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(ENABLE_EXCHANGE_BINANCE_US) add_executable(${NAME} main.cpp) diff --git a/include/ccapi_cpp/ccapi_hmac.h b/include/ccapi_cpp/ccapi_hmac.h new file mode 100644 index 00000000..3e3a942a --- /dev/null +++ b/include/ccapi_cpp/ccapi_hmac.h @@ -0,0 +1,3001 @@ +#ifndef INCLUDE_CCAPI_CPP_CCAPI_HMAC_H_ +#define INCLUDE_CCAPI_CPP_CCAPI_HMAC_H_ +//https://github.com/Yubico/yubico-c-client/blob/ykclient-2.15/hmac.c +/**************************** hmac.c ****************************/ +/******************** See RFC 4634 for details ******************/ +/* + * Description: + * This file implements the HMAC algorithm (Keyed-Hashing for + * Message Authentication, RFC2104), expressed in terms of the + * various SHA algorithms. + */ + +//#include "sha.h" +/**************************** sha.h ****************************/ +/******************* See RFC 4634 for details ******************/ +#ifndef _SHA_H_ +#define _SHA_H_ + +/* + * Description: + * This file implements the Secure Hash Signature Standard + * algorithms as defined in the National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 + * published on August 1, 2002, and the FIPS PUB 180-2 Change + * Notice published on February 28, 2004. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-2/fips180-2withchangenotice.pdf + * + * The five hashes are defined in these sizes: + * SHA-1 20 byte / 160 bit + * SHA-224 28 byte / 224 bit + * SHA-256 32 byte / 256 bit + * SHA-384 48 byte / 384 bit + * SHA-512 64 byte / 512 bit + */ + +#include +/* + * If you do not have the ISO standard stdint.h header file, then you + * must typedef the following: + * name meaning + * uint64_t unsigned 64 bit integer + * uint32_t unsigned 32 bit integer + * uint8_t unsigned 8 bit integer (i.e., unsigned char) + * int_least16_t integer of >= 16 bits + * + */ +namespace yubico { +#ifndef _SHA_enum_ +#define _SHA_enum_ +/* + * All SHA functions return one of these values. + */ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError, /* called Input after FinalBits or Result */ + shaBadParam /* passed a bad parameter */ +}; +#endif /* _SHA_enum_ */ + +/* + * These constants hold size information for each of the SHA + * hashing operations + */ +enum +{ + SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, + SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128, + SHA512_Message_Block_Size = 128, + USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, + + SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, + SHA384HashSize = 48, SHA512HashSize = 64, + USHAMaxHashSize = SHA512HashSize, + + SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, + SHA256HashSizeBits = 256, SHA384HashSizeBits = 384, + SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits +}; + +/* + * These constants are used in the USHA (unified sha) functions. + */ +typedef enum SHAversion +{ + SHA1, SHA224, SHA256, SHA384, SHA512 +} SHAversion; + +/* + * This structure will hold context information for the SHA-1 + * hashing operation. + */ +typedef struct SHA1Context +{ + uint32_t Intermediate_Hash[SHA1HashSize / 4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA1_Message_Block_Size]; + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the digest corrupted? */ +} SHA1Context; + +/* + * This structure will hold context information for the SHA-256 + * hashing operation. + */ +typedef struct SHA256Context +{ + uint32_t Intermediate_Hash[SHA256HashSize / 4]; /* Message Digest */ + + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ + + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 512-bit message blocks */ + uint8_t Message_Block[SHA256_Message_Block_Size]; + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the digest corrupted? */ +} SHA256Context; + +/* + * This structure will hold context information for the SHA-512 + * hashing operation. + */ +typedef struct SHA512Context +{ +#ifdef USE_32BIT_ONLY + uint32_t Intermediate_Hash[SHA512HashSize / 4]; /* Message Digest */ + uint32_t Length[4]; /* Message length in bits */ +#else /* !USE_32BIT_ONLY */ + uint64_t Intermediate_Hash[SHA512HashSize / 8]; /* Message Digest */ + uint64_t Length_Low, Length_High; /* Message length in bits */ +#endif /* USE_32BIT_ONLY */ + int_least16_t Message_Block_Index; /* Message_Block array index */ + /* 1024-bit message blocks */ + uint8_t Message_Block[SHA512_Message_Block_Size]; + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the digest corrupted? */ +} SHA512Context; + +/* + * This structure will hold context information for the SHA-224 + * hashing operation. It uses the SHA-256 structure for computation. + */ +typedef struct SHA256Context SHA224Context; + +/* + * This structure will hold context information for the SHA-384 + * hashing operation. It uses the SHA-512 structure for computation. + */ +typedef struct SHA512Context SHA384Context; + +/* + * This structure holds context information for all SHA + * hashing operations. + */ +typedef struct USHAContext +{ + int whichSha; /* which SHA is being used */ + union + { + SHA1Context sha1Context; + SHA224Context sha224Context; + SHA256Context sha256Context; + SHA384Context sha384Context; + SHA512Context sha512Context; + } ctx; +} USHAContext; + +/* + * This structure will hold context information for the HMAC + * keyed hashing operation. + */ +typedef struct HMACContext +{ + int whichSha; /* which SHA is being used */ + int hashSize; /* hash size of SHA being used */ + int blockSize; /* block size of SHA being used */ + USHAContext shaContext; /* SHA context */ + unsigned char k_opad[USHA_Max_Message_Block_Size]; + /* outer padding - key XORd with opad */ +} HMACContext; +/* + * Function Prototypes + */ + +/* SHA-1 */ +int SHA1Reset (SHA1Context *); +int SHA1Input (SHA1Context *, const uint8_t * bytes, + unsigned int bytecount); +int SHA1FinalBits (SHA1Context *, const uint8_t bits, + unsigned int bitcount); +int SHA1Result (SHA1Context *, uint8_t Message_Digest[SHA1HashSize]); + +/* SHA-224 */ +int SHA224Reset (SHA224Context *); +int SHA224Input (SHA224Context *, const uint8_t * bytes, + unsigned int bytecount); +int SHA224FinalBits (SHA224Context *, const uint8_t bits, + unsigned int bitcount); +int SHA224Result (SHA224Context *, + uint8_t Message_Digest[SHA224HashSize]); + +/* SHA-256 */ +int SHA256Reset (SHA256Context *); +int SHA256Input (SHA256Context *, const uint8_t * bytes, + unsigned int bytecount); +int SHA256FinalBits (SHA256Context *, const uint8_t bits, + unsigned int bitcount); +int SHA256Result (SHA256Context *, + uint8_t Message_Digest[SHA256HashSize]); + +/* SHA-384 */ +int SHA384Reset (SHA384Context *); +int SHA384Input (SHA384Context *, const uint8_t * bytes, + unsigned int bytecount); +int SHA384FinalBits (SHA384Context *, const uint8_t bits, + unsigned int bitcount); +int SHA384Result (SHA384Context *, + uint8_t Message_Digest[SHA384HashSize]); + +/* SHA-512 */ +int SHA512Reset (SHA512Context *); +int SHA512Input (SHA512Context *, const uint8_t * bytes, + unsigned int bytecount); +int SHA512FinalBits (SHA512Context *, const uint8_t bits, + unsigned int bitcount); +int SHA512Result (SHA512Context *, + uint8_t Message_Digest[SHA512HashSize]); + +/* Unified SHA functions, chosen by whichSha */ +int USHAReset (USHAContext *, SHAversion whichSha); +int USHAInput (USHAContext *, + const uint8_t * bytes, unsigned int bytecount); +int USHAFinalBits (USHAContext *, + const uint8_t bits, unsigned int bitcount); +int USHAResult (USHAContext *, + uint8_t Message_Digest[USHAMaxHashSize]); +int USHABlockSize (enum SHAversion whichSha); +int USHAHashSize (enum SHAversion whichSha); +int USHAHashSizeBits (enum SHAversion whichSha); + +/* + * HMAC Keyed-Hashing for Message Authentication, RFC2104, + * for all SHAs. + * This interface allows a fixed-length text input to be used. + */ +int hmac (SHAversion whichSha, /* which SHA algorithm to use */ + const unsigned char *text, /* pointer to data stream */ + int text_len, /* length of data stream */ + const unsigned char *key, /* pointer to authentication key */ + int key_len, /* length of authentication key */ + uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ + +/* + * HMAC Keyed-Hashing for Message Authentication, RFC2104, + * for all SHAs. + * This interface allows any length of text input to be used. + */ +int hmacReset (HMACContext * ctx, enum SHAversion whichSha, + const unsigned char *key, int key_len); +int hmacInput (HMACContext * ctx, const unsigned char *text, + int text_len); + +int hmacFinalBits (HMACContext * ctx, const uint8_t bits, + unsigned int bitcount); +int hmacResult (HMACContext * ctx, uint8_t digest[USHAMaxHashSize]); + +#endif /* _SHA_H_ */ +/*************************** sha-private.h ***************************/ +/********************** See RFC 4634 for details *********************/ +#ifndef _SHA_PRIVATE__H +#define _SHA_PRIVATE__H +/* + * These definitions are defined in FIPS-180-2, section 4.1. + * Ch() and Maj() are defined identically in sections 4.1.1, + * 4.1.2 and 4.1.3. + * + * The definitions used in FIPS-180-2 are as follows: + */ + +#ifndef USE_MODIFIED_MACROS +#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#else /* USE_MODIFIED_MACROS */ +/* + * The following definitions are equivalent and potentially faster. + */ + +#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) +#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#endif /* USE_MODIFIED_MACROS */ + +#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) + +#endif /* _SHA_PRIVATE__H */ +/**************************** sha1.c ****************************/ +/******************** See RFC 4634 for details ******************/ +/* + * Description: + * This file implements the Secure Hash Signature Standard + * algorithms as defined in the National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 + * published on August 1, 2002, and the FIPS PUB 180-2 Change + * Notice published on February 28, 2004. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-2/fips180-2withchangenotice.pdf + * + * The SHA-1 algorithm produces a 160-bit message digest for a + * given data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha.h") to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. This implementation uses SHA1Input() to hash the bits + * that are a multiple of the size of an 8-bit character, and then + * uses SHA1FinalBits() to hash the final few bits of the input. + */ + +//#include "sha.h" +//#include "sha-private.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1_ROTL(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* + * add "length" to the length + */ +static uint32_t addTemp1; +#define SHA1AddLength(context, length) \ + (addTemp1 = (context)->Length_Low, \ + (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp1) && \ + (++(context)->Length_High == 0) ? 1 : 0) + +/* Local Function Prototypes */ +static void SHA1Finalize (SHA1Context * context, uint8_t Pad_Byte); +static void SHA1PadMessage (SHA1Context *, uint8_t Pad_Byte); +static void SHA1ProcessMessageBlock (SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int +SHA1Reset (SHA1Context * context) +{ + if (!context) + return shaNull; + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + /* Initial Hash Values: FIPS-180-2 section 5.3.1 */ + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int +SHA1Input (SHA1Context * context, + const uint8_t * message_array, unsigned length) +{ + if (!length) + return shaSuccess; + + if (!context || !message_array) + return shaNull; + + if (context->Computed) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + while (length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + if (!SHA1AddLength (context, 8) && + (context->Message_Block_Index == SHA1_Message_Block_Size)) + SHA1ProcessMessageBlock (context); + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int +SHA1FinalBits (SHA1Context * context, const uint8_t message_bits, + unsigned int length) +{ + uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!length) + return shaSuccess; + + if (!context) + return shaNull; + + if (context->Computed || (length >= 8) || (length == 0)) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + SHA1AddLength (context, length); + SHA1Finalize (context, + (uint8_t) ((message_bits & masks[length]) | markbit[length])); + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int +SHA1Result (SHA1Context * context, uint8_t Message_Digest[SHA1HashSize]) +{ + int i; + + if (!context || !Message_Digest) + return shaNull; + + if (context->Corrupted) + return context->Corrupted; + + if (!context->Computed) + SHA1Finalize (context, 0x80); + + for (i = 0; i < SHA1HashSize; ++i) + Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i >> 2] + >> 8 * (3 - (i & 0x03))); + + return shaSuccess; +} + +/* + * SHA1Finalize + * + * Description: + * This helper function finishes off the digest calculations. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * Pad_Byte: [in] + * The last byte to add to the digest before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * sha Error Code. + * + */ +static void +SHA1Finalize (SHA1Context * context, uint8_t Pad_Byte) +{ + int i; + SHA1PadMessage (context, Pad_Byte); + /* message may be sensitive, clear it out */ + for (i = 0; i < SHA1_Message_Block_Size; ++i) + context->Message_Block[i] = 0; + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; +} + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an + * even 512 bits. The first padding bit must be a '1'. The last + * 64 bits represent the length of the original message. All bits + * in between should be 0. This helper function will pad the + * message according to those rules by filling the Message_Block + * array accordingly. When it returns, it can be assumed that the + * message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * Pad_Byte: [in] + * The last byte to add to the digest before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * Nothing. + */ +static void +SHA1PadMessage (SHA1Context * context, uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) + { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA1_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + + SHA1ProcessMessageBlock (context); + } + else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t) (context->Length_High >> 24); + context->Message_Block[57] = (uint8_t) (context->Length_High >> 16); + context->Message_Block[58] = (uint8_t) (context->Length_High >> 8); + context->Message_Block[59] = (uint8_t) (context->Length_High); + context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t) (context->Length_Low); + + SHA1ProcessMessageBlock (context); +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This helper function will process the next 512 bits of the + * message stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + */ +static void +SHA1ProcessMessageBlock (SHA1Context * context) +{ + /* Constants defined in FIPS-180-2, section 4.2.1 */ + const uint32_t K[4] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32_t temp; /* Temporary word value */ + uint32_t W[80]; /* Word sequence */ + uint32_t A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = 0; t < 16; t++) + { + W[t] = ((uint32_t) context->Message_Block[t * 4]) << 24; + W[t] |= ((uint32_t) context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((uint32_t) context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((uint32_t) context->Message_Block[t * 4 + 3]); + } + for (t = 16; t < 80; t++) + W[t] = SHA1_ROTL (1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for (t = 0; t < 20; t++) + { + temp = SHA1_ROTL (5, A) + SHA_Ch (B, C, D) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1_ROTL (30, B); + B = A; + A = temp; + } + + for (t = 20; t < 40; t++) + { + temp = SHA1_ROTL (5, A) + SHA_Parity (B, C, D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1_ROTL (30, B); + B = A; + A = temp; + } + + for (t = 40; t < 60; t++) + { + temp = SHA1_ROTL (5, A) + SHA_Maj (B, C, D) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1_ROTL (30, B); + B = A; + A = temp; + } + + for (t = 60; t < 80; t++) + { + temp = SHA1_ROTL (5, A) + SHA_Parity (B, C, D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1_ROTL (30, B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} +/*************************** sha224-256.c ***************************/ +/********************* See RFC 4634 for details *********************/ +/* + * Description: + * This file implements the Secure Hash Signature Standard + * algorithms as defined in the National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 + * published on August 1, 2002, and the FIPS PUB 180-2 Change + * Notice published on February 28, 2004. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-2/fips180-2withchangenotice.pdf + * + * The SHA-224 and SHA-256 algorithms produce 224-bit and 256-bit + * message digests for a given data stream. It should take about + * 2**n steps to find a message with the same digest as a given + * message and 2**(n/2) to find any two messages with the same + * digest, when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-224 and SHA-256 are defined in terms of 32-bit "words". + * This code uses (included via "sha.h") to define 32 + * and 8 bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-224 and SHA-256 are designed to work with messages less + * than 2^64 bits long. This implementation uses SHA224/256Input() + * to hash the bits that are a multiple of the size of an 8-bit + * character, and then uses SHA224/256FinalBits() to hash the + * final few bits of the input. + */ + +//#include "sha.h" +//#include "sha-private.h" +/* Define the SHA shift, rotate left and rotate right macro */ +#define SHA256_SHR(bits,word) ((word) >> (bits)) +#define SHA256_ROTL(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) +#define SHA256_ROTR(bits,word) \ + (((word) >> (bits)) | ((word) << (32-(bits)))) + +/* Define the SHA SIGMA and sigma macros */ +#define SHA256_SIGMA0(word) \ + (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) +#define SHA256_SIGMA1(word) \ + (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) +#define SHA256_sigma0(word) \ + (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) +#define SHA256_sigma1(word) \ + (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) + +/* + * add "length" to the length + */ +static uint32_t addTemp2; +#define SHA224_256AddLength(context, length) \ + (addTemp2 = (context)->Length_Low, (context)->Corrupted = \ + (((context)->Length_Low += (length)) < addTemp2) && \ + (++(context)->Length_High == 0) ? 1 : 0) + +/* Local Function Prototypes */ +static void SHA224_256Finalize (SHA256Context * context, uint8_t Pad_Byte); +static void SHA224_256PadMessage (SHA256Context * context, uint8_t Pad_Byte); +static void SHA224_256ProcessMessageBlock (SHA256Context * context); +static int SHA224_256Reset (SHA256Context * context, uint32_t * H0); +static int SHA224_256ResultN (SHA256Context * context, + uint8_t Message_Digest[], int HashSize); + +/* Initial Hash Values: FIPS-180-2 Change Notice 1 */ +static uint32_t SHA224_H0[SHA256HashSize / 4] = { + 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 +}; + +/* Initial Hash Values: FIPS-180-2 section 5.3.2 */ +static uint32_t SHA256_H0[SHA256HashSize / 4] = { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 +}; + +/* + * SHA224Reset + * + * Description: + * This function will initialize the SHA384Context in preparation + * for computing a new SHA224 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + */ +int +SHA224Reset (SHA224Context * context) +{ + return SHA224_256Reset (context, SHA224_H0); +} + +/* + * SHA224Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int +SHA224Input (SHA224Context * context, const uint8_t * message_array, + unsigned int length) +{ + return SHA256Input (context, message_array, length); +} + +/* + * SHA224FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int +SHA224FinalBits (SHA224Context * context, + const uint8_t message_bits, unsigned int length) +{ + return SHA256FinalBits (context, message_bits, length); +} + +/* + * SHA224Result + * + * Description: + * This function will return the 224-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 28th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + */ +int +SHA224Result (SHA224Context * context, uint8_t Message_Digest[SHA224HashSize]) +{ + return SHA224_256ResultN (context, Message_Digest, SHA224HashSize); +} + +/* + * SHA256Reset + * + * Description: + * This function will initialize the SHA256Context in preparation + * for computing a new SHA256 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + */ +int +SHA256Reset (SHA256Context * context) +{ + return SHA224_256Reset (context, SHA256_H0); +} + +/* + * SHA256Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + */ +int +SHA256Input (SHA256Context * context, const uint8_t * message_array, + unsigned int length) +{ + if (!length) + return shaSuccess; + + if (!context || !message_array) + return shaNull; + + if (context->Computed) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + while (length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + if (!SHA224_256AddLength (context, 8) && + (context->Message_Block_Index == SHA256_Message_Block_Size)) + SHA224_256ProcessMessageBlock (context); + + message_array++; + } + + return shaSuccess; + +} + +/* + * SHA256FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int +SHA256FinalBits (SHA256Context * context, + const uint8_t message_bits, unsigned int length) +{ + uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!length) + return shaSuccess; + + if (!context) + return shaNull; + + if ((context->Computed) || (length >= 8) || (length == 0)) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + SHA224_256AddLength (context, length); + SHA224_256Finalize (context, (uint8_t) + ((message_bits & masks[length]) | markbit[length])); + + return shaSuccess; +} + +/* + * SHA256Result + * + * Description: + * This function will return the 256-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 32nd element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + */ +int +SHA256Result (SHA256Context * context, uint8_t Message_Digest[]) +{ + return SHA224_256ResultN (context, Message_Digest, SHA256HashSize); +} + +/* + * SHA224_256Finalize + * + * Description: + * This helper function finishes off the digest calculations. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * Pad_Byte: [in] + * The last byte to add to the digest before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * sha Error Code. + */ +static void +SHA224_256Finalize (SHA256Context * context, uint8_t Pad_Byte) +{ + int i; + SHA224_256PadMessage (context, Pad_Byte); + /* message may be sensitive, so clear it out */ + for (i = 0; i < SHA256_Message_Block_Size; ++i) + context->Message_Block[i] = 0; + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; +} + +/* + * SHA224_256PadMessage + * + * Description: + * According to the standard, the message must be padded to an + * even 512 bits. The first padding bit must be a '1'. The + * last 64 bits represent the length of the original message. + * All bits in between should be 0. This helper function will pad + * the message according to those rules by filling the + * Message_Block array accordingly. When it returns, it can be + * assumed that the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * Pad_Byte: [in] + * The last byte to add to the digest before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * Nothing. + */ +static void +SHA224_256PadMessage (SHA256Context * context, uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA256_Message_Block_Size - 8)) + { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA256_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + SHA224_256ProcessMessageBlock (context); + } + else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA256_Message_Block_Size - 8)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (uint8_t) (context->Length_High >> 24); + context->Message_Block[57] = (uint8_t) (context->Length_High >> 16); + context->Message_Block[58] = (uint8_t) (context->Length_High >> 8); + context->Message_Block[59] = (uint8_t) (context->Length_High); + context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24); + context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16); + context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8); + context->Message_Block[63] = (uint8_t) (context->Length_Low); + + SHA224_256ProcessMessageBlock (context); +} + +/* + * SHA224_256ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + */ +static void +SHA224_256ProcessMessageBlock (SHA256Context * context) +{ + /* Constants defined in FIPS-180-2, section 4.2.2 */ + static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, + 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, + 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, + 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, + 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, + 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, + 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, + 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, + 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + int t, t4; /* Loop counter */ + uint32_t temp1, temp2; /* Temporary word value */ + uint32_t W[64]; /* Word sequence */ + uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = t4 = 0; t < 16; t++, t4 += 4) + W[t] = (((uint32_t) context->Message_Block[t4]) << 24) | + (((uint32_t) context->Message_Block[t4 + 1]) << 16) | + (((uint32_t) context->Message_Block[t4 + 2]) << 8) | + (((uint32_t) context->Message_Block[t4 + 3])); + + for (t = 16; t < 64; t++) + W[t] = SHA256_sigma1 (W[t - 2]) + W[t - 7] + + SHA256_sigma0 (W[t - 15]) + W[t - 16]; + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + F = context->Intermediate_Hash[5]; + G = context->Intermediate_Hash[6]; + H = context->Intermediate_Hash[7]; + + for (t = 0; t < 64; t++) + { + temp1 = H + SHA256_SIGMA1 (E) + SHA_Ch (E, F, G) + K[t] + W[t]; + temp2 = SHA256_SIGMA0 (A) + SHA_Maj (A, B, C); + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Intermediate_Hash[5] += F; + context->Intermediate_Hash[6] += G; + context->Intermediate_Hash[7] += H; + + context->Message_Block_Index = 0; +} + +/* + * SHA224_256Reset + * + * Description: + * This helper function will initialize the SHA256Context in + * preparation for computing a new SHA256 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * H0 + * The initial hash value to use. + * + * Returns: + * sha Error Code. + */ +static int +SHA224_256Reset (SHA256Context * context, uint32_t * H0) +{ + if (!context) + return shaNull; + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = H0[0]; + context->Intermediate_Hash[1] = H0[1]; + context->Intermediate_Hash[2] = H0[2]; + context->Intermediate_Hash[3] = H0[3]; + context->Intermediate_Hash[4] = H0[4]; + context->Intermediate_Hash[5] = H0[5]; + context->Intermediate_Hash[6] = H0[6]; + context->Intermediate_Hash[7] = H0[7]; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA224_256ResultN + * + * Description: + * This helper function will return the 224-bit or 256-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 28th/32nd element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest: [out] + * Where the digest is returned. + * HashSize: [in] + * The size of the hash, either 28 or 32. + * + * Returns: + * sha Error Code. + */ +static int +SHA224_256ResultN (SHA256Context * context, + uint8_t Message_Digest[], int HashSize) +{ + int i; + + if (!context || !Message_Digest) + return shaNull; + + if (context->Corrupted) + return context->Corrupted; + + if (!context->Computed) + SHA224_256Finalize (context, 0x80); + + for (i = 0; i < HashSize; ++i) + Message_Digest[i] = (uint8_t) + (context->Intermediate_Hash[i >> 2] >> 8 * (3 - (i & 0x03))); + + return shaSuccess; +} +/*************************** sha384-512.c ***************************/ +/********************* See RFC 4634 for details *********************/ +/* + * Description: + * This file implements the Secure Hash Signature Standard + * algorithms as defined in the National Institute of Standards + * and Technology Federal Information Processing Standards + * Publication (FIPS PUB) 180-1 published on April 17, 1995, 180-2 + * published on August 1, 2002, and the FIPS PUB 180-2 Change + * Notice published on February 28, 2004. + * + * A combined document showing all algorithms is available at + * http://csrc.nist.gov/publications/fips/ + * fips180-2/fips180-2withchangenotice.pdf + * + * The SHA-384 and SHA-512 algorithms produce 384-bit and 512-bit + * message digests for a given data stream. It should take about + * 2**n steps to find a message with the same digest as a given + * message and 2**(n/2) to find any two messages with the same + * digest, when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-384 and SHA-512 are defined in terms of 64-bit "words", + * but if USE_32BIT_ONLY is #defined, this code is implemented in + * terms of 32-bit "words". This code uses (included + * via "sha.h") to define the 64, 32 and 8 bit unsigned integer + * types. If your C compiler does not support 64 bit unsigned + * integers, and you do not #define USE_32BIT_ONLY, this code is + * not appropriate. + * + * Caveats: + * SHA-384 and SHA-512 are designed to work with messages less + * than 2^128 bits long. This implementation uses + * SHA384/512Input() to hash the bits that are a multiple of the + * size of an 8-bit character, and then uses SHA384/256FinalBits() + * to hash the final few bits of the input. + * + */ + +//#include "sha.h" +//#include "sha-private.h" + +#ifdef USE_32BIT_ONLY +/* + * Define 64-bit arithmetic in terms of 32-bit arithmetic. + * Each 64-bit number is represented in a 2-word array. + * All macros are defined such that the result is the last parameter. + */ + +/* + * Define shift, rotate left and rotate right functions + */ +#define SHA512_SHR(bits, word, ret) ( \ + /* (((uint64_t)((word))) >> (bits)) */ \ + (ret)[0] = (((bits) < 32) && ((bits) >= 0)) ? \ + ((word)[0] >> (bits)) : 0, \ + (ret)[1] = ((bits) > 32) ? ((word)[0] >> ((bits) - 32)) : \ + ((bits) == 32) ? (word)[0] : \ + ((bits) >= 0) ? \ + (((word)[0] << (32 - (bits))) | \ + ((word)[1] >> (bits))) : 0 ) + +#define SHA512_SHL(bits, word, ret) ( \ + /* (((uint64_t)(word)) << (bits)) */ \ + (ret)[0] = ((bits) > 32) ? ((word)[1] << ((bits) - 32)) : \ + ((bits) == 32) ? (word)[1] : \ + ((bits) >= 0) ? \ + (((word)[0] << (bits)) | \ + ((word)[1] >> (32 - (bits)))) : \ + 0, \ + (ret)[1] = (((bits) < 32) && ((bits) >= 0)) ? \ + ((word)[1] << (bits)) : 0 ) + +/* + * Define 64-bit OR + */ +#define SHA512_OR(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] | (word2)[0], \ + (ret)[1] = (word1)[1] | (word2)[1] ) + +/* + * Define 64-bit XOR + */ +#define SHA512_XOR(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] ^ (word2)[0], \ + (ret)[1] = (word1)[1] ^ (word2)[1] ) + +/* + * Define 64-bit AND + */ +#define SHA512_AND(word1, word2, ret) ( \ + (ret)[0] = (word1)[0] & (word2)[0], \ + (ret)[1] = (word1)[1] & (word2)[1] ) + +/* + * Define 64-bit TILDA + */ +#define SHA512_TILDA(word, ret) \ + ( (ret)[0] = ~(word)[0], (ret)[1] = ~(word)[1] ) + +/* + * Define 64-bit ADD + */ +#define SHA512_ADD(word1, word2, ret) ( \ + (ret)[1] = (word1)[1], (ret)[1] += (word2)[1], \ + (ret)[0] = (word1)[0] + (word2)[0] + ((ret)[1] < (word1)[1]) ) + +/* + * Add the 4word value in word2 to word1. + */ +static uint32_t ADDTO4_temp, ADDTO4_temp2; +#define SHA512_ADDTO4(word1, word2) ( \ + ADDTO4_temp = (word1)[3], \ + (word1)[3] += (word2)[3], \ + ADDTO4_temp2 = (word1)[2], \ + (word1)[2] += (word2)[2] + ((word1)[3] < ADDTO4_temp), \ + ADDTO4_temp = (word1)[1], \ + (word1)[1] += (word2)[1] + ((word1)[2] < ADDTO4_temp2), \ + (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO4_temp) ) + +/* + * Add the 2word value in word2 to word1. + */ +static uint32_t ADDTO2_temp; +#define SHA512_ADDTO2(word1, word2) ( \ + ADDTO2_temp = (word1)[1], \ + (word1)[1] += (word2)[1], \ + (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO2_temp) ) + +/* + * SHA rotate ((word >> bits) | (word << (64-bits))) + */ +static uint32_t ROTR_temp1[2], ROTR_temp2[2]; +#define SHA512_ROTR(bits, word, ret) ( \ + SHA512_SHR((bits), (word), ROTR_temp1), \ + SHA512_SHL(64-(bits), (word), ROTR_temp2), \ + SHA512_OR(ROTR_temp1, ROTR_temp2, (ret)) ) + +/* + * Define the SHA SIGMA and sigma macros + * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word) + */ +static uint32_t SIGMA0_temp1[2], SIGMA0_temp2[2], + SIGMA0_temp3[2], SIGMA0_temp4[2]; +#define SHA512_SIGMA0(word, ret) ( \ + SHA512_ROTR(28, (word), SIGMA0_temp1), \ + SHA512_ROTR(34, (word), SIGMA0_temp2), \ + SHA512_ROTR(39, (word), SIGMA0_temp3), \ + SHA512_XOR(SIGMA0_temp2, SIGMA0_temp3, SIGMA0_temp4), \ + SHA512_XOR(SIGMA0_temp1, SIGMA0_temp4, (ret)) ) + +/* + * SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word) + */ +static uint32_t SIGMA1_temp1[2], SIGMA1_temp2[2], + SIGMA1_temp3[2], SIGMA1_temp4[2]; +#define SHA512_SIGMA1(word, ret) ( \ + SHA512_ROTR(14, (word), SIGMA1_temp1), \ + SHA512_ROTR(18, (word), SIGMA1_temp2), \ + SHA512_ROTR(41, (word), SIGMA1_temp3), \ + SHA512_XOR(SIGMA1_temp2, SIGMA1_temp3, SIGMA1_temp4), \ + SHA512_XOR(SIGMA1_temp1, SIGMA1_temp4, (ret)) ) + +/* + * (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) + */ +static uint32_t sigma0_temp1[2], sigma0_temp2[2], + sigma0_temp3[2], sigma0_temp4[2]; +#define SHA512_sigma0(word, ret) ( \ + SHA512_ROTR( 1, (word), sigma0_temp1), \ + SHA512_ROTR( 8, (word), sigma0_temp2), \ + SHA512_SHR( 7, (word), sigma0_temp3), \ + SHA512_XOR(sigma0_temp2, sigma0_temp3, sigma0_temp4), \ + SHA512_XOR(sigma0_temp1, sigma0_temp4, (ret)) ) + +/* + * (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) + */ +static uint32_t sigma1_temp1[2], sigma1_temp2[2], + sigma1_temp3[2], sigma1_temp4[2]; +#define SHA512_sigma1(word, ret) ( \ + SHA512_ROTR(19, (word), sigma1_temp1), \ + SHA512_ROTR(61, (word), sigma1_temp2), \ + SHA512_SHR( 6, (word), sigma1_temp3), \ + SHA512_XOR(sigma1_temp2, sigma1_temp3, sigma1_temp4), \ + SHA512_XOR(sigma1_temp1, sigma1_temp4, (ret)) ) + +#undef SHA_Ch +#undef SHA_Maj + +#ifndef USE_MODIFIED_MACROS +/* + * These definitions are the ones used in FIPS-180-2, section 4.1.3 + * Ch(x,y,z) ((x & y) ^ (~x & z)) + */ +static uint32_t Ch_temp1[2], Ch_temp2[2], Ch_temp3[2]; +#define SHA_Ch(x, y, z, ret) ( \ + SHA512_AND(x, y, Ch_temp1), \ + SHA512_TILDA(x, Ch_temp2), \ + SHA512_AND(Ch_temp2, z, Ch_temp3), \ + SHA512_XOR(Ch_temp1, Ch_temp3, (ret)) ) +/* + * Maj(x,y,z) (((x)&(y)) ^ ((x)&(z)) ^ ((y)&(z))) + */ +static uint32_t Maj_temp1[2], Maj_temp2[2], Maj_temp3[2], Maj_temp4[2]; +#define SHA_Maj(x, y, z, ret) ( \ + SHA512_AND(x, y, Maj_temp1), \ + SHA512_AND(x, z, Maj_temp2), \ + SHA512_AND(y, z, Maj_temp3), \ + SHA512_XOR(Maj_temp2, Maj_temp3, Maj_temp4), \ + SHA512_XOR(Maj_temp1, Maj_temp4, (ret)) ) + +#else /* !USE_32BIT_ONLY */ +/* + * These definitions are potentially faster equivalents for the ones + * used in FIPS-180-2, section 4.1.3. + * ((x & y) ^ (~x & z)) becomes + * ((x & (y ^ z)) ^ z) + */ +#define SHA_Ch(x, y, z, ret) ( \ + (ret)[0] = (((x)[0] & ((y)[0] ^ (z)[0])) ^ (z)[0]), \ + (ret)[1] = (((x)[1] & ((y)[1] ^ (z)[1])) ^ (z)[1]) ) + +/* + * ((x & y) ^ (x & z) ^ (y & z)) becomes + * ((x & (y | z)) | (y & z)) + */ +#define SHA_Maj(x, y, z, ret) ( \ + ret[0] = (((x)[0] & ((y)[0] | (z)[0])) | ((y)[0] & (z)[0])), \ + ret[1] = (((x)[1] & ((y)[1] | (z)[1])) | ((y)[1] & (z)[1])) ) +#endif /* USE_MODIFIED_MACROS */ + +/* + * add "length" to the length + */ +static uint32_t addTemp3[4] = { 0, 0, 0, 0 }; + +#define SHA384_512AddLength(context, length) ( \ + addTemp3[3] = (length), SHA512_ADDTO4((context)->Length, addTemp3), \ + (context)->Corrupted = (((context)->Length[3] == 0) && \ + ((context)->Length[2] == 0) && ((context)->Length[1] == 0) && \ + ((context)->Length[0] < 8)) ? 1 : 0 ) + +/* Local Function Prototypes */ +static void SHA384_512Finalize (SHA512Context * context, uint8_t Pad_Byte); +static void SHA384_512PadMessage (SHA512Context * context, uint8_t Pad_Byte); +static void SHA384_512ProcessMessageBlock (SHA512Context * context); +static int SHA384_512Reset (SHA512Context * context, uint32_t H0[]); +static int SHA384_512ResultN (SHA512Context * context, + uint8_t Message_Digest[], int HashSize); + +/* Initial Hash Values: FIPS-180-2 sections 5.3.3 and 5.3.4 */ +static uint32_t SHA384_H0[SHA512HashSize / 4] = { + 0xCBBB9D5D, 0xC1059ED8, 0x629A292A, 0x367CD507, 0x9159015A, + 0x3070DD17, 0x152FECD8, 0xF70E5939, 0x67332667, 0xFFC00B31, + 0x8EB44A87, 0x68581511, 0xDB0C2E0D, 0x64F98FA7, 0x47B5481D, + 0xBEFA4FA4 +}; + +static uint32_t SHA512_H0[SHA512HashSize / 4] = { + 0x6A09E667, 0xF3BCC908, 0xBB67AE85, 0x84CAA73B, 0x3C6EF372, + 0xFE94F82B, 0xA54FF53A, 0x5F1D36F1, 0x510E527F, 0xADE682D1, + 0x9B05688C, 0x2B3E6C1F, 0x1F83D9AB, 0xFB41BD6B, 0x5BE0CD19, + 0x137E2179 +}; + +#else /* !USE_32BIT_ONLY */ + +/* Define the SHA shift, rotate left and rotate right macro */ +#define SHA512_SHR(bits,word) (((uint64_t)(word)) >> (bits)) +#define SHA512_ROTR(bits,word) ((((uint64_t)(word)) >> (bits)) | \ + (((uint64_t)(word)) << (64-(bits)))) + +/* Define the SHA SIGMA and sigma macros */ +#define SHA512_SIGMA0(word) \ + (SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word)) +#define SHA512_SIGMA1(word) \ + (SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word)) +#define SHA512_sigma0(word) \ + (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) +#define SHA512_sigma1(word) \ + (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) + +/* + * add "length" to the length + */ +static uint64_t addTemp4; +#define SHA384_512AddLength(context, length) \ + (addTemp4 = context->Length_Low, context->Corrupted = \ + ((context->Length_Low += length) < addTemp4) && \ + (++context->Length_High == 0) ? 1 : 0) + +/* Local Function Prototypes */ +static void SHA384_512Finalize (SHA512Context * context, uint8_t Pad_Byte); +static void SHA384_512PadMessage (SHA512Context * context, uint8_t Pad_Byte); +static void SHA384_512ProcessMessageBlock (SHA512Context * context); +static int SHA384_512Reset (SHA512Context * context, uint64_t H0[]); +static int SHA384_512ResultN (SHA512Context * context, + uint8_t Message_Digest[], int HashSize); + +/* Initial Hash Values: FIPS-180-2 sections 5.3.3 and 5.3.4 */ +static uint64_t SHA384_H0[] = { + 0xCBBB9D5DC1059ED8ll, 0x629A292A367CD507ll, 0x9159015A3070DD17ll, + 0x152FECD8F70E5939ll, 0x67332667FFC00B31ll, 0x8EB44A8768581511ll, + 0xDB0C2E0D64F98FA7ll, 0x47B5481DBEFA4FA4ll +}; + +static uint64_t SHA512_H0[] = { + 0x6A09E667F3BCC908ll, 0xBB67AE8584CAA73Bll, 0x3C6EF372FE94F82Bll, + 0xA54FF53A5F1D36F1ll, 0x510E527FADE682D1ll, 0x9B05688C2B3E6C1Fll, + 0x1F83D9ABFB41BD6Bll, 0x5BE0CD19137E2179ll +}; + +#endif /* USE_32BIT_ONLY */ + +/* + * SHA384Reset + * + * Description: + * This function will initialize the SHA384Context in preparation + * for computing a new SHA384 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int +SHA384Reset (SHA384Context * context) +{ + return SHA384_512Reset (context, SHA384_H0); +} + +/* + * SHA384Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int +SHA384Input (SHA384Context * context, + const uint8_t * message_array, unsigned int length) +{ + return SHA512Input (context, message_array, length); +} + +/* + * SHA384FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + * + */ +int +SHA384FinalBits (SHA384Context * context, + const uint8_t message_bits, unsigned int length) +{ + return SHA512FinalBits (context, message_bits, length); +} + +/* + * SHA384Result + * + * Description: + * This function will return the 384-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 48th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int +SHA384Result (SHA384Context * context, uint8_t Message_Digest[SHA384HashSize]) +{ + return SHA384_512ResultN (context, Message_Digest, SHA384HashSize); +} + +/* + * SHA512Reset + * + * Description: + * This function will initialize the SHA512Context in preparation + * for computing a new SHA512 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int +SHA512Reset (SHA512Context * context) +{ + return SHA384_512Reset (context, SHA512_H0); +} + +/* + * SHA512Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int +SHA512Input (SHA512Context * context, + const uint8_t * message_array, unsigned int length) +{ + if (!length) + return shaSuccess; + + if (!context || !message_array) + return shaNull; + + if (context->Computed) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + while (length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + if (!SHA384_512AddLength (context, 8) && + (context->Message_Block_Index == SHA512_Message_Block_Size)) + SHA384_512ProcessMessageBlock (context); + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA512FinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + * + */ +int +SHA512FinalBits (SHA512Context * context, + const uint8_t message_bits, unsigned int length) +{ + uint8_t masks[8] = { + /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, + /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, + /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, + /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE + }; + uint8_t markbit[8] = { + /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, + /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, + /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, + /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 + }; + + if (!length) + return shaSuccess; + + if (!context) + return shaNull; + + if ((context->Computed) || (length >= 8) || (length == 0)) + { + context->Corrupted = shaStateError; + return shaStateError; + } + + if (context->Corrupted) + return context->Corrupted; + + SHA384_512AddLength (context, length); + SHA384_512Finalize (context, (uint8_t) + ((message_bits & masks[length]) | markbit[length])); + + return shaSuccess; +} + +/* + * SHA384_512Finalize + * + * Description: + * This helper function finishes off the digest calculations. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * Pad_Byte: [in] + * The last byte to add to the digest before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * sha Error Code. + * + */ +static void +SHA384_512Finalize (SHA512Context * context, uint8_t Pad_Byte) +{ + int_least16_t i; + SHA384_512PadMessage (context, Pad_Byte); + /* message may be sensitive, clear it out */ + for (i = 0; i < SHA512_Message_Block_Size; ++i) + context->Message_Block[i] = 0; +#ifdef USE_32BIT_ONLY /* and clear length */ + context->Length[0] = context->Length[1] = 0; + context->Length[2] = context->Length[3] = 0; +#else /* !USE_32BIT_ONLY */ + context->Length_Low = 0; + context->Length_High = 0; +#endif /* USE_32BIT_ONLY */ + context->Computed = 1; +} + +/* + * SHA512Result + * + * Description: + * This function will return the 512-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 64th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int +SHA512Result (SHA512Context * context, uint8_t Message_Digest[SHA512HashSize]) +{ + return SHA384_512ResultN (context, Message_Digest, SHA512HashSize); +} + +/* + * SHA384_512PadMessage + * + * Description: + * According to the standard, the message must be padded to an + * even 1024 bits. The first padding bit must be a '1'. The + * last 128 bits represent the length of the original message. + * All bits in between should be 0. This helper function will + * pad the message according to those rules by filling the + * Message_Block array accordingly. When it returns, it can be + * assumed that the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * Pad_Byte: [in] + * The last byte to add to the digest before the 0-padding + * and length. This will contain the last bits of the message + * followed by another single bit. If the message was an + * exact multiple of 8-bits long, Pad_Byte will be 0x80. + * + * Returns: + * Nothing. + * + */ +static void +SHA384_512PadMessage (SHA512Context * context, uint8_t Pad_Byte) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index >= (SHA512_Message_Block_Size - 16)) + { + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + while (context->Message_Block_Index < SHA512_Message_Block_Size) + context->Message_Block[context->Message_Block_Index++] = 0; + + SHA384_512ProcessMessageBlock (context); + } + else + context->Message_Block[context->Message_Block_Index++] = Pad_Byte; + + while (context->Message_Block_Index < (SHA512_Message_Block_Size - 16)) + context->Message_Block[context->Message_Block_Index++] = 0; + + /* + * Store the message length as the last 16 octets + */ +#ifdef USE_32BIT_ONLY + context->Message_Block[112] = (uint8_t) (context->Length[0] >> 24); + context->Message_Block[113] = (uint8_t) (context->Length[0] >> 16); + context->Message_Block[114] = (uint8_t) (context->Length[0] >> 8); + context->Message_Block[115] = (uint8_t) (context->Length[0]); + context->Message_Block[116] = (uint8_t) (context->Length[1] >> 24); + context->Message_Block[117] = (uint8_t) (context->Length[1] >> 16); + context->Message_Block[118] = (uint8_t) (context->Length[1] >> 8); + context->Message_Block[119] = (uint8_t) (context->Length[1]); + + context->Message_Block[120] = (uint8_t) (context->Length[2] >> 24); + context->Message_Block[121] = (uint8_t) (context->Length[2] >> 16); + context->Message_Block[122] = (uint8_t) (context->Length[2] >> 8); + context->Message_Block[123] = (uint8_t) (context->Length[2]); + context->Message_Block[124] = (uint8_t) (context->Length[3] >> 24); + context->Message_Block[125] = (uint8_t) (context->Length[3] >> 16); + context->Message_Block[126] = (uint8_t) (context->Length[3] >> 8); + context->Message_Block[127] = (uint8_t) (context->Length[3]); +#else /* !USE_32BIT_ONLY */ + context->Message_Block[112] = (uint8_t) (context->Length_High >> 56); + context->Message_Block[113] = (uint8_t) (context->Length_High >> 48); + context->Message_Block[114] = (uint8_t) (context->Length_High >> 40); + context->Message_Block[115] = (uint8_t) (context->Length_High >> 32); + context->Message_Block[116] = (uint8_t) (context->Length_High >> 24); + context->Message_Block[117] = (uint8_t) (context->Length_High >> 16); + context->Message_Block[118] = (uint8_t) (context->Length_High >> 8); + context->Message_Block[119] = (uint8_t) (context->Length_High); + + context->Message_Block[120] = (uint8_t) (context->Length_Low >> 56); + context->Message_Block[121] = (uint8_t) (context->Length_Low >> 48); + context->Message_Block[122] = (uint8_t) (context->Length_Low >> 40); + context->Message_Block[123] = (uint8_t) (context->Length_Low >> 32); + context->Message_Block[124] = (uint8_t) (context->Length_Low >> 24); + context->Message_Block[125] = (uint8_t) (context->Length_Low >> 16); + context->Message_Block[126] = (uint8_t) (context->Length_Low >> 8); + context->Message_Block[127] = (uint8_t) (context->Length_Low); +#endif /* USE_32BIT_ONLY */ + + SHA384_512ProcessMessageBlock (context); +} + +/* + * SHA384_512ProcessMessageBlock + * + * Description: + * This helper function will process the next 1024 bits of the + * message stored in the Message_Block array. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +static void +SHA384_512ProcessMessageBlock (SHA512Context * context) +{ + /* Constants defined in FIPS-180-2, section 4.2.3 */ +#ifdef USE_32BIT_ONLY + static const uint32_t K[80 * 2] = { + 0x428A2F98, 0xD728AE22, 0x71374491, 0x23EF65CD, 0xB5C0FBCF, + 0xEC4D3B2F, 0xE9B5DBA5, 0x8189DBBC, 0x3956C25B, 0xF348B538, + 0x59F111F1, 0xB605D019, 0x923F82A4, 0xAF194F9B, 0xAB1C5ED5, + 0xDA6D8118, 0xD807AA98, 0xA3030242, 0x12835B01, 0x45706FBE, + 0x243185BE, 0x4EE4B28C, 0x550C7DC3, 0xD5FFB4E2, 0x72BE5D74, + 0xF27B896F, 0x80DEB1FE, 0x3B1696B1, 0x9BDC06A7, 0x25C71235, + 0xC19BF174, 0xCF692694, 0xE49B69C1, 0x9EF14AD2, 0xEFBE4786, + 0x384F25E3, 0x0FC19DC6, 0x8B8CD5B5, 0x240CA1CC, 0x77AC9C65, + 0x2DE92C6F, 0x592B0275, 0x4A7484AA, 0x6EA6E483, 0x5CB0A9DC, + 0xBD41FBD4, 0x76F988DA, 0x831153B5, 0x983E5152, 0xEE66DFAB, + 0xA831C66D, 0x2DB43210, 0xB00327C8, 0x98FB213F, 0xBF597FC7, + 0xBEEF0EE4, 0xC6E00BF3, 0x3DA88FC2, 0xD5A79147, 0x930AA725, + 0x06CA6351, 0xE003826F, 0x14292967, 0x0A0E6E70, 0x27B70A85, + 0x46D22FFC, 0x2E1B2138, 0x5C26C926, 0x4D2C6DFC, 0x5AC42AED, + 0x53380D13, 0x9D95B3DF, 0x650A7354, 0x8BAF63DE, 0x766A0ABB, + 0x3C77B2A8, 0x81C2C92E, 0x47EDAEE6, 0x92722C85, 0x1482353B, + 0xA2BFE8A1, 0x4CF10364, 0xA81A664B, 0xBC423001, 0xC24B8B70, + 0xD0F89791, 0xC76C51A3, 0x0654BE30, 0xD192E819, 0xD6EF5218, + 0xD6990624, 0x5565A910, 0xF40E3585, 0x5771202A, 0x106AA070, + 0x32BBD1B8, 0x19A4C116, 0xB8D2D0C8, 0x1E376C08, 0x5141AB53, + 0x2748774C, 0xDF8EEB99, 0x34B0BCB5, 0xE19B48A8, 0x391C0CB3, + 0xC5C95A63, 0x4ED8AA4A, 0xE3418ACB, 0x5B9CCA4F, 0x7763E373, + 0x682E6FF3, 0xD6B2B8A3, 0x748F82EE, 0x5DEFB2FC, 0x78A5636F, + 0x43172F60, 0x84C87814, 0xA1F0AB72, 0x8CC70208, 0x1A6439EC, + 0x90BEFFFA, 0x23631E28, 0xA4506CEB, 0xDE82BDE9, 0xBEF9A3F7, + 0xB2C67915, 0xC67178F2, 0xE372532B, 0xCA273ECE, 0xEA26619C, + 0xD186B8C7, 0x21C0C207, 0xEADA7DD6, 0xCDE0EB1E, 0xF57D4F7F, + 0xEE6ED178, 0x06F067AA, 0x72176FBA, 0x0A637DC5, 0xA2C898A6, + 0x113F9804, 0xBEF90DAE, 0x1B710B35, 0x131C471B, 0x28DB77F5, + 0x23047D84, 0x32CAAB7B, 0x40C72493, 0x3C9EBE0A, 0x15C9BEBC, + 0x431D67C4, 0x9C100D4C, 0x4CC5D4BE, 0xCB3E42B6, 0x597F299C, + 0xFC657E2A, 0x5FCB6FAB, 0x3AD6FAEC, 0x6C44198C, 0x4A475817 + }; + int t, t2, t8; /* Loop counter */ + uint32_t temp1[2], temp2[2], /* Temporary word values */ + temp3[2], temp4[2], temp5[2]; + uint32_t W[2 * 80]; /* Word sequence */ + uint32_t A[2], B[2], C[2], D[2], /* Word buffers */ + E[2], F[2], G[2], H[2]; + + /* Initialize the first 16 words in the array W */ + for (t = t2 = t8 = 0; t < 16; t++, t8 += 8) + { + W[t2++] = ((((uint32_t) context->Message_Block[t8])) << 24) | + ((((uint32_t) context->Message_Block[t8 + 1])) << 16) | + ((((uint32_t) context->Message_Block[t8 + 2])) << 8) | + ((((uint32_t) context->Message_Block[t8 + 3]))); + W[t2++] = ((((uint32_t) context->Message_Block[t8 + 4])) << 24) | + ((((uint32_t) context->Message_Block[t8 + 5])) << 16) | + ((((uint32_t) context->Message_Block[t8 + 6])) << 8) | + ((((uint32_t) context->Message_Block[t8 + 7]))); + } + + for (t = 16; t < 80; t++, t2 += 2) + { + /* W[t] = SHA512_sigma1(W[t-2]) + W[t-7] + + SHA512_sigma0(W[t-15]) + W[t-16]; */ + uint32_t *Wt2 = &W[t2 - 2 * 2]; + uint32_t *Wt7 = &W[t2 - 7 * 2]; + uint32_t *Wt15 = &W[t2 - 15 * 2]; + uint32_t *Wt16 = &W[t2 - 16 * 2]; + SHA512_sigma1 (Wt2, temp1); + SHA512_ADD (temp1, Wt7, temp2); + SHA512_sigma0 (Wt15, temp1); + SHA512_ADD (temp1, Wt16, temp3); + SHA512_ADD (temp2, temp3, &W[t2]); + } + + A[0] = context->Intermediate_Hash[0]; + A[1] = context->Intermediate_Hash[1]; + B[0] = context->Intermediate_Hash[2]; + B[1] = context->Intermediate_Hash[3]; + C[0] = context->Intermediate_Hash[4]; + C[1] = context->Intermediate_Hash[5]; + D[0] = context->Intermediate_Hash[6]; + D[1] = context->Intermediate_Hash[7]; + E[0] = context->Intermediate_Hash[8]; + E[1] = context->Intermediate_Hash[9]; + F[0] = context->Intermediate_Hash[10]; + F[1] = context->Intermediate_Hash[11]; + G[0] = context->Intermediate_Hash[12]; + G[1] = context->Intermediate_Hash[13]; + H[0] = context->Intermediate_Hash[14]; + H[1] = context->Intermediate_Hash[15]; + + for (t = t2 = 0; t < 80; t++, t2 += 2) + { + /* + * temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; + */ + SHA512_SIGMA1 (E, temp1); + SHA512_ADD (H, temp1, temp2); + SHA_Ch (E, F, G, temp3); + SHA512_ADD (temp2, temp3, temp4); + SHA512_ADD (&K[t2], &W[t2], temp5); + SHA512_ADD (temp4, temp5, temp1); + /* + * temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C); + */ + SHA512_SIGMA0 (A, temp3); + SHA_Maj (A, B, C, temp4); + SHA512_ADD (temp3, temp4, temp2); + H[0] = G[0]; + H[1] = G[1]; + G[0] = F[0]; + G[1] = F[1]; + F[0] = E[0]; + F[1] = E[1]; + SHA512_ADD (D, temp1, E); + D[0] = C[0]; + D[1] = C[1]; + C[0] = B[0]; + C[1] = B[1]; + B[0] = A[0]; + B[1] = A[1]; + SHA512_ADD (temp1, temp2, A); + } + + SHA512_ADDTO2 (&context->Intermediate_Hash[0], A); + SHA512_ADDTO2 (&context->Intermediate_Hash[2], B); + SHA512_ADDTO2 (&context->Intermediate_Hash[4], C); + SHA512_ADDTO2 (&context->Intermediate_Hash[6], D); + SHA512_ADDTO2 (&context->Intermediate_Hash[8], E); + SHA512_ADDTO2 (&context->Intermediate_Hash[10], F); + SHA512_ADDTO2 (&context->Intermediate_Hash[12], G); + SHA512_ADDTO2 (&context->Intermediate_Hash[14], H); + +#else /* !USE_32BIT_ONLY */ + static const uint64_t K[80] = { + 0x428A2F98D728AE22ll, 0x7137449123EF65CDll, 0xB5C0FBCFEC4D3B2Fll, + 0xE9B5DBA58189DBBCll, 0x3956C25BF348B538ll, 0x59F111F1B605D019ll, + 0x923F82A4AF194F9Bll, 0xAB1C5ED5DA6D8118ll, 0xD807AA98A3030242ll, + 0x12835B0145706FBEll, 0x243185BE4EE4B28Cll, 0x550C7DC3D5FFB4E2ll, + 0x72BE5D74F27B896Fll, 0x80DEB1FE3B1696B1ll, 0x9BDC06A725C71235ll, + 0xC19BF174CF692694ll, 0xE49B69C19EF14AD2ll, 0xEFBE4786384F25E3ll, + 0x0FC19DC68B8CD5B5ll, 0x240CA1CC77AC9C65ll, 0x2DE92C6F592B0275ll, + 0x4A7484AA6EA6E483ll, 0x5CB0A9DCBD41FBD4ll, 0x76F988DA831153B5ll, + 0x983E5152EE66DFABll, 0xA831C66D2DB43210ll, 0xB00327C898FB213Fll, + 0xBF597FC7BEEF0EE4ll, 0xC6E00BF33DA88FC2ll, 0xD5A79147930AA725ll, + 0x06CA6351E003826Fll, 0x142929670A0E6E70ll, 0x27B70A8546D22FFCll, + 0x2E1B21385C26C926ll, 0x4D2C6DFC5AC42AEDll, 0x53380D139D95B3DFll, + 0x650A73548BAF63DEll, 0x766A0ABB3C77B2A8ll, 0x81C2C92E47EDAEE6ll, + 0x92722C851482353Bll, 0xA2BFE8A14CF10364ll, 0xA81A664BBC423001ll, + 0xC24B8B70D0F89791ll, 0xC76C51A30654BE30ll, 0xD192E819D6EF5218ll, + 0xD69906245565A910ll, 0xF40E35855771202All, 0x106AA07032BBD1B8ll, + 0x19A4C116B8D2D0C8ll, 0x1E376C085141AB53ll, 0x2748774CDF8EEB99ll, + 0x34B0BCB5E19B48A8ll, 0x391C0CB3C5C95A63ll, 0x4ED8AA4AE3418ACBll, + 0x5B9CCA4F7763E373ll, 0x682E6FF3D6B2B8A3ll, 0x748F82EE5DEFB2FCll, + 0x78A5636F43172F60ll, 0x84C87814A1F0AB72ll, 0x8CC702081A6439ECll, + 0x90BEFFFA23631E28ll, 0xA4506CEBDE82BDE9ll, 0xBEF9A3F7B2C67915ll, + 0xC67178F2E372532Bll, 0xCA273ECEEA26619Cll, 0xD186B8C721C0C207ll, + 0xEADA7DD6CDE0EB1Ell, 0xF57D4F7FEE6ED178ll, 0x06F067AA72176FBAll, + 0x0A637DC5A2C898A6ll, 0x113F9804BEF90DAEll, 0x1B710B35131C471Bll, + 0x28DB77F523047D84ll, 0x32CAAB7B40C72493ll, 0x3C9EBE0A15C9BEBCll, + 0x431D67C49C100D4Cll, 0x4CC5D4BECB3E42B6ll, 0x597F299CFC657E2All, + 0x5FCB6FAB3AD6FAECll, 0x6C44198C4A475817ll + }; + int t, t8; /* Loop counter */ + uint64_t temp1, temp2; /* Temporary word value */ + uint64_t W[80]; /* Word sequence */ + uint64_t A, B, C, D, E, F, G, H; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for (t = t8 = 0; t < 16; t++, t8 += 8) + W[t] = ((uint64_t) (context->Message_Block[t8]) << 56) | + ((uint64_t) (context->Message_Block[t8 + 1]) << 48) | + ((uint64_t) (context->Message_Block[t8 + 2]) << 40) | + ((uint64_t) (context->Message_Block[t8 + 3]) << 32) | + ((uint64_t) (context->Message_Block[t8 + 4]) << 24) | + ((uint64_t) (context->Message_Block[t8 + 5]) << 16) | + ((uint64_t) (context->Message_Block[t8 + 6]) << 8) | + ((uint64_t) (context->Message_Block[t8 + 7])); + + for (t = 16; t < 80; t++) + W[t] = SHA512_sigma1 (W[t - 2]) + W[t - 7] + + SHA512_sigma0 (W[t - 15]) + W[t - 16]; + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + F = context->Intermediate_Hash[5]; + G = context->Intermediate_Hash[6]; + H = context->Intermediate_Hash[7]; + + for (t = 0; t < 80; t++) + { + temp1 = H + SHA512_SIGMA1 (E) + SHA_Ch (E, F, G) + K[t] + W[t]; + temp2 = SHA512_SIGMA0 (A) + SHA_Maj (A, B, C); + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + context->Intermediate_Hash[5] += F; + context->Intermediate_Hash[6] += G; + context->Intermediate_Hash[7] += H; +#endif /* USE_32BIT_ONLY */ + + context->Message_Block_Index = 0; +} + +/* + * SHA384_512Reset + * + * Description: + * This helper function will initialize the SHA512Context in + * preparation for computing a new SHA384 or SHA512 message + * digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * H0 + * The initial hash value to use. + * + * Returns: + * sha Error Code. + * + */ +#ifdef USE_32BIT_ONLY +static int +SHA384_512Reset (SHA512Context * context, uint32_t H0[]) +#else /* !USE_32BIT_ONLY */ +static int +SHA384_512Reset (SHA512Context * context, uint64_t H0[]) +#endif /* USE_32BIT_ONLY */ +{ + int i; + if (!context) + return shaNull; + + context->Message_Block_Index = 0; + +#ifdef USE_32BIT_ONLY + context->Length[0] = context->Length[1] = 0; + context->Length[2] = context->Length[3] = 0; + + for (i = 0; i < SHA512HashSize / 4; i++) + context->Intermediate_Hash[i] = H0[i]; +#else /* !USE_32BIT_ONLY */ + context->Length_High = context->Length_Low = 0; + + for (i = 0; i < SHA512HashSize / 8; i++) + context->Intermediate_Hash[i] = H0[i]; +#endif /* USE_32BIT_ONLY */ + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA384_512ResultN + * + * Description: + * This helper function will return the 384-bit or 512-bit message + * digest into the Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 48th/64th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA hash. + * Message_Digest: [out] + * Where the digest is returned. + * HashSize: [in] + * The size of the hash, either 48 or 64. + * + * Returns: + * sha Error Code. + * + */ +static int +SHA384_512ResultN (SHA512Context * context, + uint8_t Message_Digest[], int HashSize) +{ + int i; + +#ifdef USE_32BIT_ONLY + int i2; +#endif /* USE_32BIT_ONLY */ + + if (!context || !Message_Digest) + return shaNull; + + if (context->Corrupted) + return context->Corrupted; + + if (!context->Computed) + SHA384_512Finalize (context, 0x80); + +#ifdef USE_32BIT_ONLY + for (i = i2 = 0; i < HashSize;) + { + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 24); + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 16); + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 8); + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2++]); + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 24); + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 16); + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2] >> 8); + Message_Digest[i++] = (uint8_t) (context->Intermediate_Hash[i2++]); + } +#else /* !USE_32BIT_ONLY */ + for (i = 0; i < HashSize; ++i) + Message_Digest[i] = (uint8_t) + (context->Intermediate_Hash[i >> 3] >> 8 * (7 - (i % 8))); +#endif /* USE_32BIT_ONLY */ + + return shaSuccess; +} +/**************************** usha.c ****************************/ +/******************** See RFC 4634 for details ******************/ +/* + * Description: + * This file implements a unified interface to the SHA algorithms. + */ + +//#include "sha.h" + +/* + * USHAReset + * + * Description: + * This function will initialize the SHA Context in preparation + * for computing a new SHA message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * whichSha: [in] + * Selects which SHA reset to call + * + * Returns: + * sha Error Code. + * + */ +int +USHAReset (USHAContext * ctx, enum SHAversion whichSha) +{ + if (ctx) + { + ctx->whichSha = whichSha; + switch (whichSha) + { + case SHA1: + return SHA1Reset ((SHA1Context *) & ctx->ctx); + case SHA224: + return SHA224Reset ((SHA224Context *) & ctx->ctx); + case SHA256: + return SHA256Reset ((SHA256Context *) & ctx->ctx); + case SHA384: + return SHA384Reset ((SHA384Context *) & ctx->ctx); + case SHA512: + return SHA512Reset ((SHA512Context *) & ctx->ctx); + default: + return shaBadParam; + } + } + else + { + return shaNull; + } +} + +/* + * USHAInput + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int +USHAInput (USHAContext * ctx, const uint8_t * bytes, unsigned int bytecount) +{ + if (ctx) + { + switch (ctx->whichSha) + { + case SHA1: + return SHA1Input ((SHA1Context *) & ctx->ctx, bytes, bytecount); + case SHA224: + return SHA224Input ((SHA224Context *) & ctx->ctx, bytes, bytecount); + case SHA256: + return SHA256Input ((SHA256Context *) & ctx->ctx, bytes, bytecount); + case SHA384: + return SHA384Input ((SHA384Context *) & ctx->ctx, bytes, bytecount); + case SHA512: + return SHA512Input ((SHA512Context *) & ctx->ctx, bytes, bytecount); + default: + return shaBadParam; + } + } + else + { + return shaNull; + } +} + +/* + * USHAFinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int +USHAFinalBits (USHAContext * ctx, const uint8_t bits, unsigned int bitcount) +{ + if (ctx) + { + switch (ctx->whichSha) + { + case SHA1: + return SHA1FinalBits ((SHA1Context *) & ctx->ctx, bits, bitcount); + case SHA224: + return SHA224FinalBits ((SHA224Context *) & ctx->ctx, bits, + bitcount); + case SHA256: + return SHA256FinalBits ((SHA256Context *) & ctx->ctx, bits, + bitcount); + case SHA384: + return SHA384FinalBits ((SHA384Context *) & ctx->ctx, bits, + bitcount); + case SHA512: + return SHA512FinalBits ((SHA512Context *) & ctx->ctx, bits, + bitcount); + default: + return shaBadParam; + } + } + else + { + return shaNull; + } +} + +/* + * USHAResult + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int +USHAResult (USHAContext * ctx, uint8_t Message_Digest[USHAMaxHashSize]) +{ + if (ctx) + { + switch (ctx->whichSha) + { + case SHA1: + return SHA1Result ((SHA1Context *) & ctx->ctx, Message_Digest); + case SHA224: + return SHA224Result ((SHA224Context *) & ctx->ctx, Message_Digest); + case SHA256: + return SHA256Result ((SHA256Context *) & ctx->ctx, Message_Digest); + case SHA384: + return SHA384Result ((SHA384Context *) & ctx->ctx, Message_Digest); + case SHA512: + return SHA512Result ((SHA512Context *) & ctx->ctx, Message_Digest); + default: + return shaBadParam; + } + } + else + { + return shaNull; + } +} + +/* + * USHABlockSize + * + * Description: + * This function will return the blocksize for the given SHA + * algorithm. + * + * Parameters: + * whichSha: + * which SHA algorithm to query + * + * Returns: + * block size + * + */ +int +USHABlockSize (enum SHAversion whichSha) +{ + switch (whichSha) + { + case SHA1: + return SHA1_Message_Block_Size; + case SHA224: + return SHA224_Message_Block_Size; + case SHA256: + return SHA256_Message_Block_Size; + case SHA384: + return SHA384_Message_Block_Size; + default: + case SHA512: + return SHA512_Message_Block_Size; + } +} + +/* + * USHAHashSize + * + * Description: + * This function will return the hashsize for the given SHA + * algorithm. + * + * Parameters: + * whichSha: + * which SHA algorithm to query + * + * Returns: + * hash size + * + */ +int +USHAHashSize (enum SHAversion whichSha) +{ + switch (whichSha) + { + case SHA1: + return SHA1HashSize; + case SHA224: + return SHA224HashSize; + case SHA256: + return SHA256HashSize; + case SHA384: + return SHA384HashSize; + default: + case SHA512: + return SHA512HashSize; + } +} + +/* + * USHAHashSizeBits + * + * Description: + * This function will return the hashsize for the given SHA + * algorithm, expressed in bits. + * + * Parameters: + * whichSha: + * which SHA algorithm to query + * + * Returns: + * hash size in bits + * + */ +int +USHAHashSizeBits (enum SHAversion whichSha) +{ + switch (whichSha) + { + case SHA1: + return SHA1HashSizeBits; + case SHA224: + return SHA224HashSizeBits; + case SHA256: + return SHA256HashSizeBits; + case SHA384: + return SHA384HashSizeBits; + default: + case SHA512: + return SHA512HashSizeBits; + } +} +/* + * hmac + * + * Description: + * This function will compute an HMAC message digest. + * + * Parameters: + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * key: [in] + * The secret shared key. + * key_len: [in] + * The length of the secret shared key. + * message_array: [in] + * An array of characters representing the message. + * length: [in] + * The length of the message in message_array + * digest: [out] + * Where the digest is returned. + * NOTE: The length of the digest is determined by + * the value of whichSha. + * + * Returns: + * sha Error Code. + * + */ +int +hmac (SHAversion whichSha, const unsigned char *text, int text_len, + const unsigned char *key, int key_len, uint8_t digest[USHAMaxHashSize]) +{ + HMACContext ctx; + return hmacReset (&ctx, whichSha, key, key_len) || + hmacInput (&ctx, text, text_len) || hmacResult (&ctx, digest); +} + +/* + * hmacReset + * + * Description: + * This function will initialize the hmacContext in preparation + * for computing a new HMAC message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * whichSha: [in] + * One of SHA1, SHA224, SHA256, SHA384, SHA512 + * key: [in] + * The secret shared key. + * key_len: [in] + * The length of the secret shared key. + * + * Returns: + * sha Error Code. + * + */ +int +hmacReset (HMACContext * ctx, enum SHAversion whichSha, + const unsigned char *key, int key_len) +{ + int i, blocksize, hashsize; + + /* inner padding - key XORd with ipad */ + unsigned char k_ipad[USHA_Max_Message_Block_Size]; + + /* temporary buffer when keylen > blocksize */ + unsigned char tempkey[USHAMaxHashSize]; + + if (!ctx) + return shaNull; + + blocksize = ctx->blockSize = USHABlockSize (whichSha); + hashsize = ctx->hashSize = USHAHashSize (whichSha); + + ctx->whichSha = whichSha; + + /* + * If key is longer than the hash blocksize, + * reset it to key = HASH(key). + */ + if (key_len > blocksize) + { + USHAContext tctx; + int err = USHAReset (&tctx, whichSha) || + USHAInput (&tctx, key, key_len) || USHAResult (&tctx, tempkey); + if (err != shaSuccess) + return err; + + key = tempkey; + key_len = hashsize; + } + + /* + * The HMAC transform looks like: + * + * SHA(K XOR opad, SHA(K XOR ipad, text)) + * + * where K is an n byte key. + * ipad is the byte 0x36 repeated blocksize times + * opad is the byte 0x5c repeated blocksize times + * and text is the data being protected. + */ + + /* store key into the pads, XOR'd with ipad and opad values */ + for (i = 0; i < key_len; i++) + { + k_ipad[i] = key[i] ^ 0x36; + ctx->k_opad[i] = key[i] ^ 0x5c; + } + /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ + for (; i < blocksize; i++) + { + k_ipad[i] = 0x36; + ctx->k_opad[i] = 0x5c; + } + + /* perform inner hash */ + /* init context for 1st pass */ + return USHAReset (&ctx->shaContext, whichSha) || + /* and start with inner pad */ + USHAInput (&ctx->shaContext, k_ipad, blocksize); +} + +/* + * hmacInput + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The HMAC context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int +hmacInput (HMACContext * ctx, const unsigned char *text, int text_len) +{ + if (!ctx) + return shaNull; + /* then text of datagram */ + return USHAInput (&ctx->shaContext, text, text_len); +} + +/* + * HMACFinalBits + * + * Description: + * This function will add in any final bits of the message. + * + * Parameters: + * context: [in/out] + * The HMAC context to update + * message_bits: [in] + * The final bits of the message, in the upper portion of the + * byte. (Use 0b###00000 instead of 0b00000### to input the + * three bits ###.) + * length: [in] + * The number of bits in message_bits, between 1 and 7. + * + * Returns: + * sha Error Code. + */ +int +hmacFinalBits (HMACContext * ctx, const uint8_t bits, unsigned int bitcount) +{ + if (!ctx) + return shaNull; + /* then final bits of datagram */ + return USHAFinalBits (&ctx->shaContext, bits, bitcount); +} + +/* + * HMACResult + * + * Description: + * This function will return the N-byte message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the Nth element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the HMAC hash. + * digest: [out] + * Where the digest is returned. + * NOTE 2: The length of the hash is determined by the value of + * whichSha that was passed to hmacReset(). + * + * Returns: + * sha Error Code. + * + */ +int +hmacResult (HMACContext * ctx, uint8_t * digest) +{ + if (!ctx) + return shaNull; + + /* finish up 1st pass */ + /* (Use digest here as a temporary buffer.) */ + return USHAResult (&ctx->shaContext, digest) || + /* perform outer SHA */ + /* init context for 2nd pass */ + USHAReset (&ctx->shaContext, (SHAversion)ctx->whichSha) || + /* start with outer pad */ + USHAInput (&ctx->shaContext, ctx->k_opad, ctx->blockSize) || + /* then results of 1st hash */ + USHAInput (&ctx->shaContext, digest, ctx->hashSize) || + /* finish up 2nd pass */ + USHAResult (&ctx->shaContext, digest); +} +} +#include "ccapi_cpp/ccapi_macro.h" +#include "ccapi_cpp/ccapi_logger.h" +namespace ccapi { +class Hmac final { +// https://github.com/Yubico/yubico-c-client/blob/ykclient-2.15/sha384-512.c + public: + enum class ShaVersion { + UNKNOWN, + SHA1, + SHA224, + SHA256, + SHA384, + SHA512 + }; + static std::string hmac(const ShaVersion shaVersion, const std::string& key, const std::string& msg, bool returnHex = false) { + yubico::SHAversion whichSha{}; + int shaHashSize{}; + switch(shaVersion) { + case ShaVersion::SHA1: + whichSha = yubico::SHAversion::SHA1; + shaHashSize = yubico::SHA1HashSize; + break; + case ShaVersion::SHA224: + whichSha = yubico::SHAversion::SHA224; + shaHashSize = yubico::SHA224HashSize; + break; + case ShaVersion::SHA256: + whichSha = yubico::SHAversion::SHA256; + shaHashSize = yubico::SHA256HashSize; + break; + case ShaVersion::SHA384: + whichSha = yubico::SHAversion::SHA384; + shaHashSize = yubico::SHA384HashSize; + break; + case ShaVersion::SHA512: + whichSha = yubico::SHAversion::SHA512; + shaHashSize = yubico::SHA512HashSize; + break; + default: + CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); + } + uint8_t digest[yubico::USHAMaxHashSize]; + int err = yubico::hmac(whichSha, + reinterpret_cast(const_cast(msg.c_str())), + msg.length(), + reinterpret_cast(const_cast(key.c_str())), + key.length(), + digest); + if (err != yubico::shaSuccess) { + throw std::runtime_error("hmac sha error"); + } + std::stringstream ss; + if (returnHex) { + ss << std::hex << std::setfill('0'); + for (int i = 0; i < shaHashSize; i++) { + ss << std::hex << std::setw(2) << (unsigned int)digest[i]; + } + } else { + ss << std::setfill('0'); + for (int i = 0; i < shaHashSize; i++) { + ss << (int)digest[i]; + } + } + return (ss.str()); + } +}; +} /* namespace ccapi */ +#endif // INCLUDE_CCAPI_CPP_CCAPI_HMAC_H_ diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 88050f15..ada05d9e 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -183,6 +183,9 @@ #ifndef CCAPI_COINBASE_URL_REST_BASE #define CCAPI_COINBASE_URL_REST_BASE "https://api.pro.coinbase.com" #endif +#ifndef CCAPI_GEMINI_URL_REST_BASE +#define CCAPI_GEMINI_URL_REST_BASE "https://api.gemini.com" +#endif #ifndef CCAPI_BINANCE_US_URL_REST_BASE #define CCAPI_BINANCE_US_URL_REST_BASE "https://api.binance.us" #endif @@ -210,6 +213,12 @@ #ifndef CCAPI_COINBASE_API_SECRET #define CCAPI_COINBASE_API_SECRET "COINBASE_API_SECRET" #endif +#ifndef CCAPI_GEMINI_API_KEY +#define CCAPI_GEMINI_API_KEY "GEMINI_API_KEY" +#endif +#ifndef CCAPI_GEMINI_API_SECRET +#define CCAPI_GEMINI_API_SECRET "GEMINI_API_SECRET" +#endif #ifndef CCAPI_COINBASE_API_PASSPHRASE #define CCAPI_COINBASE_API_PASSPHRASE "COINBASE_API_PASSPHRASE" #endif diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 98f9e51c..417b7308 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -39,6 +39,9 @@ #ifdef ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_execution_management_service_coinbase.h" #endif +#ifdef ENABLE_EXCHANGE_GEMINI +#include "ccapi_cpp/service/ccapi_execution_management_service_gemini.h" +#endif #ifdef ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_us.h" #endif @@ -139,6 +142,9 @@ class Session final { #ifdef ENABLE_EXCHANGE_COINBASE this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_COINBASE] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif +#ifdef ENABLE_EXCHANGE_GEMINI + this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_GEMINI] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +#endif #ifdef ENABLE_EXCHANGE_BINANCE_US this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_US] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif diff --git a/include/ccapi_cpp/ccapi_session_configs.h b/include/ccapi_cpp/ccapi_session_configs.h index 504dc56b..744ff60b 100644 --- a/include/ccapi_cpp/ccapi_session_configs.h +++ b/include/ccapi_cpp/ccapi_session_configs.h @@ -217,6 +217,7 @@ class SessionConfigs final { } this->urlRestBase = { { CCAPI_EXCHANGE_NAME_COINBASE, CCAPI_COINBASE_URL_REST_BASE}, + { CCAPI_EXCHANGE_NAME_GEMINI, CCAPI_GEMINI_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE_US, CCAPI_BINANCE_US_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE, CCAPI_BINANCE_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE_FUTURES, CCAPI_BINANCE_FUTURES_URL_REST_BASE}, diff --git a/include/ccapi_cpp/ccapi_util.h b/include/ccapi_cpp/ccapi_util.h index 11e75e79..149ab763 100644 --- a/include/ccapi_cpp/ccapi_util.h +++ b/include/ccapi_cpp/ccapi_util.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_UTIL_H_ #define INCLUDE_CCAPI_CPP_CCAPI_UTIL_H_ -#include -#include +//#include +//#include #include #include #include @@ -237,38 +237,46 @@ class UtilAlgorithm final { return initial + multiplier * (pow(base, exponent) - 1); } template static uint_fast32_t crc(InputIterator first, InputIterator last); - static std::string hmac(std::string key, std::string msg, bool returnHex = false) { - unsigned char hash[32]; -#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) && OPENSSL_VERSION_MAJOR <= 1 && (OPENSSL_VERSION_MAJOR != 1 || OPENSSL_VERSION_MINOR < 1) - HMAC_CTX hmac; - HMAC_CTX_init(&hmac); - HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL); - HMAC_Update(&hmac, (unsigned char*)&msg[0], msg.length()); - unsigned int len = 32; - HMAC_Final(&hmac, hash, &len); - HMAC_CTX_cleanup(&hmac); -#else - HMAC_CTX *hmac = HMAC_CTX_new(); - HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha256(), NULL); - HMAC_Update(hmac, (unsigned char*)&msg[0], msg.length()); - unsigned int len = 32; - HMAC_Final(hmac, hash, &len); - HMAC_CTX_free(hmac); -#endif - std::stringstream ss; - if (returnHex) { - ss << std::hex << std::setfill('0'); - for (int i = 0; i < len; i++) { - ss << std::hex << std::setw(2) << (unsigned int)hash[i]; - } - } else { - ss << std::setfill('0'); - for (int i = 0; i < len; i++) { - ss << hash[i]; - } - } - return (ss.str()); - } +// static std::string hmac(std::string key, std::string msg, bool returnHex = false, const std::string& algorithm = "") { +// unsigned char hash[32]; +//#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) && OPENSSL_VERSION_MAJOR <= 1 && (OPENSSL_VERSION_MAJOR != 1 || OPENSSL_VERSION_MINOR < 1) +// HMAC_CTX hmac; +// HMAC_CTX_init(&hmac); +// if (algorithm == "sha384") { +// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha384(), NULL); +// } else { +// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL); +// } +// HMAC_Update(&hmac, (unsigned char*)&msg[0], msg.length()); +// unsigned int len = 32; +// HMAC_Final(&hmac, hash, &len); +// HMAC_CTX_cleanup(&hmac); +//#else +// HMAC_CTX *hmac = HMAC_CTX_new(); +// if (algorithm == "sha384") { +// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha384(), NULL); +// } else { +// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha256(), NULL); +// } +// HMAC_Update(hmac, (unsigned char*)&msg[0], msg.length()); +// unsigned int len = 32; +// HMAC_Final(hmac, hash, &len); +// HMAC_CTX_free(hmac); +//#endif +// std::stringstream ss; +// if (returnHex) { +// ss << std::hex << std::setfill('0'); +// for (int i = 0; i < len; i++) { +// ss << std::hex << std::setw(2) << (unsigned int)hash[i]; +// } +// } else { +// ss << std::setfill('0'); +// for (int i = 0; i < len; i++) { +// ss << hash[i]; +// } +// } +// return (ss.str()); +// } }; template uint_fast32_t UtilAlgorithm::crc(InputIterator first, InputIterator last) { static auto const table = []() { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 38b05a8b..2505438f 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -26,6 +26,7 @@ #include "ccapi_cpp/ccapi_http_retry.h" #include "ccapi_cpp/ccapi_url.h" #include "ccapi_cpp/ccapi_macro.h" +#include "ccapi_cpp/ccapi_hmac.h" #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" @@ -385,7 +386,6 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro auto operation = request.getOperation(); http::request req; req.set(http::field::host, this->host+":"+this->port); - req.set(beast::http::field::content_type, "application/json"); req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); this->convertReq(request, now, req, credential, symbolId, operation); return req; @@ -445,7 +445,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro messageList.push_back(std::move(message)); return messageList; } - Element extractOrderInfo(const rj::Value& x, const std::map >& extractionFieldNameMap) { + virtual Element extractOrderInfo(const rj::Value& x, const std::map >& extractionFieldNameMap) { Element element; for (const auto& y : extractionFieldNameMap) { auto it = x.FindMember(y.second.first.c_str()); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h index 07370333..a2c3809d 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h @@ -23,7 +23,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService } queryString.pop_back(); auto apiSecret = mapGetWithDefault(credential, this->apiSecretName, {}); - std::string signature = UtilAlgorithm::hmac(apiSecret, queryString, true); + auto signature = Hmac::hmac(Hmac::ShaVersion::SHA256, apiSecret, queryString, true); queryString += "&signature="; queryString += signature; } @@ -98,12 +98,11 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService { req.method(http::verb::get); std::string queryString; - const std::map& param = {}; - this->appendParam(queryString, param); + this->appendParam(queryString, {}); if (!symbolId.empty()) { this->appendSymbolId(queryString, symbolId); } - this->signRequest(queryString, param, now, credential); + this->signRequest(queryString, {}, now, credential); req.target(this->getOpenOrdersTarget + "?" + queryString); } break; @@ -111,10 +110,9 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService { req.method(http::verb::delete_); std::string queryString; - const std::map& param = {}; - this->appendParam(queryString, param); + this->appendParam(queryString, {}); this->appendSymbolId(queryString, symbolId); - this->signRequest(queryString, param, now, credential); + this->signRequest(queryString, {}, now, credential); req.target(this->cancelOpenOrdersTarget + "?" + queryString); } break; diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h index c29a4526..85168e41 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h @@ -33,8 +33,7 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi preSignedText += UtilString::toUpper(std::string(req.method_string())); preSignedText += std::string(req.target()); preSignedText += body; - CCAPI_LOGGER_TRACE("preSignedText = "+preSignedText); - std::string signature = UtilAlgorithm::base64Encode(UtilAlgorithm::hmac(UtilAlgorithm::base64Decode(apiSecret), preSignedText)); + auto signature = UtilAlgorithm::base64Encode(Hmac::hmac(Hmac::ShaVersion::SHA256, UtilAlgorithm::base64Decode(apiSecret), preSignedText)); req.set("CB-ACCESS-SIGN", signature); req.body() = body; req.prepare_payload(); @@ -53,6 +52,7 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi document.AddMember("product_id", rj::Value(symbolId.c_str(), allocator).Move(), allocator); } void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) override { + req.set(beast::http::field::content_type, "application/json"); auto apiKey = mapGetWithDefault(credential, this->apiKeyName, {}); req.set("CB-ACCESS-KEY", apiKey); req.set("CB-ACCESS-TIMESTAMP", std::to_string(std::chrono::duration_cast(now.time_since_epoch()).count())); @@ -93,7 +93,6 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi target += "?product_id="; target += symbolId; } - CCAPI_LOGGER_TRACE("target = "+target); req.target(target); this->signRequest(req, "", param, now, credential); } @@ -106,7 +105,6 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi : param.find(CCAPI_EM_CLIENT_ORDER_ID) != param.end() ? "client:" + param.at(CCAPI_EM_CLIENT_ORDER_ID) : ""; auto target = std::regex_replace(this->getOrderTarget, std::regex("\\{id\\}"), id); - CCAPI_LOGGER_TRACE("target = "+target); req.target(target); this->signRequest(req, "", param, now, credential); } @@ -114,29 +112,25 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi case Request::Operation::GET_OPEN_ORDERS: { req.method(http::verb::get); - const std::map& param = {}; auto target = this->getOpenOrdersTarget; if (!symbolId.empty()) { target += "?product_id="; target += symbolId; } - CCAPI_LOGGER_TRACE("target = "+target); req.target(target); - this->signRequest(req, "", param, now, credential); + this->signRequest(req, "", {}, now, credential); } break; case Request::Operation::CANCEL_OPEN_ORDERS: { req.method(http::verb::delete_); - const std::map& param = {}; auto target = this->cancelOpenOrdersTarget; if (!symbolId.empty()) { target += "?product_id="; target += symbolId; } - CCAPI_LOGGER_TRACE("target = "+target); req.target(target); - this->signRequest(req, "", param, now, credential); + this->signRequest(req, "", {}, now, credential); } break; default: diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h new file mode 100644 index 00000000..1a3473c1 --- /dev/null +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h @@ -0,0 +1,195 @@ +#ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_GEMINI_H_ +#define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_GEMINI_H_ +#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef ENABLE_EXCHANGE_GEMINI +#include "ccapi_cpp/service/ccapi_execution_management_service.h" +namespace ccapi { +class ExecutionManagementServiceGemini final : public ExecutionManagementService { + public: + ExecutionManagementServiceGemini(std::function eventHandler, SessionOptions sessionOptions, + SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) + : ExecutionManagementService(eventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { + CCAPI_LOGGER_FUNCTION_ENTER; + this->name = CCAPI_EXCHANGE_NAME_GEMINI; + this->baseUrlRest = this->sessionConfigs.getUrlRestBase().at(this->name); + this->setHostFromUrl(this->baseUrlRest); + this->apiKeyName = CCAPI_GEMINI_API_KEY; + this->apiSecretName = CCAPI_GEMINI_API_SECRET; + this->setupCredential({this->apiKeyName, this->apiSecretName}); + this->createOrderTarget = "/v1/order/new"; + this->cancelOrderTarget = "/v1/order/cancel"; + this->getOrderTarget = "/v1/order/status"; + this->getOpenOrdersTarget = "/v1/orders"; + this->cancelOpenOrdersTarget = "/v1/order/cancel/session"; + CCAPI_LOGGER_FUNCTION_EXIT; + } + + protected: + void signRequest(http::request& req, rj::Document& document, rj::Document::AllocatorType& allocator, const std::map& param, const TimePoint& now, const std::map& credential) { + document.AddMember("request", rj::Value(std::string(req.target()).c_str(), allocator).Move(), allocator); + int64_t nonce = std::chrono::duration_cast(now.time_since_epoch()).count(); + document.AddMember("nonce", rj::Value(nonce).Move(), allocator); + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + auto body = stringBuffer.GetString(); + auto base64Payload = UtilAlgorithm::base64Encode(body); + req.set("X-GEMINI-PAYLOAD", base64Payload); + auto apiSecret = mapGetWithDefault(credential, this->apiSecretName, {}); + auto signature = Hmac::hmac(Hmac::ShaVersion::SHA384, apiSecret, base64Payload, true); + req.set("X-GEMINI-SIGNATURE", signature); + } + void appendParam(rj::Document& document, rj::Document::AllocatorType& allocator, const std::map& param, const std::map regularizationMap = {}) { + for (const auto& kv : param) { + auto key = regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first; + auto value = kv.second; + if (key == "side") { + value = value == CCAPI_EM_ORDER_SIDE_BUY ? "buy" : "sell"; + } + if (key == "order_id") { + document.AddMember(rj::Value(key.c_str(), allocator).Move(), rj::Value(std::stoi(value)).Move(), allocator); + } else { + document.AddMember(rj::Value(key.c_str(), allocator).Move(), rj::Value(value.c_str(), allocator).Move(), allocator); + } + } + } + void appendSymbolId(rj::Document& document, rj::Document::AllocatorType& allocator, const std::string symbolId) { + document.AddMember("symbol", rj::Value(symbolId.c_str(), allocator).Move(), allocator); + } + void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) override { + auto apiKey = mapGetWithDefault(credential, this->apiKeyName, {}); + req.set("Content-Length", "0"); + req.set("Content-Type", "text/plain"); + req.set("X-GEMINI-APIKEY", apiKey); + req.set("Cache-Control", "no-cache"); + switch (operation) { + case Request::Operation::CREATE_ORDER: + { + req.method(http::verb::post); + const std::map& param = request.getParamList().at(0); + req.target(this->createOrderTarget); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_ORDER_SIDE , "side"}, + {CCAPI_EM_ORDER_QUANTITY , "amount"}, + {CCAPI_EM_ORDER_LIMIT_PRICE , "price"}, + {CCAPI_EM_CLIENT_ORDER_ID , "client_order_id"} + }); + this->appendSymbolId(document, allocator, symbolId); + if (param.find("type") == param.end()) { + document.AddMember("type", rj::Value("exchange limit").Move(), allocator); + } + this->signRequest(req, document, allocator, param, now, credential); + } + break; + case Request::Operation::CANCEL_ORDER: + { + req.method(http::verb::post); + const std::map& param = request.getParamList().at(0); + req.target(this->cancelOrderTarget); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_ORDER_ID , "order_id"} + }); + this->signRequest(req, document, allocator, param, now, credential); + } + break; + case Request::Operation::GET_ORDER: + { + req.method(http::verb::post); + const std::map& param = request.getParamList().at(0); + req.target(this->getOrderTarget); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_ORDER_ID , "order_id"}, + {CCAPI_EM_CLIENT_ORDER_ID , "client_order_id"}, + {CCAPI_EM_ACCOUNT_ID, "account"} + }); + this->signRequest(req, document, allocator, param, now, credential); + } + break; + case Request::Operation::GET_OPEN_ORDERS: + { + req.method(http::verb::post); + req.target(this->getOpenOrdersTarget); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, {}, { + {CCAPI_EM_ACCOUNT_ID, "account"} + }); + this->signRequest(req, document, allocator, {}, now, credential); + } + break; + case Request::Operation::CANCEL_OPEN_ORDERS: + { + req.method(http::verb::post); + req.target(this->cancelOpenOrdersTarget); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, {}, { + {CCAPI_EM_ACCOUNT_ID, "account"} + }); + this->signRequest(req, document, allocator, {}, now, credential); + } + break; + default: + CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); + } + } + std::vector extractOrderInfo(const Request::Operation operation, const rj::Document& document) override { + const std::map >& extractionFieldNameMap = { + {CCAPI_EM_ORDER_ID, std::make_pair("order_id", JsonDataType::STRING)}, + {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("client_order_id", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_QUANTITY, std::make_pair("original_amount", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("price", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::make_pair("executed_amount", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("symbol", JsonDataType::STRING)} + }; + std::vector elementList; + if (operation == Request::Operation::CANCEL_OPEN_ORDERS) { + for (const auto& x : document["details"]["cancelledOrders"].GetArray()) { + Element element; + element.insert(CCAPI_EM_ORDER_ID, std::to_string(x.GetInt())); + elementList.emplace_back(element); + } + } + else if (document.IsObject()) { + elementList.emplace_back(this->extractOrderInfo(document, extractionFieldNameMap)); + } else { + for (const auto& x : document.GetArray()) { + elementList.emplace_back(this->extractOrderInfo(x, extractionFieldNameMap)); + } + } + return elementList; + } + Element extractOrderInfo(const rj::Value& x, const std::map >& extractionFieldNameMap) override { + Element element = ExecutionManagementService::extractOrderInfo(x, extractionFieldNameMap); + { + auto it1 = x.FindMember("executed_amount"); + auto it2 = x.FindMember("avg_execution_price"); + if (it1 != x.MemberEnd() && it2 != x.MemberEnd()) { + element.insert(CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::to_string(std::stod(it1->value.GetString()) * std::stod(it2->value.GetString()))); + } + } + { + auto it = x.FindMember("is_live"); + if (it != x.MemberEnd()) { + element.insert(CCAPI_EM_ORDER_STATUS, it->value.GetBool() ? CCAPI_EM_ORDER_STATUS_OPEN : CCAPI_EM_ORDER_STATUS_CLOSED); + } + } + return element; + } +}; +} /* namespace ccapi */ +#endif +#endif +#endif // INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_GEMINI_H_ diff --git a/test/unit_test/src/common/CMakeLists.txt b/test/unit_test/src/common/CMakeLists.txt index 691d93fa..322c5df4 100644 --- a/test/unit_test/src/common/CMakeLists.txt +++ b/test/unit_test/src/common/CMakeLists.txt @@ -1,5 +1,5 @@ set(NAME common) project(${NAME}) -add_executable(${NAME} ${SOURCE_LOGGER} ccapi_decimal_test.cpp ccapi_util_test.cpp) +add_executable(${NAME} ${SOURCE_LOGGER} ccapi_decimal_test.cpp ccapi_hmac_test.cpp) target_link_libraries(${NAME} GTest::GTest GTest::Main) gtest_discover_tests(${NAME}) diff --git a/test/unit_test/src/common/ccapi_hmac_test.cpp b/test/unit_test/src/common/ccapi_hmac_test.cpp new file mode 100644 index 00000000..7f9de4a6 --- /dev/null +++ b/test/unit_test/src/common/ccapi_hmac_test.cpp @@ -0,0 +1,11 @@ +#include "gtest/gtest.h" +#include "ccapi_cpp/ccapi_hmac.h" +namespace ccapi { +TEST(HmacTest, hmac256ReturnHex) { + auto result = Hmac::hmac(Hmac::ShaVersion::SHA256, + "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j", + "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559", + true); + EXPECT_EQ(result, "c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71"); +} +} /* namespace ccapi */ diff --git a/test/unit_test/src/common/ccapi_util_test.cpp b/test/unit_test/src/common/ccapi_util_test.cpp deleted file mode 100644 index ee1b790d..00000000 --- a/test/unit_test/src/common/ccapi_util_test.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "gtest/gtest.h" -#include "ccapi_cpp/ccapi_util.h" -namespace ccapi { -TEST(UtilAlgorithmTest, hmacHex) { - auto result = UtilAlgorithm::hmacHex("NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j", "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559"); - EXPECT_EQ(result, "c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71"); -} -} /* namespace ccapi */ diff --git a/test/unit_test/src/execution_management/binance_futures/CMakeLists.txt b/test/unit_test/src/execution_management/binance_futures/CMakeLists.txt index bc40a3e4..908f450b 100644 --- a/test/unit_test/src/execution_management/binance_futures/CMakeLists.txt +++ b/test/unit_test/src/execution_management/binance_futures/CMakeLists.txt @@ -1,7 +1,7 @@ set(NAME execution_management_binance_futures) project(${NAME}) -add_definitions(-DENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_definitions(-DENABLE_EXCHANGE_BINANCE_FUTURES) +add_compile_definitions(ENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(ENABLE_EXCHANGE_BINANCE_FUTURES) add_executable(${NAME} ${SOURCE_LOGGER} test.cpp) target_link_libraries(${NAME} GTest::GTest GTest::Main) gtest_discover_tests(${NAME}) diff --git a/test/unit_test/src/execution_management/binance_us/CMakeLists.txt b/test/unit_test/src/execution_management/binance_us/CMakeLists.txt index 14daf0e6..9345c379 100644 --- a/test/unit_test/src/execution_management/binance_us/CMakeLists.txt +++ b/test/unit_test/src/execution_management/binance_us/CMakeLists.txt @@ -1,7 +1,7 @@ set(NAME execution_management_binance_us) project(${NAME}) -add_definitions(-DENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_definitions(-DENABLE_EXCHANGE_BINANCE_US) +add_compile_definitions(ENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(ENABLE_EXCHANGE_BINANCE_US) add_executable(${NAME} ${SOURCE_LOGGER} test.cpp) target_link_libraries(${NAME} GTest::GTest GTest::Main) gtest_discover_tests(${NAME}) From 0792a8c09029e7dab722f574e9f23fc6871ab6ed Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Tue, 22 Dec 2020 14:19:59 -0800 Subject: [PATCH 03/18] feat: execution management bitmex --- .../CMakeLists.txt | 5 +- .../src/execution_management_simple/main.cpp | 19 +- .../src/sample_market_making/CMakeLists.txt | 2 +- example/src/sample_market_making/main.cpp | 22 +- include/ccapi_cpp/ccapi_macro.h | 16 +- include/ccapi_cpp/ccapi_session.h | 6 + include/ccapi_cpp/ccapi_session_configs.h | 1 + .../ccapi_execution_management_service.h | 1 + ...xecution_management_service_binance_base.h | 2 +- ...capi_execution_management_service_bitmex.h | 213 ++++++++++++++++++ ...pi_execution_management_service_coinbase.h | 8 +- 11 files changed, 254 insertions(+), 41 deletions(-) create mode 100644 include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h diff --git a/example/src/execution_management_simple/CMakeLists.txt b/example/src/execution_management_simple/CMakeLists.txt index 4b07ccc7..7f0d801c 100644 --- a/example/src/execution_management_simple/CMakeLists.txt +++ b/example/src/execution_management_simple/CMakeLists.txt @@ -1,6 +1,5 @@ set(NAME execution_management_simple) project(${NAME}) -add_definitions(-DENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_definitions(-DENABLE_EXCHANGE_COINBASE) -add_definitions(-DENABLE_LOG_TRACE) +add_compile_definitions(-DENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(-DENABLE_EXCHANGE_COINBASE) add_executable(${NAME} main.cpp) diff --git a/example/src/execution_management_simple/main.cpp b/example/src/execution_management_simple/main.cpp index d3f306dd..56879b50 100644 --- a/example/src/execution_management_simple/main.cpp +++ b/example/src/execution_management_simple/main.cpp @@ -1,23 +1,6 @@ #include "ccapi_cpp/ccapi_session.h" namespace ccapi { -class ExampleLogger final: public Logger { - public: - virtual void logMessage(Logger::Severity severity, std::thread::id threadId, - std::chrono::system_clock::time_point time, - std::string fileName, int lineNumber, - std::string message) override { - std::lock_guard lock(m); - std::cout << threadId << ": [" << UtilTime::getISOTimestamp(time) << "] {" - << fileName << ":" << lineNumber << "} " - << Logger::severityToString(severity) << std::string(8, ' ') << message - << std::endl; -// lock.unlock(); - } - private: - std::mutex m; -}; -ExampleLogger exampleLogger; -Logger* Logger::logger = &exampleLogger; +Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: bool processEvent(const Event& event, Session *session) override { diff --git a/example/src/sample_market_making/CMakeLists.txt b/example/src/sample_market_making/CMakeLists.txt index 6faea68c..567593fa 100644 --- a/example/src/sample_market_making/CMakeLists.txt +++ b/example/src/sample_market_making/CMakeLists.txt @@ -2,5 +2,5 @@ set(NAME sample_market_making) project(${NAME}) add_compile_definitions(ENABLE_SERVICE_MARKET_DATA) add_compile_definitions(ENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_compile_definitions(ENABLE_EXCHANGE_BINANCE_US) +add_compile_definitions(ENABLE_EXCHANGE_COINBASE) add_executable(${NAME} main.cpp) diff --git a/example/src/sample_market_making/main.cpp b/example/src/sample_market_making/main.cpp index cfbf64c2..1db0f6b3 100644 --- a/example/src/sample_market_making/main.cpp +++ b/example/src/sample_market_making/main.cpp @@ -46,26 +46,24 @@ int main(int argc, char **argv) { } double spreadPercentage = std::stod(argv[1]); std::string orderQuantity = argv[2]; - std::string key = UtilSystem::getEnvAsString("BINANCE_US_API_KEY"); + std::string key = UtilSystem::getEnvAsString("COINBASE_API_KEY"); if (key.empty()) { - std::cerr << "Please set environment variable BINANCE_US_API_KEY" << std::endl; + std::cerr << "Please set environment variable COINBASE_API_KEY" << std::endl; return EXIT_FAILURE; } - std::string secret = UtilSystem::getEnvAsString("BINANCE_US_API_SECRET"); + std::string secret = UtilSystem::getEnvAsString("COINBASE_API_SECRET"); if (secret.empty()) { - std::cerr << "Please set environment variable BINANCE_US_API_SECRET" << std::endl; + std::cerr << "Please set environment variable COINBASE_API_SECRET" << std::endl; return EXIT_FAILURE; } SessionOptions sessionOptions; SessionConfigs sessionConfigs; MyEventHandler eventHandler; Session session(sessionOptions, sessionConfigs, &eventHandler); - // https://github.com/binance-us/binance-official-api-docs/blob/master/web-socket-streams.md: All symbols for streams are lowercase - Subscription subscription("binance-us", "btcusd", "MARKET_DEPTH"); + Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH"); session.subscribe(subscription); while (true) { - // https://github.com/binance-us/binance-official-api-docs/blob/master/rest-api.md#signed-endpoint-examples-for-post-apiv3order: All symbols for REST are uppercase - Request requestCancel(Request::Operation::CANCEL_OPEN_ORDERS, "binance-us", "BTCUSD"); + Request requestCancel(Request::Operation::CANCEL_OPEN_ORDERS, "coinbase", "BTC-USD"); session.sendRequest(requestCancel); std::cout << "Cancel all open orders" << std::endl; auto bbo = eventHandler.getBBO(); @@ -75,14 +73,14 @@ int main(int argc, char **argv) { std::string buyPrice = regularizePrice(midPrice * (1 - spreadPercentage / 100)); std::string sellPrice = regularizePrice(midPrice * (1 + spreadPercentage / 100)); std::vector requestList; - Request requestBuy(Request::Operation::CREATE_ORDER, "binance-us", "BTCUSD"); + Request requestBuy(Request::Operation::CREATE_ORDER, "coinbase", "BTC-USD"); requestBuy.appendParam({ {"SIDE", "BUY"}, {"QUANTITY", orderQuantity}, {"LIMIT_PRICE", buyPrice} }); requestList.push_back(requestBuy); - Request requestSell(Request::Operation::CREATE_ORDER, "binance-us", "BTCUSD"); + Request requestSell(Request::Operation::CREATE_ORDER, "coinbase", "BTC-USD"); requestSell.appendParam({ {"SIDE", "SELL"}, {"QUANTITY", orderQuantity}, @@ -90,8 +88,8 @@ int main(int argc, char **argv) { }); requestList.push_back(requestSell); session.sendRequest(requestList); - std::cout << "Buy " + orderQuantity + " BTCUSD at price " + buyPrice << std::endl; - std::cout << "Sell " + orderQuantity + " BTCUSD at price " + sellPrice << std::endl; + std::cout << "Buy " + orderQuantity + " BTC-USD at price " + buyPrice << std::endl; + std::cout << "Sell " + orderQuantity + " BTC-USD at price " + sellPrice << std::endl; } else { std::cout << "Insufficient market information" << std::endl; } diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index ada05d9e..67bbe323 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -186,6 +186,9 @@ #ifndef CCAPI_GEMINI_URL_REST_BASE #define CCAPI_GEMINI_URL_REST_BASE "https://api.gemini.com" #endif +#ifndef CCAPI_BITMEX_URL_REST_BASE +#define CCAPI_BITMEX_URL_REST_BASE "https://www.bitmex.com" +#endif #ifndef CCAPI_BINANCE_US_URL_REST_BASE #define CCAPI_BINANCE_US_URL_REST_BASE "https://api.binance.us" #endif @@ -213,14 +216,20 @@ #ifndef CCAPI_COINBASE_API_SECRET #define CCAPI_COINBASE_API_SECRET "COINBASE_API_SECRET" #endif +#ifndef CCAPI_COINBASE_API_PASSPHRASE +#define CCAPI_COINBASE_API_PASSPHRASE "COINBASE_API_PASSPHRASE" +#endif #ifndef CCAPI_GEMINI_API_KEY #define CCAPI_GEMINI_API_KEY "GEMINI_API_KEY" #endif #ifndef CCAPI_GEMINI_API_SECRET #define CCAPI_GEMINI_API_SECRET "GEMINI_API_SECRET" #endif -#ifndef CCAPI_COINBASE_API_PASSPHRASE -#define CCAPI_COINBASE_API_PASSPHRASE "COINBASE_API_PASSPHRASE" +#ifndef CCAPI_BITMEX_API_KEY +#define CCAPI_BITMEX_API_KEY "BITMEX_API_KEY" +#endif +#ifndef CCAPI_BITMEX_API_SECRET +#define CCAPI_BITMEX_API_SECRET "BITMEX_API_SECRET" #endif #ifndef CCAPI_BINANCE_US_API_KEY #define CCAPI_BINANCE_US_API_KEY "BINANCE_US_API_KEY" @@ -246,4 +255,7 @@ #ifndef CCAPI_HUOBI_API_SECRET #define CCAPI_HUOBI_API_SECRET "HUOBI_API_SECRET" #endif +#ifndef CCAPI_BITMEX_API_RECEIVE_WINDOW_SECONDS +#define CCAPI_BITMEX_API_RECEIVE_WINDOW_SECONDS 5 +#endif #endif // INCLUDE_CCAPI_CPP_CCAPI_MACRO_H_ diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 417b7308..390cf8b6 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -42,6 +42,9 @@ #ifdef ENABLE_EXCHANGE_GEMINI #include "ccapi_cpp/service/ccapi_execution_management_service_gemini.h" #endif +#ifdef ENABLE_EXCHANGE_BITMEX +#include "ccapi_cpp/service/ccapi_execution_management_service_bitmex.h" +#endif #ifdef ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_us.h" #endif @@ -145,6 +148,9 @@ class Session final { #ifdef ENABLE_EXCHANGE_GEMINI this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_GEMINI] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif +#ifdef ENABLE_EXCHANGE_BITMEX + this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITMEX] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +#endif #ifdef ENABLE_EXCHANGE_BINANCE_US this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_US] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif diff --git a/include/ccapi_cpp/ccapi_session_configs.h b/include/ccapi_cpp/ccapi_session_configs.h index 744ff60b..c888012b 100644 --- a/include/ccapi_cpp/ccapi_session_configs.h +++ b/include/ccapi_cpp/ccapi_session_configs.h @@ -218,6 +218,7 @@ class SessionConfigs final { this->urlRestBase = { { CCAPI_EXCHANGE_NAME_COINBASE, CCAPI_COINBASE_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_GEMINI, CCAPI_GEMINI_URL_REST_BASE}, + { CCAPI_EXCHANGE_NAME_BITMEX, CCAPI_BITMEX_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE_US, CCAPI_BINANCE_US_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE, CCAPI_BINANCE_URL_REST_BASE}, { CCAPI_EXCHANGE_NAME_BINANCE_FUTURES, CCAPI_BINANCE_FUTURES_URL_REST_BASE}, diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 2505438f..e77b1fa0 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -404,6 +404,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro : CCAPI_EM_ORDER_STATUS_CLOSED; } virtual std::vector processSuccessfulTextMessage(const Request& request, const std::string& textMessage, const TimePoint& timeReceived) { + CCAPI_LOGGER_DEBUG("textMessage = " + textMessage); rj::Document document; document.Parse(textMessage.c_str()); Message message; diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h index a2c3809d..d5af694e 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h @@ -31,7 +31,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService for (const auto& kv : param) { queryString += regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first; queryString += "="; - queryString += kv.second; + queryString += Url::urlEncode(kv.second); queryString += "&"; } } diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h new file mode 100644 index 00000000..ecb04d7e --- /dev/null +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h @@ -0,0 +1,213 @@ +#ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BITMEX_H_ +#define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BITMEX_H_ +#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef ENABLE_EXCHANGE_BITMEX +#include "ccapi_cpp/service/ccapi_execution_management_service.h" +namespace ccapi { +class ExecutionManagementServiceBitmex final : public ExecutionManagementService { + public: + ExecutionManagementServiceBitmex(std::function eventHandler, SessionOptions sessionOptions, + SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) + : ExecutionManagementService(eventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { + CCAPI_LOGGER_FUNCTION_ENTER; + this->name = CCAPI_EXCHANGE_NAME_BITMEX; + this->baseUrlRest = this->sessionConfigs.getUrlRestBase().at(this->name); + this->setHostFromUrl(this->baseUrlRest); + this->apiKeyName = CCAPI_BITMEX_API_KEY; + this->apiSecretName = CCAPI_BITMEX_API_SECRET; + this->setupCredential({this->apiKeyName, this->apiSecretName}); + std::string prefix = "/api/v1"; + this->createOrderTarget = prefix + "/order"; + this->cancelOrderTarget = prefix + "/order"; + this->getOrderTarget = prefix + "/order"; + this->getOpenOrdersTarget = prefix + "/order"; + this->cancelOpenOrdersTarget = prefix + "/order/all"; + this->orderStatusOpenSet = {"New"}; + CCAPI_LOGGER_FUNCTION_EXIT; + } + + protected: + void signRequest(http::request& req, const std::string& body, const std::map& credential) { + auto apiSecret = mapGetWithDefault(credential, this->apiSecretName, {}); + auto preSignedText = UtilString::toUpper(std::string(req.method_string())); + preSignedText += std::string(req.target()); + preSignedText += std::string(req.base().at("api-expires")); + preSignedText += body; + auto signature = Hmac::hmac(Hmac::ShaVersion::SHA256, apiSecret, preSignedText, true); + req.set("api-signature", signature); + req.body() = body; + req.prepare_payload(); + } + void appendParam(rj::Document& document, rj::Document::AllocatorType& allocator, const std::map& param, const std::map regularizationMap = {}) { + for (const auto& kv : param) { + auto key = regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first; + auto value = kv.second; + if (key == "side") { + value = value == CCAPI_EM_ORDER_SIDE_BUY ? "Buy" : "Sell"; + } + document.AddMember(rj::Value(key.c_str(), allocator).Move(), rj::Value(value.c_str(), allocator).Move(), allocator); + } + } + void appendParam(std::string& queryString, const std::map& param, const std::map regularizationMap = {}) { + for (const auto& kv : param) { + queryString += regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first; + queryString += "="; + queryString += Url::urlEncode(kv.second); + queryString += "&"; + } + } + void appendSymbolId(rj::Document& document, rj::Document::AllocatorType& allocator, const std::string symbolId) { + document.AddMember("symbol", rj::Value(symbolId.c_str(), allocator).Move(), allocator); + } + void appendSymbolId(std::string& queryString, const std::string symbolId) { + queryString += "symbol="; + queryString += symbolId; + queryString += "&"; + } + void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) override { + req.set(beast::http::field::content_type, "application/json"); + req.set("api-expires", std::to_string(std::chrono::duration_cast((now+std::chrono::seconds(CCAPI_BITMEX_API_RECEIVE_WINDOW_SECONDS)).time_since_epoch()).count())); + auto apiKey = mapGetWithDefault(credential, this->apiKeyName, {}); + req.set("api-key", apiKey); + switch (operation) { + case Request::Operation::CREATE_ORDER: + { + req.method(http::verb::post); + const std::map& param = request.getParamList().at(0); + req.target(this->createOrderTarget); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_ORDER_SIDE , "side"}, + {CCAPI_EM_ORDER_QUANTITY , "orderQty"}, + {CCAPI_EM_ORDER_LIMIT_PRICE , "price"}, + {CCAPI_EM_CLIENT_ORDER_ID , "clOrdID"} + }); + this->appendSymbolId(document, allocator, symbolId); + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + auto body = stringBuffer.GetString(); + this->signRequest(req, body, credential); + } + break; + case Request::Operation::CANCEL_ORDER: + { + req.method(http::verb::delete_); + std::string queryString; + const std::map& param = request.getParamList().at(0); + this->appendParam(queryString, param, { + {CCAPI_EM_ORDER_ID , "orderID"}, + {CCAPI_EM_CLIENT_ORDER_ID , "clOrdID"} + }); + if (!queryString.empty()) { + queryString.pop_back(); + } + req.target(this->cancelOrderTarget + "?" + queryString); + this->signRequest(req, "", credential); + } + break; + case Request::Operation::GET_ORDER: + { + req.method(http::verb::get); + std::string queryString; + const std::map& param = request.getParamList().at(0); + if (!param.empty()) { + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_ORDER_ID , "orderID"}, + {CCAPI_EM_CLIENT_ORDER_ID , "clOrdID"} + }); + queryString += "filter="; + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + queryString += Url::urlEncode(stringBuffer.GetString()); + queryString += "&"; + } + if (!symbolId.empty()) { + this->appendSymbolId(queryString, symbolId); + } + if (!queryString.empty()) { + queryString.pop_back(); + } + req.target(this->getOrderTarget + "?" + queryString); + this->signRequest(req, "", credential); + } + break; + case Request::Operation::GET_OPEN_ORDERS: + { + req.method(http::verb::get); + std::string queryString("filter="); + queryString += Url::urlEncode("{\"open\": true}"); + queryString += "&"; + if (!symbolId.empty()) { + this->appendSymbolId(queryString, symbolId); + } + if (!queryString.empty()) { + queryString.pop_back(); + } + req.target(this->getOrderTarget + "?" + queryString); + this->signRequest(req, "", credential); + } + break; + case Request::Operation::CANCEL_OPEN_ORDERS: + { + req.method(http::verb::delete_); + auto target = this->cancelOpenOrdersTarget; + if (!symbolId.empty()) { + target += "?symbol="; + target += symbolId; + } + req.target(target); + this->signRequest(req, "", credential); + } + break; + default: + CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); + } + } + std::vector extractOrderInfo(const Request::Operation operation, const rj::Document& document) override { + const std::map >& extractionFieldNameMap = { + {CCAPI_EM_ORDER_ID, std::make_pair("orderID", JsonDataType::STRING)}, + {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("clOrdID", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_QUANTITY, std::make_pair("orderQty", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("price", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::make_pair("cumQty", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_STATUS, std::make_pair("ordStatus", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("symbol", JsonDataType::STRING)} + }; + std::vector elementList; + if (document.IsObject()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(document, extractionFieldNameMap)); + } else { + for (const auto& x : document.GetArray()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(x, extractionFieldNameMap)); + } + } + return elementList; + } + std::vector processSuccessfulTextMessage(const Request& request, const std::string& textMessage, const TimePoint& timeReceived) override { + const std::string& quotedTextMessage = std::regex_replace(textMessage, std::regex("(\\[|,|\":)(-?\\d+\\.?\\d*)"), "$1\"$2\""); + return ExecutionManagementService::processSuccessfulTextMessage(request, quotedTextMessage, timeReceived); + } + Element extractOrderInfo(const rj::Value& x, const std::map >& extractionFieldNameMap) override { + Element element = ExecutionManagementService::extractOrderInfo(x, extractionFieldNameMap); + { + auto it1 = x.FindMember("cumQty"); + auto it2 = x.FindMember("avgPx"); + if (it1 != x.MemberEnd() && it2 != x.MemberEnd()) { + element.insert(CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::to_string(std::stod(it1->value.GetString()) * std::stod(it2->value.GetString()))); + } + } + return element; + } +}; +} /* namespace ccapi */ +#endif +#endif +#endif // INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BITMEX_H_ diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h index 85168e41..68cff87c 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h @@ -27,7 +27,7 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi } protected: - void signRequest(http::request& req, const std::string& body, const std::map& param, const TimePoint& now, const std::map& credential) { + void signRequest(http::request& req, const std::string& body, const std::map& credential) { auto apiSecret = mapGetWithDefault(credential, this->apiSecretName, {}); auto preSignedText = std::string(req.base().at("CB-ACCESS-TIMESTAMP")); preSignedText += UtilString::toUpper(std::string(req.method_string())); @@ -78,7 +78,7 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi rj::Writer writer(stringBuffer); document.Accept(writer); auto body = stringBuffer.GetString(); - this->signRequest(req, body, param, now, credential); + this->signRequest(req, body, credential); } break; case Request::Operation::CANCEL_ORDER: @@ -94,7 +94,7 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi target += symbolId; } req.target(target); - this->signRequest(req, "", param, now, credential); + this->signRequest(req, "", credential); } break; case Request::Operation::GET_ORDER: @@ -106,7 +106,7 @@ class ExecutionManagementServiceCoinbase final : public ExecutionManagementServi : ""; auto target = std::regex_replace(this->getOrderTarget, std::regex("\\{id\\}"), id); req.target(target); - this->signRequest(req, "", param, now, credential); + this->signRequest(req, "", credential); } break; case Request::Operation::GET_OPEN_ORDERS: From 1cda8927580a65e4f864dbb4a0c1ca1d74ada401 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Tue, 29 Dec 2020 13:33:59 -0800 Subject: [PATCH 04/18] draft feat: execution management huobi --- README.md | 5 +- include/ccapi_cpp/ccapi_decimal.h | 4 +- include/ccapi_cpp/ccapi_element.h | 4 +- include/ccapi_cpp/ccapi_event.h | 2 +- include/ccapi_cpp/ccapi_event_dispatcher.h | 6 +- include/ccapi_cpp/ccapi_event_handler.h | 4 +- include/ccapi_cpp/ccapi_hmac.h | 2 +- include/ccapi_cpp/ccapi_http_connection.h | 2 +- include/ccapi_cpp/ccapi_http_retry.h | 2 +- include/ccapi_cpp/ccapi_logger.h | 72 +- include/ccapi_cpp/ccapi_macro.h | 3 + include/ccapi_cpp/ccapi_market_data_message.h | 4 +- include/ccapi_cpp/ccapi_message.h | 8 +- include/ccapi_cpp/ccapi_request.h | 4 +- include/ccapi_cpp/ccapi_session.h | 18 +- include/ccapi_cpp/ccapi_session_configs.h | 3 +- include/ccapi_cpp/ccapi_session_options.h | 7 +- include/ccapi_cpp/ccapi_subscription.h | 4 +- include/ccapi_cpp/ccapi_url.h | 2 +- include/ccapi_cpp/ccapi_util.h | 629 ----------------- include/ccapi_cpp/ccapi_util_private.h | 636 ++++++++++++++++++ include/ccapi_cpp/ccapi_ws_connection.h | 2 +- ...api_execution_management_service_binance.h | 2 +- ...ution_management_service_binance_futures.h | 2 +- ..._execution_management_service_binance_us.h | 2 +- ...capi_execution_management_service_bitmex.h | 2 +- ...pi_execution_management_service_coinbase.h | 2 +- ...capi_execution_management_service_gemini.h | 2 +- .../service/ccapi_market_data_service.h | 2 +- .../ccapi_market_data_service_binance.h | 2 +- ...capi_market_data_service_binance_futures.h | 2 +- .../ccapi_market_data_service_binance_us.h | 2 +- .../ccapi_market_data_service_bitfinex.h | 2 +- .../ccapi_market_data_service_bitmex.h | 2 +- .../ccapi_market_data_service_bitstamp.h | 2 +- .../ccapi_market_data_service_coinbase.h | 2 +- .../ccapi_market_data_service_gemini.h | 2 +- .../service/ccapi_market_data_service_huobi.h | 2 +- .../ccapi_market_data_service_kraken.h | 2 +- .../service/ccapi_market_data_service_okex.h | 2 +- .../ccapi_cpp/service/ccapi_service_context.h | 2 +- test/build_test/CMakeLists.txt | 10 +- 42 files changed, 747 insertions(+), 724 deletions(-) create mode 100644 include/ccapi_cpp/ccapi_util_private.h diff --git a/README.md b/README.md index 8f6c854a..7a09df8e 100644 --- a/README.md +++ b/README.md @@ -193,9 +193,8 @@ Extend a subclass, e.g. `MyLogger`, from class `Logger` and override method `log ``` namespace ccapi { class MyLogger final: public Logger { - public: - virtual void logMessage(Logger::Severity severity, std::thread::id threadId, - std::chrono::system_clock::time_point time, + virtual void logMessage(std::string severity, std::string threadId, + std::string timeISO, std::string fileName, int lineNumber, std::string message) override { ... diff --git a/include/ccapi_cpp/ccapi_decimal.h b/include/ccapi_cpp/ccapi_decimal.h index 003f4a05..adf016ea 100644 --- a/include/ccapi_cpp/ccapi_decimal.h +++ b/include/ccapi_cpp/ccapi_decimal.h @@ -1,10 +1,10 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_DECIMAL_H_ #define INCLUDE_CCAPI_CPP_CCAPI_DECIMAL_H_ #include -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { // minimalistic just for the purpose of being used as the key of a map -class Decimal final { +class Decimal CCAPI_FINAL { public: explicit Decimal(std::string originalValue) { std::string value = originalValue; diff --git a/include/ccapi_cpp/ccapi_element.h b/include/ccapi_cpp/ccapi_element.h index c65fca2e..6bbd92be 100644 --- a/include/ccapi_cpp/ccapi_element.h +++ b/include/ccapi_cpp/ccapi_element.h @@ -2,9 +2,9 @@ #define INCLUDE_CCAPI_CPP_CCAPI_ELEMENT_H_ #include #include -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { -class Element final { +class Element CCAPI_FINAL { public: void insert(std::string name, std::string value) { this->nameValueMap.insert(std::pair(name, value)); diff --git a/include/ccapi_cpp/ccapi_event.h b/include/ccapi_cpp/ccapi_event.h index bfbcfb00..8f7aad29 100644 --- a/include/ccapi_cpp/ccapi_event.h +++ b/include/ccapi_cpp/ccapi_event.h @@ -4,7 +4,7 @@ #include "ccapi_cpp/ccapi_logger.h" #include "ccapi_cpp/ccapi_message.h" namespace ccapi { -class Event final { +class Event CCAPI_FINAL { public: enum class Type { UNKNOWN, diff --git a/include/ccapi_cpp/ccapi_event_dispatcher.h b/include/ccapi_cpp/ccapi_event_dispatcher.h index 10c6c8d1..e908ec95 100644 --- a/include/ccapi_cpp/ccapi_event_dispatcher.h +++ b/include/ccapi_cpp/ccapi_event_dispatcher.h @@ -9,11 +9,11 @@ #include #include #include "ccapi_cpp/ccapi_logger.h" -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { -class EventDispatcher final { +class EventDispatcher CCAPI_FINAL { public: - explicit EventDispatcher(const size_t numDispatcherThreads = 1) + explicit EventDispatcher(const int numDispatcherThreads = 1) : numDispatcherThreads(numDispatcherThreads) { CCAPI_LOGGER_FUNCTION_ENTER; CCAPI_LOGGER_TRACE("numDispatcherThreads = "+size_tToString(numDispatcherThreads)); diff --git a/include/ccapi_cpp/ccapi_event_handler.h b/include/ccapi_cpp/ccapi_event_handler.h index cec6ba8c..fc80c759 100644 --- a/include/ccapi_cpp/ccapi_event_handler.h +++ b/include/ccapi_cpp/ccapi_event_handler.h @@ -7,7 +7,9 @@ class EventHandler { public: virtual ~EventHandler() { } - virtual bool processEvent(const Event& event, Session *session) = 0; + virtual bool processEvent(const Event& event, Session *session) { + return true; + } // An implementation of processEvent should process the specified // 'event' which originates from the specified 'session' and // return true to indicate events should continue to be delivered diff --git a/include/ccapi_cpp/ccapi_hmac.h b/include/ccapi_cpp/ccapi_hmac.h index 3e3a942a..966ef368 100644 --- a/include/ccapi_cpp/ccapi_hmac.h +++ b/include/ccapi_cpp/ccapi_hmac.h @@ -2934,7 +2934,7 @@ hmacResult (HMACContext * ctx, uint8_t * digest) #include "ccapi_cpp/ccapi_macro.h" #include "ccapi_cpp/ccapi_logger.h" namespace ccapi { -class Hmac final { +class Hmac CCAPI_FINAL { // https://github.com/Yubico/yubico-c-client/blob/ykclient-2.15/sha384-512.c public: enum class ShaVersion { diff --git a/include/ccapi_cpp/ccapi_http_connection.h b/include/ccapi_cpp/ccapi_http_connection.h index 9180b1b3..56afacb4 100644 --- a/include/ccapi_cpp/ccapi_http_connection.h +++ b/include/ccapi_cpp/ccapi_http_connection.h @@ -6,7 +6,7 @@ #include "ccapi_cpp/ccapi_request.h" namespace beast = boost::beast; namespace ccapi { -class HttpConnection final { +class HttpConnection CCAPI_FINAL { public: HttpConnection(std::string host, std::string port, std::shared_ptr > streamPtr) : host(host), port(port), streamPtr(streamPtr) { } diff --git a/include/ccapi_cpp/ccapi_http_retry.h b/include/ccapi_cpp/ccapi_http_retry.h index 8960cc59..012fdded 100644 --- a/include/ccapi_cpp/ccapi_http_retry.h +++ b/include/ccapi_cpp/ccapi_http_retry.h @@ -2,7 +2,7 @@ #define INCLUDE_CCAPI_CPP_CCAPI_HTTP_RETRY_H_ #include namespace ccapi { -class HttpRetry final { +class HttpRetry CCAPI_FINAL { public: explicit HttpRetry(int numRetry = 0, int numRedirect = 0, std::string redirectUrlStr = "", std::shared_ptr > promisePtr = std::make_shared >(nullptr)): numRetry(numRetry), numRedirect(numRedirect), promisePtr(promisePtr) {} diff --git a/include/ccapi_cpp/ccapi_logger.h b/include/ccapi_cpp/ccapi_logger.h index e285cb7c..9115f78f 100644 --- a/include/ccapi_cpp/ccapi_logger.h +++ b/include/ccapi_cpp/ccapi_logger.h @@ -49,73 +49,59 @@ #include #include #include "ccapi_cpp/ccapi_macro.h" +#include "date/date.h" +#include "ccapi_cpp/ccapi_util.h" namespace ccapi { class Logger { public: - enum class Severity { - FATAL = 1, - ERROR = 2, - WARN = 3, - INFO = 4, - DEBUG = 5, - TRACE = 6 - }; - static std::string severityToString(Severity severity) { - std::string output; - switch (severity) { - case Severity::FATAL: - output = "FATAL"; - break; - case Severity::ERROR: - output = "ERROR"; - break; - case Severity::WARN: - output = "WARN"; - break; - case Severity::INFO: - output = "INFO"; - break; - case Severity::DEBUG: - output = "DEBUG"; - break; - case Severity::TRACE: - output = "TRACE"; - break; - default: - CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); - } - return output; - } + std::string SEVERITY_FATAL = "FATAL"; + std::string SEVERITY_ERROR = "ERROR"; + std::string SEVERITY_WARN = "WARN"; + std::string SEVERITY_INFO = "INFO"; + std::string SEVERITY_DEBUG = "DEBUG"; + std::string SEVERITY_TRACE = "TRACE"; virtual ~Logger() { } - virtual void logMessage(Severity severity, std::thread::id threadId, std::chrono::system_clock::time_point time, - std::string fileName, int lineNumber, std::string message) { - } void fatal(std::thread::id threadId, std::chrono::system_clock::time_point time, std::string fileName, int lineNumber, std::string message) { - this->logMessage(Severity::FATAL, threadId, time, fileName, lineNumber, message); + this->logMessagePrivate(SEVERITY_FATAL, threadId, time, fileName, lineNumber, message); } void error(std::thread::id threadId, std::chrono::system_clock::time_point time, std::string fileName, int lineNumber, std::string message) { - this->logMessage(Severity::ERROR, threadId, time, fileName, lineNumber, message); + this->logMessagePrivate(SEVERITY_ERROR, threadId, time, fileName, lineNumber, message); } void warn(std::thread::id threadId, std::chrono::system_clock::time_point time, std::string fileName, int lineNumber, std::string message) { - this->logMessage(Severity::WARN, threadId, time, fileName, lineNumber, message); + this->logMessagePrivate(SEVERITY_WARN, threadId, time, fileName, lineNumber, message); } void info(std::thread::id threadId, std::chrono::system_clock::time_point time, std::string fileName, int lineNumber, std::string message) { - this->logMessage(Severity::INFO, threadId, time, fileName, lineNumber, message); + this->logMessagePrivate(SEVERITY_INFO, threadId, time, fileName, lineNumber, message); } void debug(std::thread::id threadId, std::chrono::system_clock::time_point time, std::string fileName, int lineNumber, std::string message) { - this->logMessage(Severity::DEBUG, threadId, time, fileName, lineNumber, message); + this->logMessagePrivate(SEVERITY_DEBUG, threadId, time, fileName, lineNumber, message); } void trace(std::thread::id threadId, std::chrono::system_clock::time_point time, std::string fileName, int lineNumber, std::string message) { - this->logMessage(Severity::TRACE, threadId, time, fileName, lineNumber, message); + this->logMessagePrivate(SEVERITY_TRACE, threadId, time, fileName, lineNumber, message); } static Logger* logger; + + protected: + virtual void logMessage(std::string severity, std::string threadId, std::string timeISO, + std::string fileName, std::string lineNumber, std::string message) { + } + void logMessagePrivate(std::string severity, std::thread::id threadId, std::chrono::system_clock::time_point time, + std::string fileName, int lineNumber, std::string message) { + std::stringstream ss; + ss << threadId; + this->logMessage(severity, ss.str(), getISOTimestamp(time), fileName, std::to_string(lineNumber), message); + } + template + static std::string getISOTimestamp(TimePoint tp, std::string fmt = "%FT%TZ") { + return date::format(fmt.c_str(), date::floor(tp)); + } }; } /* namespace ccapi */ #endif // INCLUDE_CCAPI_CPP_CCAPI_LOGGER_H_ diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 67bbe323..0a5b0935 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -1,5 +1,8 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_MACRO_H_ #define INCLUDE_CCAPI_CPP_CCAPI_MACRO_H_ +#ifndef CCAPI_FINAL +#define CCAPI_FINAL final +#endif #define CCAPI_MARKET_DEPTH "MARKET_DEPTH" #define CCAPI_TRADE "TRADE" #ifndef CCAPI_MARKET_DEPTH_MAX diff --git a/include/ccapi_cpp/ccapi_market_data_message.h b/include/ccapi_cpp/ccapi_market_data_message.h index f967a6ce..b05103aa 100644 --- a/include/ccapi_cpp/ccapi_market_data_message.h +++ b/include/ccapi_cpp/ccapi_market_data_message.h @@ -1,10 +1,10 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_MARKET_DATA_MESSAGE_H_ #define INCLUDE_CCAPI_CPP_CCAPI_MARKET_DATA_MESSAGE_H_ #include "ccapi_cpp/ccapi_logger.h" -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" // #include "ccapi_message.h" namespace ccapi { -class MarketDataMessage final { +class MarketDataMessage CCAPI_FINAL { public: enum class Type { UNKNOWN, diff --git a/include/ccapi_cpp/ccapi_message.h b/include/ccapi_cpp/ccapi_message.h index 906245cb..852544ef 100644 --- a/include/ccapi_cpp/ccapi_message.h +++ b/include/ccapi_cpp/ccapi_message.h @@ -5,7 +5,7 @@ #include "ccapi_cpp/ccapi_element.h" #include "ccapi_cpp/ccapi_logger.h" namespace ccapi { -class Message final { +class Message CCAPI_FINAL { public: enum class RecapType { UNKNOWN, @@ -124,6 +124,9 @@ class Message final { TimePoint getTime() const { return time; } + std::string getTimeISO() const { + return UtilTime::getISOTimestamp(time); + } void setTime(TimePoint time) { this->time = time; } @@ -142,6 +145,9 @@ class Message final { TimePoint getTimeReceived() const { return timeReceived; } + std::string getTimeReceivedISO() const { + return UtilTime::getISOTimestamp(timeReceived); + } void setTimeReceived(TimePoint timeReceived) { this->timeReceived = timeReceived; } diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index afc85fa5..e35bdc57 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -5,9 +5,9 @@ #include #include #include "ccapi_cpp/ccapi_macro.h" -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { -class Request final { +class Request CCAPI_FINAL { public: enum class Operation { UNKNOWN, diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 390cf8b6..fc8a3dce 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -1,5 +1,6 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_SESSION_H_ #define INCLUDE_CCAPI_CPP_CCAPI_SESSION_H_ +#include "ccapi_cpp/ccapi_macro.h" #ifdef ENABLE_SERVICE_MARKET_DATA #ifdef ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_market_data_service_coinbase.h" @@ -54,6 +55,9 @@ #ifdef ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h" #endif +#ifdef ENABLE_EXCHANGE_HUOBI +#include "ccapi_cpp/service/ccapi_execution_management_service_huobi.h" +#endif #endif #include "ccapi_cpp/ccapi_session_options.h" #include "ccapi_cpp/ccapi_session_configs.h" @@ -62,7 +66,6 @@ #include #include #include "ccapi_cpp/ccapi_queue.h" -#include "ccapi_cpp/ccapi_macro.h" #include "ccapi_cpp/ccapi_event_dispatcher.h" #include "ccapi_cpp/ccapi_event_handler.h" #include "ccapi_cpp/ccapi_event.h" @@ -70,7 +73,7 @@ #include "ccapi_cpp/ccapi_request.h" #include "ccapi_cpp/service/ccapi_service.h" namespace ccapi { -class Session final { +class Session CCAPI_FINAL { public: Session(const Session&) = delete; Session& operator=(const Session&) = delete; @@ -98,6 +101,9 @@ class Session final { } ~Session() { CCAPI_LOGGER_FUNCTION_ENTER; + if (this->useInternalEventDispatcher) { + delete this->eventDispatcher; + } CCAPI_LOGGER_FUNCTION_EXIT; } void start() { @@ -160,6 +166,9 @@ class Session final { #ifdef ENABLE_EXCHANGE_BINANCE_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_FUTURES] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif +#ifdef ENABLE_EXCHANGE_HUOBI + this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_HUOBI] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +#endif #endif for (const auto& x : this->serviceByServiceNameExchangeMap) { auto serviceName = x.first; @@ -343,7 +352,9 @@ class Session final { } CCAPI_LOGGER_FUNCTION_EXIT; } - Queue eventQueue; + const Queue& getEventQueue() const { + return eventQueue; + } private: SessionOptions sessionOptions; @@ -354,6 +365,7 @@ class Session final { wspp::lib::shared_ptr serviceContextPtr; std::map > > serviceByServiceNameExchangeMap; std::thread t; + Queue eventQueue; }; } /* namespace ccapi */ #endif // INCLUDE_CCAPI_CPP_CCAPI_SESSION_H_ diff --git a/include/ccapi_cpp/ccapi_session_configs.h b/include/ccapi_cpp/ccapi_session_configs.h index c888012b..cc1c9cfe 100644 --- a/include/ccapi_cpp/ccapi_session_configs.h +++ b/include/ccapi_cpp/ccapi_session_configs.h @@ -6,8 +6,9 @@ #include #include #include "ccapi_cpp/ccapi_logger.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { -class SessionConfigs final { +class SessionConfigs CCAPI_FINAL { public: SessionConfigs() : SessionConfigs({}, {}, {}) { } diff --git a/include/ccapi_cpp/ccapi_session_options.h b/include/ccapi_cpp/ccapi_session_options.h index da07754d..07c6be52 100644 --- a/include/ccapi_cpp/ccapi_session_options.h +++ b/include/ccapi_cpp/ccapi_session_options.h @@ -1,9 +1,10 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_SESSION_OPTIONS_H_ #define INCLUDE_CCAPI_CPP_CCAPI_SESSION_OPTIONS_H_ +#include "ccapi_cpp/ccapi_macro.h" #include -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { -class SessionOptions final { +class SessionOptions CCAPI_FINAL { public: std::string toString() const { std::string output = "SessionOptions [warnLateEventMaxMilliSeconds = " + ccapi::toString(warnLateEventMaxMilliSeconds) @@ -25,7 +26,7 @@ class SessionOptions final { bool enableOneIoContextPerExchange{}; long pingIntervalMilliSeconds{10000}; long pongTimeoutMilliSeconds{5000}; - long maxEventQueueSize{0}; + int maxEventQueueSize{0}; bool enableOneHttpConnectionPerRequest{}; int httpMaxNumRetry{3}; int httpMaxNumRedirect{3}; diff --git a/include/ccapi_cpp/ccapi_subscription.h b/include/ccapi_cpp/ccapi_subscription.h index c4282e0c..a72f36d7 100644 --- a/include/ccapi_cpp/ccapi_subscription.h +++ b/include/ccapi_cpp/ccapi_subscription.h @@ -3,9 +3,9 @@ #include "ccapi_cpp/ccapi_macro.h" #include #include -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" namespace ccapi { -class Subscription final { +class Subscription CCAPI_FINAL { public: Subscription(std::string exchange, std::string instrument, std::string field, std::string options = "", std::string correlationId = "", std::map credential = {}) diff --git a/include/ccapi_cpp/ccapi_url.h b/include/ccapi_cpp/ccapi_url.h index a1b82fe6..0e0a7970 100644 --- a/include/ccapi_cpp/ccapi_url.h +++ b/include/ccapi_cpp/ccapi_url.h @@ -4,7 +4,7 @@ #include namespace beast = boost::beast; namespace ccapi { -class Url final { +class Url CCAPI_FINAL { public: explicit Url(std::string urlStr) { std::regex ex("^(.*:)//([A-Za-z0-9\\-\\.]+)(:[0-9]+)?(.*)$"); diff --git a/include/ccapi_cpp/ccapi_util.h b/include/ccapi_cpp/ccapi_util.h index 149ab763..6e7bbd75 100644 --- a/include/ccapi_cpp/ccapi_util.h +++ b/include/ccapi_cpp/ccapi_util.h @@ -1,636 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_UTIL_H_ #define INCLUDE_CCAPI_CPP_CCAPI_UTIL_H_ -//#include -//#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "date/date.h" -#include "ccapi_cpp/ccapi_logger.h" namespace ccapi { typedef std::chrono::time_point TimePoint; -class UtilString final { - public: - static std::string generateRandomString(const size_t length) { - auto randchar = []() -> char { - const char charset[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - const size_t max_index = (sizeof(charset) - 1); - return charset[ rand() % max_index ]; - }; - std::string str(length, 0); - std::generate_n(str.begin(), length, randchar); - return str; - } - static std::vector split(const std::string& original, const std::string& delimiter) { - std::string s = original; - std::vector output; - size_t pos = 0; - std::string token; - while ((pos = s.find(delimiter)) != std::string::npos) { - token = s.substr(0, pos); - output.push_back(token); - s.erase(0, pos + delimiter.length()); - } - output.push_back(s); - return output; - } - static std::string join(const std::vector& strings, const std::string& delimiter) { - switch (strings.size()) { - case 0: - return ""; - case 1: - return strings[0]; - default: - std::ostringstream joined; - std::copy(strings.begin(), strings.end() - 1, std::ostream_iterator(joined, delimiter.c_str())); - joined << *strings.rbegin(); - return joined.str(); - } - } - static std::string toUpper(const std::string& input) { - std::string output(input); - std::transform(output.begin(), output.end(), output.begin(), ::toupper); - return output; - } - static std::string toLower(const std::string& input) { - std::string output(input); - std::transform(output.begin(), output.end(), output.begin(), ::tolower); - return output; - } - static std::string ltrim(const std::string& original, const std::string& chars = "\t\n\v\f\r ") { - std::string str = original; - str.erase(0, str.find_first_not_of(chars)); - return str; - } - static std::string rtrim(const std::string& original, const std::string& chars = "\t\n\v\f\r ") { - std::string str = original; - str.erase(str.find_last_not_of(chars) + 1); - return str; - } - static std::string trim(const std::string& original, const std::string& chars = "\t\n\v\f\r ") { - return ltrim(rtrim(original, chars), chars); - } - static std::string firstNCharacter(const std::string& str, size_t n) { - if (str.length() > n) { - return str.substr(0, n) + "..."; - } else { - return str; - } - } - static std::string normalizeDecimalString(const std::string& str) { - if (str.find('.') != std::string::npos) { - return UtilString::rtrim(UtilString::rtrim(str, "0"), "."); - } else { - return str; - } - } - static std::string leftPadTo(const std::string str, const size_t padToLength, const char paddingChar) { - std::string copy = str; - if (padToLength > copy.size()) { - copy.insert(0, padToLength - copy.size(), paddingChar); - } - return copy; - } - static std::string rightPadTo(const std::string str, const size_t padToLength, const char paddingChar) { - std::string copy = str; - if (padToLength > copy.size()) { - copy.append(padToLength - copy.size(), paddingChar); - } - return copy; - } -}; -class UtilTime final { - public: - static TimePoint parse(std::string s) { - TimePoint tp; - std::istringstream ss { s }; - ss >> date::parse("%FT%TZ", tp); - if (ss.fail()) { - CCAPI_LOGGER_FATAL("unable to parse time string"); - } - return tp; - } - static TimePoint makeTimePoint(std::pair timePair) { - auto tp = TimePoint(std::chrono::duration(timePair.first)); - tp += std::chrono::nanoseconds(timePair.second); - return tp; - } - static std::pair divide(TimePoint tp) { - auto then = tp.time_since_epoch(); - auto s = std::chrono::duration_cast(then); - then -= s; - auto ns = std::chrono::duration_cast(then); - return std::make_pair(s.count(), ns.count()); - } - static std::pair divide(std::string seconds) { - if (seconds.find(".") != std::string::npos) { - auto splittedSeconds = UtilString::split(UtilString::rtrim(UtilString::rtrim(seconds, "0"), "."), "."); - return std::make_pair( - std::stoi(splittedSeconds[0]), - splittedSeconds.size() == 1 ? 0 : std::stoi(UtilString::rightPadTo(splittedSeconds[1], 9, '0'))); - } else { - return std::make_pair(std::stoi(seconds), 0); - } - } - static std::string getISOTimestamp(TimePoint tp) { - return date::format("%FT%TZ", date::floor(tp)); - } - static TimePoint makeTimePointFromMilliseconds(long milliseconds) { - return TimePoint(std::chrono::milliseconds(milliseconds)); - } -}; -class UtilAlgorithm final { - public: - static std::string stringToHex(const std::string& input) { - static const char hex_digits[] = "0123456789ABCDEF"; - std::string output; - output.reserve(input.length() * 2); - for (unsigned char c : input) { - output.push_back(hex_digits[c >> 4]); - output.push_back(hex_digits[c & 15]); - } - return output; - } - static int hexValue(unsigned char hex_digit) { - static const signed char hex_values[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - }; - int value = hex_values[hex_digit]; - if (value == -1) throw std::invalid_argument("invalid hex digit"); - return value; - } - std::string hexToString(const std::string& input) { - const auto len = input.length(); - if (len & 1) throw std::invalid_argument("odd length"); - std::string output; - output.reserve(len / 2); - for (auto it = input.begin(); it != input.end(); ) { - int hi = hexValue(*it++); - int lo = hexValue(*it++); - output.push_back(hi << 4 | lo); - } - return output; - } - static std::string base64Encode(const std::string &in) { - std::string out; - int val=0, valb=-6; - for (unsigned char c : in) { - val = (val<<8) + c; - valb += 8; - while (valb>=0) { - out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val>>valb)&0x3F]); - valb-=6; - } - } - if (valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val<<8)>>(valb+8))&0x3F]); - while (out.size()%4) out.push_back('='); - return out; - } - static std::string base64Decode(const std::string &in) { - std::string out; - std::vector T(256,-1); - for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; - int val=0, valb=-8; - for (unsigned char c : in) { - if (T[c] == -1) break; - val = (val<<6) + T[c]; - valb += 6; - if (valb>=0) { - out.push_back(char((val>>valb)&0xFF)); - valb-=8; - } - } - return out; - } - static double exponentialBackoff(double initial, double multiplier, double base, double exponent) { - return initial + multiplier * (pow(base, exponent) - 1); - } - template static uint_fast32_t crc(InputIterator first, InputIterator last); -// static std::string hmac(std::string key, std::string msg, bool returnHex = false, const std::string& algorithm = "") { -// unsigned char hash[32]; -//#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) && OPENSSL_VERSION_MAJOR <= 1 && (OPENSSL_VERSION_MAJOR != 1 || OPENSSL_VERSION_MINOR < 1) -// HMAC_CTX hmac; -// HMAC_CTX_init(&hmac); -// if (algorithm == "sha384") { -// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha384(), NULL); -// } else { -// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL); -// } -// HMAC_Update(&hmac, (unsigned char*)&msg[0], msg.length()); -// unsigned int len = 32; -// HMAC_Final(&hmac, hash, &len); -// HMAC_CTX_cleanup(&hmac); -//#else -// HMAC_CTX *hmac = HMAC_CTX_new(); -// if (algorithm == "sha384") { -// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha384(), NULL); -// } else { -// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha256(), NULL); -// } -// HMAC_Update(hmac, (unsigned char*)&msg[0], msg.length()); -// unsigned int len = 32; -// HMAC_Final(hmac, hash, &len); -// HMAC_CTX_free(hmac); -//#endif -// std::stringstream ss; -// if (returnHex) { -// ss << std::hex << std::setfill('0'); -// for (int i = 0; i < len; i++) { -// ss << std::hex << std::setw(2) << (unsigned int)hash[i]; -// } -// } else { -// ss << std::setfill('0'); -// for (int i = 0; i < len; i++) { -// ss << hash[i]; -// } -// } -// return (ss.str()); -// } -}; -template uint_fast32_t UtilAlgorithm::crc(InputIterator first, InputIterator last) { - static auto const table = []() { - auto const reversed_polynomial = uint_fast32_t {0xEDB88320uL}; - // This is a function object that calculates the checksum for a value, - // then increments the value, starting from zero. - struct byte_checksum { - uint_fast32_t operator()() noexcept { - auto checksum = static_cast(n++); - for (auto i = 0; i < 8; ++i) - checksum = (checksum >> 1) ^ ((checksum & 0x1u) ? reversed_polynomial : 0); - return checksum; - } - unsigned n = 0; - }; - auto table = std::array {}; - std::generate(table.begin(), table.end(), byte_checksum {}); - return table; - }(); - // Calculate the checksum - make sure to clip to 32 bits, for systems that don't - // have a true (fast) 32-bit type. - return uint_fast32_t { 0xFFFFFFFFuL } - & ~std::accumulate(first, last, ~uint_fast32_t { 0 } & uint_fast32_t { 0xFFFFFFFFuL }, - [](uint_fast32_t checksum, std::uint_fast8_t value) - { return table[(checksum ^ value) & 0xFFu] ^ (checksum >> 8);}); -} -class UtilSystem final { - public: - static bool getEnvAsBool(const std::string variableName, - const bool defaultValue = false) { - const char* env_p = std::getenv(variableName.c_str()); - if (env_p) { - return UtilString::toLower(std::string(env_p)) == "true"; - } else { - return defaultValue; - } - } - static std::string getEnvAsString(const std::string variableName, - const std::string defaultValue = "") { - const char* env_p = std::getenv(variableName.c_str()); - if (env_p) { - return std::string(env_p); - } else { - return defaultValue; - } - } - static int getEnvAsInt(const std::string variableName, - const int defaultValue = 0) { - const char* env_p = std::getenv(variableName.c_str()); - if (env_p) { - return std::stoi(std::string(env_p)); - } else { - return defaultValue; - } - } - static long getEnvAsLong(const std::string variableName, - const long defaultValue = 0) { - const char* env_p = std::getenv(variableName.c_str()); - if (env_p) { - return std::stol(std::string(env_p)); - } else { - return defaultValue; - } - } - static bool checkEnvExist(const std::string& variableName) { - const char* env_p = std::getenv(variableName.c_str()); - if (env_p) { - return true; - } else { - return false; - } - } -}; -inline std::string size_tToString(const size_t &t) { - std::stringstream ss; - ss << t; - return ss.str(); -} -template -std::string intToHex(T i) { - std::stringstream stream; - stream << std::hex << i; - return stream.str(); -} -template -int ceilSearch(const std::vector& c, int low, int high, T x) { - int i = 0; - if (x <= c[low]) { - return low; - } - for (i = low; i < high; i++) { - if (c[i] == x) { - return i; - } - if (c[i] < x && c[i + 1] >= x) { - return i + 1; - } - } - return -1; -} -template -struct reversion_wrapper { - T& iterable; -}; -template -auto begin(reversion_wrapper w) { - return std::rbegin(w.iterable); -} -template -auto end(reversion_wrapper w) { - return std::rend(w.iterable); -} -template -reversion_wrapper reverse(T&& iterable) { - return {iterable}; -} -template bool firstNSame(const std::map& c1, const std::map& c2, size_t n) { - if (c1.empty() || c2.empty()) { - return c1.empty() && c2.empty(); - } - size_t i = 0; - for (auto i1 = c1.begin(), i2 = c2.begin(); i1 != c1.end() && i2 != c2.end(); ++i1, ++i2) { - if (i >= n) { - return true; - } - if (i1 == c1.end() || i2 == c2.end()) { - return false; - } - if (i1->first != i2->first || i1->second != i2->second) { - return false; - } - ++i; - } - return true; -} -template bool lastNSame(const std::map& c1, const std::map& c2, size_t n) { - if (c1.empty() || c2.empty()) { - return c1.empty() && c2.empty(); - } - size_t i = 0; - for (auto i1 = c1.rbegin(), i2 = c2.rbegin(); i1 != c1.rend() || i2 != c2.rend(); ++i1, ++i2) { - if (i >= n) { - return true; - } - if (i1 == c1.rend() || i2 == c2.rend()) { - return false; - } - if (i1->first != i2->first || i1->second != i2->second) { - return false; - } - ++i; - } - return true; -} -template void keepFirstN(std::map& c, size_t n) { - if (!c.empty()) { - auto it = c.begin(); - std::advance(it, std::min(n, c.size())); - c.erase(it, c.end()); - } -} -template void keepLastN(std::map& c, size_t n) { - if (!c.empty()) { - auto it = c.end(); - std::advance(it, -std::min(n, c.size())); - c.erase(c.begin(), it); - } -} -template typename std::enable_if< - std::is_same().toString()), std::string>::value, std::string>::type toString( - const T &t) { - return t.toString(); -} -template typename std::enable_if< - std::is_same())), std::string>::value, std::string>::type toString( - const T &t) { - return std::to_string(t); -} -template typename std::enable_if::value, std::string>::type toString( - const T &t) { - return t; -} -template typename std::enable_if::value, std::string>::type toString( - const T &t) { - std::pair timePair = UtilTime::divide(t); - return "(" + std::to_string(timePair.first) + "," + std::to_string(timePair.second) + ")"; -} -template std::string toString(const std::unordered_set& c); -template std::string toString(const std::set& c); -template std::string toString(const std::map& c); -template std::string toString(const std::unordered_map& c); -template std::string firstNToString(const std::map& c, size_t n); -template std::string lastNToString(const std::map& c, size_t n); -template std::string toString(const std::vector& c); -template std::string firstNToString(const std::vector& c, size_t n); -template std::string toString(const std::unordered_set& c) { - std::string output = "["; - auto size = c.size(); - auto i = 0; - for (const auto& elem : c) { - output += toString(elem); - if (i < size - 1) { - output += ", "; - } - ++i; - } - output += "]"; - return output; -} -template std::string toString(const std::set& c) { - std::string output = "["; - auto size = c.size(); - auto i = 0; - for (const auto& elem : c) { - output += toString(elem); - if (i < size - 1) { - output += ", "; - } - ++i; - } - output += "]"; - return output; -} -template std::string toString(const std::map& c) { - std::string output = "{"; - auto size = c.size(); - auto i = 0; - for (const auto& elem : c) { - output += toString(elem.first); - output += "="; - output += toString(elem.second); - if (i < size - 1) { - output += ", "; - } - ++i; - } - output += "}"; - return output; -} -template std::string toString(const std::unordered_map& c) { - std::string output = "{"; - auto size = c.size(); - auto i = 0; - for (const auto& elem : c) { - output += toString(elem.first); - output += "="; - output += toString(elem.second); - if (i < size - 1) { - output += ", "; - } - ++i; - } - output += "}"; - return output; -} -template std::string firstNToString(const std::map& c, size_t n) { - std::string output = "{"; - auto size = c.size(); - auto i = 0; - for (const auto& elem : c) { - if (i >= n) { - break; - } - output += toString(elem.first); - output += "="; - output += toString(elem.second); - if (i < size - 1) { - output += ", "; - } - ++i; - } - if (i < size - 1 && i > 0) { - output += "..."; - } - output += "}"; - return output; -} -template std::string lastNToString(const std::map& c, size_t n) { - std::string output = "{"; - auto size = c.size(); - auto i = 0; - for (const auto& elem : reverse(c)) { - if (i >= n) { - break; - } - output += toString(elem.first); - output += "="; - output += toString(elem.second); - if (i < size - 1) { - output += ", "; - } - ++i; - } - if (i < size - 1 && i > 0) { - output += "..."; - } - output += "}"; - return output; -} -template std::string toString(const std::vector& c) { - std::string output = "[ "; - auto size = c.size(); - auto i = 0; - for (const auto& elem : c) { - output += toString(elem); - if (i < size - 1) { - output += ", "; - } - ++i; - } - output += " ]"; - return output; -} -template std::string firstNToString(const std::vector& c, size_t n) { - std::string output = "[ "; - auto size = c.size(); - auto i = 0; - for (const auto& elem : c) { - if (i >= n) { - break; - } - output += toString(elem); - if (i < size - 1) { - output += ", "; - } - ++i; - } - if (i < size - 1 && i > 0) { - output += "..."; - } - output += " ]"; - return output; -} -template std::map > invertMapMulti(const std::map& c) { - std::map > output; - for (const auto& elem : c) { - output[elem.second].push_back(elem.first); - } - return output; -} -template std::map invertMap(const std::map& c) { - std::map output; - for (const auto& elem : c) { - output.insert(std::make_pair(elem.second, elem.first)); - } - return output; -} -template class C, typename K, typename V, typename... Args> -V mapGetWithDefault(const C& m, K const& key, const V & defaultValue) { - typename C::const_iterator it = m.find(key); - if (it == m.end()) { - return defaultValue; - } - return it->second; -} } /* namespace ccapi */ #endif // INCLUDE_CCAPI_CPP_CCAPI_UTIL_H_ diff --git a/include/ccapi_cpp/ccapi_util_private.h b/include/ccapi_cpp/ccapi_util_private.h new file mode 100644 index 00000000..0f33557b --- /dev/null +++ b/include/ccapi_cpp/ccapi_util_private.h @@ -0,0 +1,636 @@ +#ifndef INCLUDE_CCAPI_CPP_CCAPI_UTIL_PRIVATE_H_ +#define INCLUDE_CCAPI_CPP_CCAPI_UTIL_PRIVATE_H_ +//#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "date/date.h" +#include "ccapi_cpp/ccapi_logger.h" +#include "ccapi_cpp/ccapi_util.h" +namespace ccapi { +class UtilString CCAPI_FINAL { + public: + static std::string generateRandomString(const size_t length) { + auto randchar = []() -> char { + const char charset[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[ rand() % max_index ]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; + } + static std::vector split(const std::string& original, const std::string& delimiter) { + std::string s = original; + std::vector output; + size_t pos = 0; + std::string token; + while ((pos = s.find(delimiter)) != std::string::npos) { + token = s.substr(0, pos); + output.push_back(token); + s.erase(0, pos + delimiter.length()); + } + output.push_back(s); + return output; + } + static std::string join(const std::vector& strings, const std::string& delimiter) { + switch (strings.size()) { + case 0: + return ""; + case 1: + return strings[0]; + default: + std::ostringstream joined; + std::copy(strings.begin(), strings.end() - 1, std::ostream_iterator(joined, delimiter.c_str())); + joined << *strings.rbegin(); + return joined.str(); + } + } + static std::string toUpper(const std::string& input) { + std::string output(input); + std::transform(output.begin(), output.end(), output.begin(), ::toupper); + return output; + } + static std::string toLower(const std::string& input) { + std::string output(input); + std::transform(output.begin(), output.end(), output.begin(), ::tolower); + return output; + } + static std::string ltrim(const std::string& original, const std::string& chars = "\t\n\v\f\r ") { + std::string str = original; + str.erase(0, str.find_first_not_of(chars)); + return str; + } + static std::string rtrim(const std::string& original, const std::string& chars = "\t\n\v\f\r ") { + std::string str = original; + str.erase(str.find_last_not_of(chars) + 1); + return str; + } + static std::string trim(const std::string& original, const std::string& chars = "\t\n\v\f\r ") { + return ltrim(rtrim(original, chars), chars); + } + static std::string firstNCharacter(const std::string& str, size_t n) { + if (str.length() > n) { + return str.substr(0, n) + "..."; + } else { + return str; + } + } + static std::string normalizeDecimalString(const std::string& str) { + if (str.find('.') != std::string::npos) { + return UtilString::rtrim(UtilString::rtrim(str, "0"), "."); + } else { + return str; + } + } + static std::string leftPadTo(const std::string str, const size_t padToLength, const char paddingChar) { + std::string copy = str; + if (padToLength > copy.size()) { + copy.insert(0, padToLength - copy.size(), paddingChar); + } + return copy; + } + static std::string rightPadTo(const std::string str, const size_t padToLength, const char paddingChar) { + std::string copy = str; + if (padToLength > copy.size()) { + copy.append(padToLength - copy.size(), paddingChar); + } + return copy; + } +}; +class UtilTime CCAPI_FINAL { + public: + static TimePoint parse(std::string s) { + TimePoint tp; + std::istringstream ss { s }; + ss >> date::parse("%FT%TZ", tp); + if (ss.fail()) { + CCAPI_LOGGER_FATAL("unable to parse time string"); + } + return tp; + } + static TimePoint makeTimePoint(std::pair timePair) { + auto tp = TimePoint(std::chrono::duration(timePair.first)); + tp += std::chrono::nanoseconds(timePair.second); + return tp; + } + static std::pair divide(TimePoint tp) { + auto then = tp.time_since_epoch(); + auto s = std::chrono::duration_cast(then); + then -= s; + auto ns = std::chrono::duration_cast(then); + return std::make_pair(s.count(), ns.count()); + } + static std::pair divide(std::string seconds) { + if (seconds.find(".") != std::string::npos) { + auto splittedSeconds = UtilString::split(UtilString::rtrim(UtilString::rtrim(seconds, "0"), "."), "."); + return std::make_pair( + std::stoi(splittedSeconds[0]), + splittedSeconds.size() == 1 ? 0 : std::stoi(UtilString::rightPadTo(splittedSeconds[1], 9, '0'))); + } else { + return std::make_pair(std::stoi(seconds), 0); + } + } + template + static std::string getISOTimestamp(TimePoint tp, std::string fmt = "%FT%TZ") { + return date::format(fmt.c_str(), date::floor(tp)); + } + static TimePoint makeTimePointFromMilliseconds(long milliseconds) { + return TimePoint(std::chrono::milliseconds(milliseconds)); + } +}; +class UtilAlgorithm CCAPI_FINAL { + public: + static std::string stringToHex(const std::string& input) { + static const char hex_digits[] = "0123456789ABCDEF"; + std::string output; + output.reserve(input.length() * 2); + for (unsigned char c : input) { + output.push_back(hex_digits[c >> 4]); + output.push_back(hex_digits[c & 15]); + } + return output; + } + static int hexValue(unsigned char hex_digit) { + static const signed char hex_values[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + int value = hex_values[hex_digit]; + if (value == -1) throw std::invalid_argument("invalid hex digit"); + return value; + } + std::string hexToString(const std::string& input) { + const auto len = input.length(); + if (len & 1) throw std::invalid_argument("odd length"); + std::string output; + output.reserve(len / 2); + for (auto it = input.begin(); it != input.end(); ) { + int hi = hexValue(*it++); + int lo = hexValue(*it++); + output.push_back(hi << 4 | lo); + } + return output; + } + static std::string base64Encode(const std::string &in) { + std::string out; + int val=0, valb=-6; + for (unsigned char c : in) { + val = (val<<8) + c; + valb += 8; + while (valb>=0) { + out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val>>valb)&0x3F]); + valb-=6; + } + } + if (valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val<<8)>>(valb+8))&0x3F]); + while (out.size()%4) out.push_back('='); + return out; + } + static std::string base64Decode(const std::string &in) { + std::string out; + std::vector T(256,-1); + for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; + int val=0, valb=-8; + for (unsigned char c : in) { + if (T[c] == -1) break; + val = (val<<6) + T[c]; + valb += 6; + if (valb>=0) { + out.push_back(char((val>>valb)&0xFF)); + valb-=8; + } + } + return out; + } + static double exponentialBackoff(double initial, double multiplier, double base, double exponent) { + return initial + multiplier * (pow(base, exponent) - 1); + } + template static uint_fast32_t crc(InputIterator first, InputIterator last); +// static std::string hmac(std::string key, std::string msg, bool returnHex = false, const std::string& algorithm = "") { +// unsigned char hash[32]; +//#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) && OPENSSL_VERSION_MAJOR <= 1 && (OPENSSL_VERSION_MAJOR != 1 || OPENSSL_VERSION_MINOR < 1) +// HMAC_CTX hmac; +// HMAC_CTX_init(&hmac); +// if (algorithm == "sha384") { +// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha384(), NULL); +// } else { +// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL); +// } +// HMAC_Update(&hmac, (unsigned char*)&msg[0], msg.length()); +// unsigned int len = 32; +// HMAC_Final(&hmac, hash, &len); +// HMAC_CTX_cleanup(&hmac); +//#else +// HMAC_CTX *hmac = HMAC_CTX_new(); +// if (algorithm == "sha384") { +// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha384(), NULL); +// } else { +// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha256(), NULL); +// } +// HMAC_Update(hmac, (unsigned char*)&msg[0], msg.length()); +// unsigned int len = 32; +// HMAC_Final(hmac, hash, &len); +// HMAC_CTX_free(hmac); +//#endif +// std::stringstream ss; +// if (returnHex) { +// ss << std::hex << std::setfill('0'); +// for (int i = 0; i < len; i++) { +// ss << std::hex << std::setw(2) << (unsigned int)hash[i]; +// } +// } else { +// ss << std::setfill('0'); +// for (int i = 0; i < len; i++) { +// ss << hash[i]; +// } +// } +// return (ss.str()); +// } +}; +template uint_fast32_t UtilAlgorithm::crc(InputIterator first, InputIterator last) { + static auto const table = []() { + auto const reversed_polynomial = uint_fast32_t {0xEDB88320uL}; + // This is a function object that calculates the checksum for a value, + // then increments the value, starting from zero. + struct byte_checksum { + uint_fast32_t operator()() noexcept { + auto checksum = static_cast(n++); + for (auto i = 0; i < 8; ++i) + checksum = (checksum >> 1) ^ ((checksum & 0x1u) ? reversed_polynomial : 0); + return checksum; + } + unsigned n = 0; + }; + auto table = std::array {}; + std::generate(table.begin(), table.end(), byte_checksum {}); + return table; + }(); + // Calculate the checksum - make sure to clip to 32 bits, for systems that don't + // have a true (fast) 32-bit type. + return uint_fast32_t { 0xFFFFFFFFuL } + & ~std::accumulate(first, last, ~uint_fast32_t { 0 } & uint_fast32_t { 0xFFFFFFFFuL }, + [](uint_fast32_t checksum, std::uint_fast8_t value) + { return table[(checksum ^ value) & 0xFFu] ^ (checksum >> 8);}); +} +class UtilSystem CCAPI_FINAL { + public: + static bool getEnvAsBool(const std::string variableName, + const bool defaultValue = false) { + const char* env_p = std::getenv(variableName.c_str()); + if (env_p) { + return UtilString::toLower(std::string(env_p)) == "true"; + } else { + return defaultValue; + } + } + static std::string getEnvAsString(const std::string variableName, + const std::string defaultValue = "") { + const char* env_p = std::getenv(variableName.c_str()); + if (env_p) { + return std::string(env_p); + } else { + return defaultValue; + } + } + static int getEnvAsInt(const std::string variableName, + const int defaultValue = 0) { + const char* env_p = std::getenv(variableName.c_str()); + if (env_p) { + return std::stoi(std::string(env_p)); + } else { + return defaultValue; + } + } + static long getEnvAsLong(const std::string variableName, + const long defaultValue = 0) { + const char* env_p = std::getenv(variableName.c_str()); + if (env_p) { + return std::stol(std::string(env_p)); + } else { + return defaultValue; + } + } + static bool checkEnvExist(const std::string& variableName) { + const char* env_p = std::getenv(variableName.c_str()); + if (env_p) { + return true; + } else { + return false; + } + } +}; +inline std::string size_tToString(const size_t &t) { + std::stringstream ss; + ss << t; + return ss.str(); +} +template +std::string intToHex(T i) { + std::stringstream stream; + stream << std::hex << i; + return stream.str(); +} +template +int ceilSearch(const std::vector& c, int low, int high, T x) { + int i = 0; + if (x <= c[low]) { + return low; + } + for (i = low; i < high; i++) { + if (c[i] == x) { + return i; + } + if (c[i] < x && c[i + 1] >= x) { + return i + 1; + } + } + return -1; +} +template +struct reversion_wrapper { + T& iterable; +}; +template +auto begin(reversion_wrapper w) { + return std::rbegin(w.iterable); +} +template +auto end(reversion_wrapper w) { + return std::rend(w.iterable); +} +template +reversion_wrapper reverse(T&& iterable) { + return {iterable}; +} +template bool firstNSame(const std::map& c1, const std::map& c2, size_t n) { + if (c1.empty() || c2.empty()) { + return c1.empty() && c2.empty(); + } + size_t i = 0; + for (auto i1 = c1.begin(), i2 = c2.begin(); i1 != c1.end() && i2 != c2.end(); ++i1, ++i2) { + if (i >= n) { + return true; + } + if (i1 == c1.end() || i2 == c2.end()) { + return false; + } + if (i1->first != i2->first || i1->second != i2->second) { + return false; + } + ++i; + } + return true; +} +template bool lastNSame(const std::map& c1, const std::map& c2, size_t n) { + if (c1.empty() || c2.empty()) { + return c1.empty() && c2.empty(); + } + size_t i = 0; + for (auto i1 = c1.rbegin(), i2 = c2.rbegin(); i1 != c1.rend() || i2 != c2.rend(); ++i1, ++i2) { + if (i >= n) { + return true; + } + if (i1 == c1.rend() || i2 == c2.rend()) { + return false; + } + if (i1->first != i2->first || i1->second != i2->second) { + return false; + } + ++i; + } + return true; +} +template void keepFirstN(std::map& c, size_t n) { + if (!c.empty()) { + auto it = c.begin(); + std::advance(it, std::min(n, c.size())); + c.erase(it, c.end()); + } +} +template void keepLastN(std::map& c, size_t n) { + if (!c.empty()) { + auto it = c.end(); + std::advance(it, -std::min(n, c.size())); + c.erase(c.begin(), it); + } +} +template typename std::enable_if< + std::is_same().toString()), std::string>::value, std::string>::type toString( + const T &t) { + return t.toString(); +} +template typename std::enable_if< + std::is_same())), std::string>::value, std::string>::type toString( + const T &t) { + return std::to_string(t); +} +template typename std::enable_if::value, std::string>::type toString( + const T &t) { + return t; +} +template typename std::enable_if::value, std::string>::type toString( + const T &t) { + std::pair timePair = UtilTime::divide(t); + return "(" + std::to_string(timePair.first) + "," + std::to_string(timePair.second) + ")"; +} +template std::string toString(const std::unordered_set& c); +template std::string toString(const std::set& c); +template std::string toString(const std::map& c); +template std::string toString(const std::unordered_map& c); +template std::string firstNToString(const std::map& c, size_t n); +template std::string lastNToString(const std::map& c, size_t n); +template std::string toString(const std::vector& c); +template std::string firstNToString(const std::vector& c, size_t n); +template std::string toString(const std::unordered_set& c) { + std::string output = "["; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + output += toString(elem); + if (i < size - 1) { + output += ", "; + } + ++i; + } + output += "]"; + return output; +} +template std::string toString(const std::set& c) { + std::string output = "["; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + output += toString(elem); + if (i < size - 1) { + output += ", "; + } + ++i; + } + output += "]"; + return output; +} +template std::string toString(const std::map& c) { + std::string output = "{"; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + output += toString(elem.first); + output += "="; + output += toString(elem.second); + if (i < size - 1) { + output += ", "; + } + ++i; + } + output += "}"; + return output; +} +template std::string toString(const std::unordered_map& c) { + std::string output = "{"; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + output += toString(elem.first); + output += "="; + output += toString(elem.second); + if (i < size - 1) { + output += ", "; + } + ++i; + } + output += "}"; + return output; +} +template std::string firstNToString(const std::map& c, size_t n) { + std::string output = "{"; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + if (i >= n) { + break; + } + output += toString(elem.first); + output += "="; + output += toString(elem.second); + if (i < size - 1) { + output += ", "; + } + ++i; + } + if (i < size - 1 && i > 0) { + output += "..."; + } + output += "}"; + return output; +} +template std::string lastNToString(const std::map& c, size_t n) { + std::string output = "{"; + auto size = c.size(); + auto i = 0; + for (const auto& elem : reverse(c)) { + if (i >= n) { + break; + } + output += toString(elem.first); + output += "="; + output += toString(elem.second); + if (i < size - 1) { + output += ", "; + } + ++i; + } + if (i < size - 1 && i > 0) { + output += "..."; + } + output += "}"; + return output; +} +template std::string toString(const std::vector& c) { + std::string output = "[ "; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + output += toString(elem); + if (i < size - 1) { + output += ", "; + } + ++i; + } + output += " ]"; + return output; +} +template std::string firstNToString(const std::vector& c, size_t n) { + std::string output = "[ "; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + if (i >= n) { + break; + } + output += toString(elem); + if (i < size - 1) { + output += ", "; + } + ++i; + } + if (i < size - 1 && i > 0) { + output += "..."; + } + output += " ]"; + return output; +} +template std::map > invertMapMulti(const std::map& c) { + std::map > output; + for (const auto& elem : c) { + output[elem.second].push_back(elem.first); + } + return output; +} +template std::map invertMap(const std::map& c) { + std::map output; + for (const auto& elem : c) { + output.insert(std::make_pair(elem.second, elem.first)); + } + return output; +} +template class C, typename K, typename V, typename... Args> +V mapGetWithDefault(const C& m, K const& key, const V & defaultValue) { + typename C::const_iterator it = m.find(key); + if (it == m.end()) { + return defaultValue; + } + return it->second; +} +} /* namespace ccapi */ +#endif // INCLUDE_CCAPI_CPP_CCAPI_UTIL_PRIVATE_H_ diff --git a/include/ccapi_cpp/ccapi_ws_connection.h b/include/ccapi_cpp/ccapi_ws_connection.h index f98a6c7e..56ffae7a 100644 --- a/include/ccapi_cpp/ccapi_ws_connection.h +++ b/include/ccapi_cpp/ccapi_ws_connection.h @@ -5,7 +5,7 @@ #include "ccapi_cpp/ccapi_subscription.h" namespace wspp = websocketpp; namespace ccapi { -class WsConnection final { +class WsConnection CCAPI_FINAL { public: WsConnection(std::string url, std::vector subscriptionList) : url(url), diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h index 1bb0a148..db2f6f79 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h @@ -7,7 +7,7 @@ #endif #include "ccapi_cpp/service/ccapi_execution_management_service_binance_base.h" namespace ccapi { -class ExecutionManagementServiceBinance final : public ExecutionManagementServiceBinanceBase { +class ExecutionManagementServiceBinance CCAPI_FINAL : public ExecutionManagementServiceBinanceBase { public: ExecutionManagementServiceBinance(std::function eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h index fd41b598..e1cd4317 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_execution_management_service_binance_base.h" namespace ccapi { -class ExecutionManagementServiceBinanceFutures final : public ExecutionManagementServiceBinanceBase { +class ExecutionManagementServiceBinanceFutures CCAPI_FINAL : public ExecutionManagementServiceBinanceBase { public: ExecutionManagementServiceBinanceFutures(std::function eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h index 19e8b4c3..0285a968 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_base.h" namespace ccapi { -class ExecutionManagementServiceBinanceUs final : public ExecutionManagementServiceBinanceBase { +class ExecutionManagementServiceBinanceUs CCAPI_FINAL : public ExecutionManagementServiceBinanceBase { public: ExecutionManagementServiceBinanceUs(std::function eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h index ecb04d7e..045be52d 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_BITMEX #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { -class ExecutionManagementServiceBitmex final : public ExecutionManagementService { +class ExecutionManagementServiceBitmex CCAPI_FINAL : public ExecutionManagementService { public: ExecutionManagementServiceBitmex(std::function eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h index 68cff87c..d5fb54b8 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { -class ExecutionManagementServiceCoinbase final : public ExecutionManagementService { +class ExecutionManagementServiceCoinbase CCAPI_FINAL : public ExecutionManagementService { public: ExecutionManagementServiceCoinbase(std::function eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h index 1a3473c1..1aa11fc1 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_GEMINI #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { -class ExecutionManagementServiceGemini final : public ExecutionManagementService { +class ExecutionManagementServiceGemini CCAPI_FINAL : public ExecutionManagementService { public: ExecutionManagementServiceGemini(std::function eventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) diff --git a/include/ccapi_cpp/service/ccapi_market_data_service.h b/include/ccapi_cpp/service/ccapi_market_data_service.h index 35f3b489..14172e84 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service.h @@ -18,7 +18,7 @@ #include "websocketpp/config/asio_client.hpp" #include "websocketpp/client.hpp" #include "ccapi_cpp/ccapi_logger.h" -#include "ccapi_cpp/ccapi_util.h" +#include "ccapi_cpp/ccapi_util_private.h" #include "ccapi_cpp/ccapi_decimal.h" #include "ccapi_cpp/ccapi_session_options.h" #include "ccapi_cpp/ccapi_session_configs.h" diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance.h index b98016d0..371fbf5a 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_BINANCE #include "ccapi_cpp/service/ccapi_market_data_service_binance_base.h" namespace ccapi { -class MarketDataServiceBinance final : public MarketDataServiceBinanceBase { +class MarketDataServiceBinance CCAPI_FINAL : public MarketDataServiceBinanceBase { public: MarketDataServiceBinance(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataServiceBinanceBase(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_BINANCE; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_futures.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_futures.h index dcf4dd12..c2dfd63d 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_futures.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_futures.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_market_data_service_binance_base.h" namespace ccapi { -class MarketDataServiceBinanceFutures final : public MarketDataServiceBinanceBase { +class MarketDataServiceBinanceFutures CCAPI_FINAL : public MarketDataServiceBinanceBase { public: MarketDataServiceBinanceFutures(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataServiceBinanceBase(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_BINANCE_FUTURES; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_us.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_us.h index 1b199f89..2f13a15c 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_us.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_us.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_market_data_service_binance_base.h" namespace ccapi { -class MarketDataServiceBinanceUs final : public MarketDataServiceBinanceBase { +class MarketDataServiceBinanceUs CCAPI_FINAL : public MarketDataServiceBinanceBase { public: MarketDataServiceBinanceUs(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataServiceBinanceBase(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_BINANCE_US; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h index 1992fb28..2b080c95 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h @@ -5,7 +5,7 @@ #include "ccapi_cpp/service/ccapi_market_data_service.h" #include namespace ccapi { -class MarketDataServiceBitfinex final : public MarketDataService { +class MarketDataServiceBitfinex CCAPI_FINAL : public MarketDataService { public: MarketDataServiceBitfinex(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_BITFINEX; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h index d2cf1845..8888b20f 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h @@ -5,7 +5,7 @@ #include "ccapi_cpp/service/ccapi_market_data_service.h" #include namespace ccapi { -class MarketDataServiceBitmex final : public MarketDataService { +class MarketDataServiceBitmex CCAPI_FINAL : public MarketDataService { public: MarketDataServiceBitmex(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_BITMEX; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h index efc035af..544270c8 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_BITSTAMP #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { -class MarketDataServiceBitstamp final : public MarketDataService { +class MarketDataServiceBitstamp CCAPI_FINAL : public MarketDataService { public: MarketDataServiceBitstamp(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_BITSTAMP; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h b/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h index 5566a1af..2a8c1e92 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { -class MarketDataServiceCoinbase final : public MarketDataService { +class MarketDataServiceCoinbase CCAPI_FINAL : public MarketDataService { public: MarketDataServiceCoinbase(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_COINBASE; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h b/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h index 2cce3090..4433aefa 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_GEMINI #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { -class MarketDataServiceGemini final : public MarketDataService { +class MarketDataServiceGemini CCAPI_FINAL : public MarketDataService { public: MarketDataServiceGemini(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_GEMINI; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h index d6f093be..0eec49b8 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h @@ -5,7 +5,7 @@ #include "ccapi_cpp/service/ccapi_market_data_service.h" #include namespace ccapi { -class MarketDataServiceHuobi final : public MarketDataService { +class MarketDataServiceHuobi CCAPI_FINAL : public MarketDataService { public: MarketDataServiceHuobi(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_HUOBI; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h index 76b46b78..90f2036d 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_KRAKEN #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { -class MarketDataServiceKraken final : public MarketDataService { +class MarketDataServiceKraken CCAPI_FINAL : public MarketDataService { public: MarketDataServiceKraken(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_KRAKEN; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_okex.h b/include/ccapi_cpp/service/ccapi_market_data_service_okex.h index 676f263e..72468a49 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_okex.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_okex.h @@ -4,7 +4,7 @@ #ifdef ENABLE_EXCHANGE_OKEX #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { -class MarketDataServiceOkex final : public MarketDataService { +class MarketDataServiceOkex CCAPI_FINAL : public MarketDataService { public: MarketDataServiceOkex(std::function wsEventHandler, SessionOptions sessionOptions, SessionConfigs sessionConfigs, std::shared_ptr serviceContextPtr): MarketDataService(wsEventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->name = CCAPI_EXCHANGE_NAME_OKEX; diff --git a/include/ccapi_cpp/service/ccapi_service_context.h b/include/ccapi_cpp/service/ccapi_service_context.h index 1460c74a..9380a302 100644 --- a/include/ccapi_cpp/service/ccapi_service_context.h +++ b/include/ccapi_cpp/service/ccapi_service_context.h @@ -7,7 +7,7 @@ namespace wspp = websocketpp; namespace ccapi { -class ServiceContext final { +class ServiceContext CCAPI_FINAL { public: typedef wspp::lib::asio::io_service IoContext; typedef wspp::lib::shared_ptr IoContextPtr; diff --git a/test/build_test/CMakeLists.txt b/test/build_test/CMakeLists.txt index bdbe79cf..3226fb21 100644 --- a/test/build_test/CMakeLists.txt +++ b/test/build_test/CMakeLists.txt @@ -1,9 +1,15 @@ set(NAME build_test) project(${NAME}) -set(SERVICE_LIST "MARKET_DATA") -set(EXCHANGE_LIST "COINBASE" "GEMINI" "KRAKEN" "BITSTAMP" "BITFINEX" "BITMEX" "BINANCE_US" "BINANCE" "BINANCE_FUTURES" "HUOBI" "OKEX") +set(SERVICE_LIST "MARKET_DATA" "EXECUTION_MANAGEMENT") +set(MARKET_DATA_EXCHANGE_LIST "COINBASE" "GEMINI" "KRAKEN" "BITSTAMP" "BITFINEX" "BITMEX" "BINANCE_US" "BINANCE" "BINANCE_FUTURES" "HUOBI" "OKEX") +set(EXECUTION_MANAGEMENT_EXCHANGE_LIST "COINBASE" "GEMINI" "BITMEX" "BINANCE_US" "BINANCE" "BINANCE_FUTURES" "HUOBI") foreach(SERVICE IN LISTS SERVICE_LIST) message(STATUS "SERVICE=${SERVICE}") + if("${SERVICE}" STREQUAL "MARKET_DATA") + set(EXCHANGE_LIST ${MARKET_DATA_EXCHANGE_LIST}) + elseif("${SERVICE}" STREQUAL "EXECUTION_MANAGEMENT") + set(EXCHANGE_LIST ${EXECUTION_MANAGEMENT_EXCHANGE_LIST}) + endif() foreach(EXCHANGE IN LISTS EXCHANGE_LIST) message(STATUS "EXCHANGE=${EXCHANGE}") set(CCAPI_CPP_TARGET_NAME "${SERVICE}__${EXCHANGE}") From b095999fb88c529e45e371d70345f1b37d6d64ab Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Tue, 29 Dec 2020 20:40:37 -0800 Subject: [PATCH 05/18] fix: small fix --- include/ccapi_cpp/ccapi_request.h | 3 +++ include/ccapi_cpp/ccapi_session.h | 3 --- include/ccapi_cpp/ccapi_subscription.h | 3 +++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index e35bdc57..bbbf9bfa 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -51,6 +51,9 @@ class Request CCAPI_FINAL { this->correlationId = UtilString::generateRandomString(CCAPI_CORRELATION_ID_GENERATED_LENGTH); } } +#ifdef SWIG + Request(){} +#endif std::string toString() const { std::map shortCredential; for (const auto& x : credential) { diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index fc8a3dce..6b7e31b0 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -101,9 +101,6 @@ class Session CCAPI_FINAL { } ~Session() { CCAPI_LOGGER_FUNCTION_ENTER; - if (this->useInternalEventDispatcher) { - delete this->eventDispatcher; - } CCAPI_LOGGER_FUNCTION_EXIT; } void start() { diff --git a/include/ccapi_cpp/ccapi_subscription.h b/include/ccapi_cpp/ccapi_subscription.h index a72f36d7..b50e63a3 100644 --- a/include/ccapi_cpp/ccapi_subscription.h +++ b/include/ccapi_cpp/ccapi_subscription.h @@ -7,6 +7,9 @@ namespace ccapi { class Subscription CCAPI_FINAL { public: +#ifdef SWIG + Subscription(){} +#endif Subscription(std::string exchange, std::string instrument, std::string field, std::string options = "", std::string correlationId = "", std::map credential = {}) : exchange(exchange), instrument(instrument), field(field), correlationId(correlationId), credential(credential) { From 0865391f2043be14376408a0b174dc5af70fb80b Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Wed, 30 Dec 2020 12:43:33 -0800 Subject: [PATCH 06/18] feat: execution management huobi --- ...xecution_management_service_binance_base.h | 2 +- ...capi_execution_management_service_bitmex.h | 2 +- ...ccapi_execution_management_service_huobi.h | 204 ++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h index d5af694e..e818260a 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h @@ -37,7 +37,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService } void appendSymbolId(std::string& queryString, const std::string symbolId) { queryString += "symbol="; - queryString += symbolId; + queryString += Url::urlEncode(symbolId); queryString += "&"; } void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) override { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h index 045be52d..43e2cb74 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h @@ -61,7 +61,7 @@ class ExecutionManagementServiceBitmex CCAPI_FINAL : public ExecutionManagementS } void appendSymbolId(std::string& queryString, const std::string symbolId) { queryString += "symbol="; - queryString += symbolId; + queryString += Url::urlEncode(symbolId); queryString += "&"; } void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) override { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h new file mode 100644 index 00000000..e030583a --- /dev/null +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h @@ -0,0 +1,204 @@ +#ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_HUOBI_H_ +#define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_HUOBI_H_ +#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef ENABLE_EXCHANGE_HUOBI +#include "ccapi_cpp/service/ccapi_execution_management_service.h" +namespace ccapi { +class ExecutionManagementServiceHuobi CCAPI_FINAL : public ExecutionManagementService { + public: + ExecutionManagementServiceHuobi(std::function eventHandler, SessionOptions sessionOptions, + SessionConfigs sessionConfigs, ServiceContextPtr serviceContextPtr) + : ExecutionManagementService(eventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { + CCAPI_LOGGER_FUNCTION_ENTER; + this->name = CCAPI_EXCHANGE_NAME_HUOBI; + this->baseUrlRest = this->sessionConfigs.getUrlRestBase().at(this->name); + this->setHostFromUrl(this->baseUrlRest); + this->apiKeyName = CCAPI_HUOBI_API_KEY; + this->apiSecretName = CCAPI_HUOBI_API_SECRET; + this->setupCredential({this->apiKeyName, this->apiSecretName}); + this->createOrderTarget = "/v1/order/orders/place"; + this->cancelOrderTarget = "/v1/order/orders/{order-id}/submitcancel"; + this->cancelOrderByClientOrderIdTarget = "/v1/order/orders/submitCancelClientOrder"; + this->getOrderTarget = "/v1/order/orders/{order-id}"; + this->getOrderByClientOrderIdTarget = "/v1/order/orders/getClientOrder"; + this->getOpenOrdersTarget = "/v1/order/openOrders"; + CCAPI_LOGGER_FUNCTION_EXIT; + } + + protected: + void signRequest(http::request& req, const std::string& path, const std::map& queryParamMap, const std::map& credential) { + std::string preSignedText; + preSignedText += std::string(request.method_string()); + preSignedText += "\n"; + preSignedText += this->host; + preSignedText += "\n"; + preSignedText += path; + preSignedText += "\n"; + std::string queryString; + int i = 0; + for (const auto& kv : queryParamMap) { + queryString += kv.first; + queryString += "="; + queryString += kv.second; + if (i < queryParamMap.size() - 1) { + queryString += "&"; + } + } + preSignedText += queryString; + auto apiSecret = mapGetWithDefault(credential, this->apiSecretName, {}); + auto signature = UtilAlgorithm::base64Encode(Hmac::hmac(Hmac::ShaVersion::SHA256, apiSecret, preSignedText)); + queryString += "&signature="; + queryString += Url::urlEncode(signature); + req.target(path + "?" + queryString); + } + void appendParam(rj::Document& document, rj::Document::AllocatorType& allocator, const std::map& param, const std::map regularizationMap = {}) { + for (const auto& kv : param) { + auto key = regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first; + auto value = kv.second; + if (key == "type") { + value = value == CCAPI_EM_ORDER_SIDE_BUY ? "buy-limit" : "sell-limit"; + } + document.AddMember(rj::Value(key.c_str(), allocator).Move(), rj::Value(value.c_str(), allocator).Move(), allocator); + } + } + void appendParam(std::map& queryParamMap, const std::map& param, const std::map regularizationMap = {}) { + for (const auto& kv : param) { + queryParamMap.insert( + std::make_pair( + regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first, + Url::urlEncode(kv.second) + ) + ); + } + } + void appendSymbolId(rj::Document& document, rj::Document::AllocatorType& allocator, const std::string symbolId) { + document.AddMember("symbol", rj::Value(symbolId.c_str(), allocator).Move(), allocator); + } + void appendSymbolId(std::map& queryParamMap, const std::string symbolId) { + queryParamMap.insert(std::make_pair("symbol", Url::urlEncode(symbol))); + } + void convertReq(const Request& request, const TimePoint& now, http::request& req, const std::map& credential, const std::string& symbolId, const Request::Operation operation) override { + req.set(beast::http::field::content_type, "application/json"); + auto apiKey = mapGetWithDefault(credential, this->apiKeyName, {}); + std::map queryParamMap; + queryParamMap.insert(std::make_pair("AccessKeyId", apiKey)); + queryParamMap.insert(std::make_pair("SignatureMethod", "HmacSHA256")); + queryParamMap.insert(std::make_pair("SignatureVersion", "2")); + std::string timestamp = UtilTime::getISOTimestamp(now, "%FT"); + queryParamMap.insert(std::make_pair("Timestamp", Url::urlEncode(timestamp))); + switch (operation) { + case Request::Operation::CREATE_ORDER: + { + req.method(http::verb::post); + const std::map& param = request.getParamList().at(0); + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_ORDER_SIDE , "type"}, + {CCAPI_EM_ORDER_QUANTITY , "amount"}, + {CCAPI_EM_ORDER_LIMIT_PRICE , "price"}, + {CCAPI_EM_CLIENT_ORDER_ID , "client-order-id"}, + {CCAPI_EM_ACCOUNT_ID , "account-id"} + }); + this->appendSymbolId(document, allocator, symbolId); + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + auto body = stringBuffer.GetString(); + req.body() = body; + req.prepare_payload(); + this->signRequest(req, this->createOrderTarget, queryParamMap, credential); + } + break; + case Request::Operation::CANCEL_ORDER: + { + req.method(http::verb::post); + const std::map& param = request.getParamList().at(0); + auto shouldUseOrderId = param.find(CCAPI_EM_ORDER_ID) != param.end(); + std::string id = shouldUseOrderId ? param.at(CCAPI_EM_ORDER_ID) + : param.find(CCAPI_EM_CLIENT_ORDER_ID) != param.end() ? "client:" + param.at(CCAPI_EM_CLIENT_ORDER_ID) + : ""; + auto target = shouldUseOrderId ? std::regex_replace(this->cancelOrderTarget, std::regex("\\{order\\-id\\}"), id) : this->cancelOrderTargetByClientId; + if (!shouldUseOrderId) { + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + this->appendParam(document, allocator, param, { + {CCAPI_EM_CLIENT_ORDER_ID , "client-order-id"} + }); + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + auto body = stringBuffer.GetString(); + req.body() = body; + req.prepare_payload(); + } + this->signRequest(req, target, queryParamMap, credential); + } + break; + case Request::Operation::GET_ORDER: + { + req.method(http::verb::get); + const std::map& param = request.getParamList().at(0); + auto shouldUseOrderId = param.find(CCAPI_EM_ORDER_ID) != param.end(); + std::string id = shouldUseOrderId ? param.at(CCAPI_EM_ORDER_ID) + : param.find(CCAPI_EM_CLIENT_ORDER_ID) != param.end() ? "client:" + param.at(CCAPI_EM_CLIENT_ORDER_ID) + : ""; + auto target = shouldUseOrderId ? std::regex_replace(this->getOrderTarget, std::regex("\\{order\\-id\\}"), id) : this->getOrderTargetByClientId; + req.target(target); + if (!shouldUseOrderId) { + this->appendParam(queryParamMap, param, { + {CCAPI_EM_ACCOUNT_ID , "account-id"} + }); + queryParamMap.insert(std::make_pair("clientOrderId", Url::urlEncode(id))); + } + this->signRequest(req, target, queryParamMap, credential); + } + break; + case Request::Operation::GET_OPEN_ORDERS: + { + req.method(http::verb::get); + const std::map& param = request.getParamList().at(0); + this->appendParam(queryParamMap, param, { + {CCAPI_EM_ACCOUNT_ID , "account-id"} + }); + if (!symbolId.empty()) { + this->appendSymbolId(queryParamMap, symbolId); + } + this->signRequest(req, this->getOpenOrdersTarget, queryParamMap, credential); + } + break; + default: + CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE); + } + } + std::vector extractOrderInfo(const Request::Operation operation, const rj::Document& document) override { + const std::map >& extractionFieldNameMap = { + {CCAPI_EM_ORDER_ID, std::make_pair("id", JsonDataType::STRING)}, + {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("client_oid", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_QUANTITY, std::make_pair("size", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("price", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::make_pair("filled_size", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::make_pair("executed_value", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_STATUS, std::make_pair("status", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("product_id", JsonDataType::STRING)} + }; + std::vector elementList; + if (document.IsObject()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(document, extractionFieldNameMap)); + } else { + for (const auto& x : document.GetArray()) { + elementList.emplace_back(ExecutionManagementService::extractOrderInfo(x, extractionFieldNameMap)); + } + } + return elementList; + } + std::string cancelOrderByClientOrderIdTarget; + std::string getOrderByClientOrderIdTarget; +}; +} /* namespace ccapi */ +#endif +#endif +#endif // INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_HUOBI_H_ From 8a55910f986bc5d720b3a1b10bf2e70fc2d6d9e6 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Wed, 30 Dec 2020 13:24:35 -0800 Subject: [PATCH 07/18] fix: prefix CCAPI_ to ENABLE_... macros to avoid potential name conflicts in end user code --- README.md | 4 +- include/ccapi_cpp/ccapi_logger.h | 12 +-- include/ccapi_cpp/ccapi_message.h | 6 ++ include/ccapi_cpp/ccapi_session.h | 80 +++++++++---------- include/ccapi_cpp/ccapi_util_private.h | 8 +- .../ccapi_execution_management_service.h | 6 +- ...api_execution_management_service_binance.h | 4 +- ...xecution_management_service_binance_base.h | 4 +- ...ution_management_service_binance_futures.h | 4 +- ..._execution_management_service_binance_us.h | 4 +- ...capi_execution_management_service_bitmex.h | 4 +- ...pi_execution_management_service_coinbase.h | 4 +- ...capi_execution_management_service_gemini.h | 4 +- ...ccapi_execution_management_service_huobi.h | 4 +- .../service/ccapi_market_data_service.h | 8 +- .../ccapi_market_data_service_binance.h | 4 +- .../ccapi_market_data_service_binance_base.h | 4 +- ...capi_market_data_service_binance_futures.h | 4 +- .../ccapi_market_data_service_binance_us.h | 4 +- .../ccapi_market_data_service_bitfinex.h | 4 +- .../ccapi_market_data_service_bitmex.h | 4 +- .../ccapi_market_data_service_bitstamp.h | 4 +- .../ccapi_market_data_service_coinbase.h | 4 +- .../ccapi_market_data_service_gemini.h | 4 +- .../service/ccapi_market_data_service_huobi.h | 4 +- .../ccapi_market_data_service_kraken.h | 4 +- .../service/ccapi_market_data_service_okex.h | 4 +- 27 files changed, 105 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 7a09df8e..36902856 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ * Example CMake: example/CMakeLists.txt. * Require C++14 and OpenSSL. * Definitions in the compiler command line: - * Define service enablement macro `ENABLE_SERVICE_MARKET_DATA` and exchange enablement macros such as `ENABLE_EXCHANGE_COINBASE`, etc. These macros can be found at the top of `include/ccapi_cpp/ccapi_session.h`. + * Define service enablement macro `CCAPI_ENABLE_SERVICE_MARKET_DATA` and exchange enablement macros such as `CCAPI_ENABLE_EXCHANGE_COINBASE`, etc. These macros can be found at the top of `include/ccapi_cpp/ccapi_session.h`. * Include directories: * include * dependency/websocketpp @@ -189,7 +189,7 @@ std::vector eventList = session.eventQueue.purge(); #### Enable library logging -Extend a subclass, e.g. `MyLogger`, from class `Logger` and override method `logMessage`. Assign a `MyLogger` pointer to `Logger::logger`. Add one of the following macros in the compiler command line: `ENABLE_LOG_TRACE`, `ENABLE_LOG_DEBUG`, `ENABLE_LOG_INFO`, `ENABLE_LOG_WARN`, `ENABLE_LOG_ERROR`, `ENABLE_LOG_FATAL`. +Extend a subclass, e.g. `MyLogger`, from class `Logger` and override method `logMessage`. Assign a `MyLogger` pointer to `Logger::logger`. Add one of the following macros in the compiler command line: `CCAPI_ENABLE_LOG_TRACE`, `CCAPI_ENABLE_LOG_DEBUG`, `CCAPI_ENABLE_LOG_INFO`, `CCAPI_ENABLE_LOG_WARN`, `CCAPI_ENABLE_LOG_ERROR`, `CCAPI_ENABLE_LOG_FATAL`. ``` namespace ccapi { class MyLogger final: public Logger { diff --git a/include/ccapi_cpp/ccapi_logger.h b/include/ccapi_cpp/ccapi_logger.h index 9115f78f..d461a91c 100644 --- a/include/ccapi_cpp/ccapi_logger.h +++ b/include/ccapi_cpp/ccapi_logger.h @@ -8,32 +8,32 @@ #define CCAPI_LOGGER_FILENAME (strrchr(__FILE__, CCAPI_LOGGER_FILE_SEPARATOR) ? strrchr(__FILE__, CCAPI_LOGGER_FILE_SEPARATOR) + 1 : __FILE__) #define CCAPI_LOGGER_THREAD_ID std::this_thread::get_id() #define CCAPI_LOGGER_NOW std::chrono::system_clock::now() -#if defined(ENABLE_LOG_FATAL) || defined(ENABLE_LOG_ERROR) || defined(ENABLE_LOG_WARN) || defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG) || defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_FATAL) || defined(CCAPI_ENABLE_LOG_ERROR) || defined(CCAPI_ENABLE_LOG_WARN) || defined(CCAPI_ENABLE_LOG_INFO) || defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) #define CCAPI_LOGGER_FATAL(message) Logger::logger->fatal(CCAPI_LOGGER_THREAD_ID, CCAPI_LOGGER_NOW, CCAPI_LOGGER_FILENAME, __LINE__, message); throw std::runtime_error(message) #else #define CCAPI_LOGGER_FATAL(message) throw std::runtime_error(message); #endif -#if defined(ENABLE_LOG_ERROR) || defined(ENABLE_LOG_WARN) || defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG) || defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_ERROR) || defined(CCAPI_ENABLE_LOG_WARN) || defined(CCAPI_ENABLE_LOG_INFO) || defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) #define CCAPI_LOGGER_ERROR(message) Logger::logger->error(CCAPI_LOGGER_THREAD_ID, CCAPI_LOGGER_NOW, CCAPI_LOGGER_FILENAME, __LINE__, message) #else #define CCAPI_LOGGER_ERROR(message) #endif -#if defined(ENABLE_LOG_WARN) || defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG) || defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_WARN) || defined(CCAPI_ENABLE_LOG_INFO) || defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) #define CCAPI_LOGGER_WARN(message) Logger::logger->warn(CCAPI_LOGGER_THREAD_ID, CCAPI_LOGGER_NOW, CCAPI_LOGGER_FILENAME, __LINE__, message) #else #define CCAPI_LOGGER_WARN(message) #endif -#if defined(ENABLE_LOG_INFO) || defined(ENABLE_LOG_DEBUG) || defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_INFO) || defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) #define CCAPI_LOGGER_INFO(message) Logger::logger->info(CCAPI_LOGGER_THREAD_ID, CCAPI_LOGGER_NOW, CCAPI_LOGGER_FILENAME, __LINE__, message) #else #define CCAPI_LOGGER_INFO(message) #endif -#if defined(ENABLE_LOG_DEBUG) || defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) #define CCAPI_LOGGER_DEBUG(message) Logger::logger->debug(CCAPI_LOGGER_THREAD_ID, CCAPI_LOGGER_NOW, CCAPI_LOGGER_FILENAME, __LINE__, message) #else #define CCAPI_LOGGER_DEBUG(message) #endif -#if defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_TRACE) #define CCAPI_LOGGER_TRACE(message) Logger::logger->trace(CCAPI_LOGGER_THREAD_ID, CCAPI_LOGGER_NOW, CCAPI_LOGGER_FILENAME, __LINE__, message) #else #define CCAPI_LOGGER_TRACE(message) diff --git a/include/ccapi_cpp/ccapi_message.h b/include/ccapi_cpp/ccapi_message.h index 852544ef..659ed5e3 100644 --- a/include/ccapi_cpp/ccapi_message.h +++ b/include/ccapi_cpp/ccapi_message.h @@ -127,6 +127,9 @@ class Message CCAPI_FINAL { std::string getTimeISO() const { return UtilTime::getISOTimestamp(time); } + std::pair getTimePair() const { + return UtilTime::divide(time); + } void setTime(TimePoint time) { this->time = time; } @@ -148,6 +151,9 @@ class Message CCAPI_FINAL { std::string getTimeReceivedISO() const { return UtilTime::getISOTimestamp(timeReceived); } + std::pair getTimeReceivedPair() const { + return UtilTime::divide(timeReceived); + } void setTimeReceived(TimePoint timeReceived) { this->timeReceived = timeReceived; } diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 6b7e31b0..1eac4136 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -1,61 +1,61 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_SESSION_H_ #define INCLUDE_CCAPI_CPP_CCAPI_SESSION_H_ #include "ccapi_cpp/ccapi_macro.h" -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_COINBASE +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_market_data_service_coinbase.h" #endif -#ifdef ENABLE_EXCHANGE_GEMINI +#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI #include "ccapi_cpp/service/ccapi_market_data_service_gemini.h" #endif -#ifdef ENABLE_EXCHANGE_KRAKEN +#ifdef CCAPI_ENABLE_EXCHANGE_KRAKEN #include "ccapi_cpp/service/ccapi_market_data_service_kraken.h" #endif -#ifdef ENABLE_EXCHANGE_BITSTAMP +#ifdef CCAPI_ENABLE_EXCHANGE_BITSTAMP #include "ccapi_cpp/service/ccapi_market_data_service_bitstamp.h" #endif -#ifdef ENABLE_EXCHANGE_BITFINEX +#ifdef CCAPI_ENABLE_EXCHANGE_BITFINEX #include "ccapi_cpp/service/ccapi_market_data_service_bitfinex.h" #endif -#ifdef ENABLE_EXCHANGE_BITMEX +#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX #include "ccapi_cpp/service/ccapi_market_data_service_bitmex.h" #endif -#ifdef ENABLE_EXCHANGE_BINANCE_US +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_market_data_service_binance_us.h" #endif -#ifdef ENABLE_EXCHANGE_BINANCE +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE #include "ccapi_cpp/service/ccapi_market_data_service_binance.h" #endif -#ifdef ENABLE_EXCHANGE_BINANCE_FUTURES +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_market_data_service_binance_futures.h" #endif -#ifdef ENABLE_EXCHANGE_HUOBI +#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI #include "ccapi_cpp/service/ccapi_market_data_service_huobi.h" #endif -#ifdef ENABLE_EXCHANGE_OKEX +#ifdef CCAPI_ENABLE_EXCHANGE_OKEX #include "ccapi_cpp/service/ccapi_market_data_service_okex.h" #endif #endif -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_COINBASE +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_execution_management_service_coinbase.h" #endif -#ifdef ENABLE_EXCHANGE_GEMINI +#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI #include "ccapi_cpp/service/ccapi_execution_management_service_gemini.h" #endif -#ifdef ENABLE_EXCHANGE_BITMEX +#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX #include "ccapi_cpp/service/ccapi_execution_management_service_bitmex.h" #endif -#ifdef ENABLE_EXCHANGE_BINANCE_US +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_us.h" #endif -#ifdef ENABLE_EXCHANGE_BINANCE +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE #include "ccapi_cpp/service/ccapi_execution_management_service_binance.h" #endif -#ifdef ENABLE_EXCHANGE_BINANCE_FUTURES +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h" #endif -#ifdef ENABLE_EXCHANGE_HUOBI +#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI #include "ccapi_cpp/service/ccapi_execution_management_service_huobi.h" #endif #endif @@ -109,61 +109,61 @@ class Session CCAPI_FINAL { }); this->t = std::move(t); std::function eventHandler = std::bind(&Session::onEvent, this, std::placeholders::_1, &eventQueue); -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_COINBASE +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_COINBASE] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_GEMINI +#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_GEMINI] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_KRAKEN +#ifdef CCAPI_ENABLE_EXCHANGE_KRAKEN this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_KRAKEN] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BITSTAMP +#ifdef CCAPI_ENABLE_EXCHANGE_BITSTAMP this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITSTAMP] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BITFINEX +#ifdef CCAPI_ENABLE_EXCHANGE_BITFINEX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITFINEX] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BITMEX +#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITMEX] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BINANCE_US +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BINANCE_US] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BINANCE +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BINANCE] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BINANCE_FUTURES +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BINANCE_FUTURES] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_HUOBI +#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_HUOBI] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_OKEX +#ifdef CCAPI_ENABLE_EXCHANGE_OKEX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_OKEX] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #endif -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_COINBASE +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_COINBASE] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_GEMINI +#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_GEMINI] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BITMEX +#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITMEX] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BINANCE_US +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_US] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BINANCE +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_BINANCE_FUTURES +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_FUTURES] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif -#ifdef ENABLE_EXCHANGE_HUOBI +#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_HUOBI] = std::make_shared(eventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #endif diff --git a/include/ccapi_cpp/ccapi_util_private.h b/include/ccapi_cpp/ccapi_util_private.h index 0f33557b..9a9f9041 100644 --- a/include/ccapi_cpp/ccapi_util_private.h +++ b/include/ccapi_cpp/ccapi_util_private.h @@ -125,19 +125,19 @@ class UtilTime CCAPI_FINAL { } return tp; } - static TimePoint makeTimePoint(std::pair timePair) { + static TimePoint makeTimePoint(std::pair timePair) { auto tp = TimePoint(std::chrono::duration(timePair.first)); tp += std::chrono::nanoseconds(timePair.second); return tp; } - static std::pair divide(TimePoint tp) { + static std::pair divide(TimePoint tp) { auto then = tp.time_since_epoch(); auto s = std::chrono::duration_cast(then); then -= s; auto ns = std::chrono::duration_cast(then); return std::make_pair(s.count(), ns.count()); } - static std::pair divide(std::string seconds) { + static std::pair divide(std::string seconds) { if (seconds.find(".") != std::string::npos) { auto splittedSeconds = UtilString::split(UtilString::rtrim(UtilString::rtrim(seconds, "0"), "."), "."); return std::make_pair( @@ -461,7 +461,7 @@ template typename std::enable_if::value } template typename std::enable_if::value, std::string>::type toString( const T &t) { - std::pair timePair = UtilTime::divide(t); + auto timePair = UtilTime::divide(t); return "(" + std::to_string(timePair.first) + "," + std::to_string(timePair.second) + ")"; } template std::string toString(const std::unordered_set& c); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index e77b1fa0..53404b25 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -1,6 +1,6 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT #ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) if (!(x)) { throw std::runtime_error("rapidjson internal assertion failure"); } #endif @@ -57,7 +57,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro CCAPI_LOGGER_DEBUG("request = "+toString(request)); CCAPI_LOGGER_DEBUG("useFuture = "+toString(useFuture)); auto req = this->convertRequest(request, now); -#if defined(ENABLE_LOG_DEBUG) || defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) std::ostringstream oss; oss << req; CCAPI_LOGGER_DEBUG("req = \n"+oss.str()); @@ -251,7 +251,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro } } } -#if defined(ENABLE_LOG_DEBUG) || defined(ENABLE_LOG_TRACE) +#if defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) std::ostringstream oss; oss << *resPtr; CCAPI_LOGGER_DEBUG("res = \n"+oss.str()); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h index db2f6f79..2251eb15 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_BINANCE +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE #ifndef CCAPI_BINANCE_CREATE_ORDER_TARGET #define CCAPI_BINANCE_CREATE_ORDER_TARGET "/api/v3/order" #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h index e818260a..33e6d13c 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_BASE_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_BASE_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#if defined(ENABLE_EXCHANGE_BINANCE_US) || defined(ENABLE_EXCHANGE_BINANCE) || defined(ENABLE_EXCHANGE_BINANCE_FUTURES) +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#if defined(CCAPI_ENABLE_EXCHANGE_BINANCE_US) || defined(CCAPI_ENABLE_EXCHANGE_BINANCE) || defined(CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES) #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { class ExecutionManagementServiceBinanceBase : public ExecutionManagementService { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h index e1cd4317..926c5b02 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_FUTURES_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_FUTURES_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_BINANCE_FUTURES +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_execution_management_service_binance_base.h" namespace ccapi { class ExecutionManagementServiceBinanceFutures CCAPI_FINAL : public ExecutionManagementServiceBinanceBase { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h index 0285a968..f5bf2880 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_us.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_US_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BINANCE_US_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_BINANCE_US +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_base.h" namespace ccapi { class ExecutionManagementServiceBinanceUs CCAPI_FINAL : public ExecutionManagementServiceBinanceBase { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h index 43e2cb74..9c82e99c 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BITMEX_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_BITMEX_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_BITMEX +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { class ExecutionManagementServiceBitmex CCAPI_FINAL : public ExecutionManagementService { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h index d5fb54b8..f05bcab0 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_coinbase.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_COINBASE_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_COINBASE_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_COINBASE +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { class ExecutionManagementServiceCoinbase CCAPI_FINAL : public ExecutionManagementService { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h index 1aa11fc1..93c6df34 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_GEMINI_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_GEMINI_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_GEMINI +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { class ExecutionManagementServiceGemini CCAPI_FINAL : public ExecutionManagementService { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h index e030583a..aecefafc 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_HUOBI_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_EXECUTION_MANAGEMENT_SERVICE_HUOBI_H_ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_HUOBI +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI #include "ccapi_cpp/service/ccapi_execution_management_service.h" namespace ccapi { class ExecutionManagementServiceHuobi CCAPI_FINAL : public ExecutionManagementService { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service.h b/include/ccapi_cpp/service/ccapi_market_data_service.h index 14172e84..b1f93fbb 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service.h @@ -1,6 +1,6 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA #ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) if (!(x)) { throw std::runtime_error("rapidjson internal assertion failure"); } #endif @@ -25,7 +25,7 @@ #include "ccapi_cpp/ccapi_ws_connection.h" #include "ccapi_cpp/service/ccapi_service_context.h" #include "ccapi_cpp/service/ccapi_service.h" -#if defined(ENABLE_EXCHANGE_HUOBI) || defined(ENABLE_EXCHANGE_OKEX) +#if defined(CCAPI_ENABLE_EXCHANGE_HUOBI) || defined(CCAPI_ENABLE_EXCHANGE_OKEX) #include #include #include "ccapi_cpp/websocketpp_decompress_workaround.h" @@ -346,7 +346,7 @@ class MarketDataService : public Service, public std::enable_shared_from_this namespace ccapi { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h index 8888b20f..3f2c27ee 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitmex.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_BITMEX_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_BITMEX_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_BITMEX +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX #include "ccapi_cpp/service/ccapi_market_data_service.h" #include namespace ccapi { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h index 544270c8..03ae8be0 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitstamp.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_BITSTAMP_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_BITSTAMP_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_BITSTAMP +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_BITSTAMP #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { class MarketDataServiceBitstamp CCAPI_FINAL : public MarketDataService { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h b/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h index 2a8c1e92..97d70c54 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_coinbase.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_COINBASE_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_COINBASE_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_COINBASE +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { class MarketDataServiceCoinbase CCAPI_FINAL : public MarketDataService { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h b/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h index 4433aefa..b5a84491 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_GEMINI_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_GEMINI_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_GEMINI +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { class MarketDataServiceGemini CCAPI_FINAL : public MarketDataService { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h index 0eec49b8..51f9bfe4 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_HUOBI_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_HUOBI_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_HUOBI +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI #include "ccapi_cpp/service/ccapi_market_data_service.h" #include namespace ccapi { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h index 90f2036d..56d9e60d 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_KRAKEN_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_KRAKEN_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_KRAKEN +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_KRAKEN #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { class MarketDataServiceKraken CCAPI_FINAL : public MarketDataService { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_okex.h b/include/ccapi_cpp/service/ccapi_market_data_service_okex.h index 72468a49..f9e2a7e4 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_okex.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_okex.h @@ -1,7 +1,7 @@ #ifndef INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_OKEX_H_ #define INCLUDE_CCAPI_CPP_SERVICE_CCAPI_MARKET_DATA_SERVICE_OKEX_H_ -#ifdef ENABLE_SERVICE_MARKET_DATA -#ifdef ENABLE_EXCHANGE_OKEX +#ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA +#ifdef CCAPI_ENABLE_EXCHANGE_OKEX #include "ccapi_cpp/service/ccapi_market_data_service.h" namespace ccapi { class MarketDataServiceOkex CCAPI_FINAL : public MarketDataService { From ed1e230729a9eaf2f78913bce816875c6ad01d9d Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Wed, 30 Dec 2020 21:04:58 -0800 Subject: [PATCH 08/18] test: update tests --- .github/workflows/release.yml | 6 +++++- .github/workflows/{build_cmake.yml => test.yml} | 15 ++++++++++++++- .../execution_management_simple/CMakeLists.txt | 4 ++-- example/src/market_data_advanced/CMakeLists.txt | 6 +++--- example/src/market_data_simple/CMakeLists.txt | 4 ++-- example/src/sample_market_making/CMakeLists.txt | 6 +++--- test/CMakeLists.txt | 10 +++++----- test/{build_test => test_build}/CMakeLists.txt | 6 +++--- test/{build_test => test_build}/test.cpp | 0 test/{unit_test => test_unit}/CMakeLists.txt | 3 ++- .../src/common/CMakeLists.txt | 0 .../src/common/ccapi_decimal_test.cpp | 0 .../src/common/ccapi_hmac_test.cpp | 0 .../binance_futures/CMakeLists.txt | 4 ++-- .../execution_management/binance_futures/test.cpp | 4 ++-- .../binance_us/CMakeLists.txt | 4 ++-- .../src/execution_management/binance_us/test.cpp | 6 +++--- 17 files changed, 48 insertions(+), 30 deletions(-) rename .github/workflows/{build_cmake.yml => test.yml} (95%) rename test/{build_test => test_build}/CMakeLists.txt (84%) rename test/{build_test => test_build}/test.cpp (100%) rename test/{unit_test => test_unit}/CMakeLists.txt (66%) rename test/{unit_test => test_unit}/src/common/CMakeLists.txt (100%) rename test/{unit_test => test_unit}/src/common/ccapi_decimal_test.cpp (100%) rename test/{unit_test => test_unit}/src/common/ccapi_hmac_test.cpp (100%) rename test/{unit_test => test_unit}/src/execution_management/binance_futures/CMakeLists.txt (60%) rename test/{unit_test => test_unit}/src/execution_management/binance_futures/test.cpp (96%) rename test/{unit_test => test_unit}/src/execution_management/binance_us/CMakeLists.txt (60%) rename test/{unit_test => test_unit}/src/execution_management/binance_us/test.cpp (98%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8da203be..3f27b75c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,8 +32,12 @@ jobs: {"type": "style", "release": "patch"}, {"type": "refactor", "release": "patch"}, {"type": "perf", "release": "patch"}, - {"type": "test", "release": "patch"} + {"type": "test", "release": "patch"}, + {"type": "minor", "release": "minor"}, + {"type": "major", "release": "major"}, ] + }], ["@semantic-release/release-notes-generator", { + "preset": "conventionalcommits" }], "@semantic-release/github"] } }'' > "package.json"' diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/test.yml similarity index 95% rename from .github/workflows/build_cmake.yml rename to .github/workflows/test.yml index e8f8d0bf..d499f911 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/test.yml @@ -153,7 +153,8 @@ jobs: execute_process( COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake - -DBUILD_BUILD_TEST=ON + -DBUILD_TEST_BUILD=ON + -DBUILD_TEST_UNIT=ON -S test -B build -D CMAKE_BUILD_TYPE=$ENV{BUILD_TYPE} @@ -210,3 +211,15 @@ jobs: endif() execute_process(COMMAND ccache -s) + + + - name: Test + shell: cmake -P {0} + run: | + execute_process( + COMMAND ctest -j + RESULT_VARIABLE result + ) + if (NOT result EQUAL 0) + message(FATAL_ERROR "Bad exit status") + endif() diff --git a/example/src/execution_management_simple/CMakeLists.txt b/example/src/execution_management_simple/CMakeLists.txt index 7f0d801c..0815f8c5 100644 --- a/example/src/execution_management_simple/CMakeLists.txt +++ b/example/src/execution_management_simple/CMakeLists.txt @@ -1,5 +1,5 @@ set(NAME execution_management_simple) project(${NAME}) -add_compile_definitions(-DENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_compile_definitions(-DENABLE_EXCHANGE_COINBASE) +add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE) add_executable(${NAME} main.cpp) diff --git a/example/src/market_data_advanced/CMakeLists.txt b/example/src/market_data_advanced/CMakeLists.txt index 10324008..87a06716 100644 --- a/example/src/market_data_advanced/CMakeLists.txt +++ b/example/src/market_data_advanced/CMakeLists.txt @@ -1,6 +1,6 @@ set(NAME market_data_advanced) project(${NAME}) -add_compile_definitions(ENABLE_SERVICE_MARKET_DATA) -add_compile_definitions(ENABLE_EXCHANGE_COINBASE) -add_compile_definitions(ENABLE_EXCHANGE_BINANCE_US) +add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US) add_executable(${NAME} main.cpp) diff --git a/example/src/market_data_simple/CMakeLists.txt b/example/src/market_data_simple/CMakeLists.txt index 3bf1f81b..6569771c 100644 --- a/example/src/market_data_simple/CMakeLists.txt +++ b/example/src/market_data_simple/CMakeLists.txt @@ -1,5 +1,5 @@ set(NAME market_data_simple) project(${NAME}) -add_compile_definitions(ENABLE_SERVICE_MARKET_DATA) -add_compile_definitions(ENABLE_EXCHANGE_COINBASE) +add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE) add_executable(${NAME} main.cpp) diff --git a/example/src/sample_market_making/CMakeLists.txt b/example/src/sample_market_making/CMakeLists.txt index 567593fa..19ef6690 100644 --- a/example/src/sample_market_making/CMakeLists.txt +++ b/example/src/sample_market_making/CMakeLists.txt @@ -1,6 +1,6 @@ set(NAME sample_market_making) project(${NAME}) -add_compile_definitions(ENABLE_SERVICE_MARKET_DATA) -add_compile_definitions(ENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_compile_definitions(ENABLE_EXCHANGE_COINBASE) +add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA) +add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE) add_executable(${NAME} main.cpp) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7abd3fbc..58efdf82 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,9 +18,9 @@ link_libraries(OpenSSL::Crypto OpenSSL::SSL) set(SOURCE_LOGGER ${CCAPI_CPP_PROJECT_DIR}/test/ccapi_logger.cpp) option(BUILD_BUILD_TEST "Build build_test") option(BUILD_UNIT_TEST "Build unit_test") -if(BUILD_BUILD_TEST) - add_subdirectory(build_test) +if(BUILD_TEST_BUILD) + add_subdirectory(test_build) +endif() +if(BUILD_TEST_UNIT) + add_subdirectory(test_unit) endif() -if(BUILD_UNIT_TEST) - add_subdirectory(unit_test) -endif() \ No newline at end of file diff --git a/test/build_test/CMakeLists.txt b/test/test_build/CMakeLists.txt similarity index 84% rename from test/build_test/CMakeLists.txt rename to test/test_build/CMakeLists.txt index 3226fb21..24d8e269 100644 --- a/test/build_test/CMakeLists.txt +++ b/test/test_build/CMakeLists.txt @@ -2,7 +2,7 @@ set(NAME build_test) project(${NAME}) set(SERVICE_LIST "MARKET_DATA" "EXECUTION_MANAGEMENT") set(MARKET_DATA_EXCHANGE_LIST "COINBASE" "GEMINI" "KRAKEN" "BITSTAMP" "BITFINEX" "BITMEX" "BINANCE_US" "BINANCE" "BINANCE_FUTURES" "HUOBI" "OKEX") -set(EXECUTION_MANAGEMENT_EXCHANGE_LIST "COINBASE" "GEMINI" "BITMEX" "BINANCE_US" "BINANCE" "BINANCE_FUTURES" "HUOBI") +set(EXECUTION_MANAGEMENT_EXCHANGE_LIST "BINANCE_US" "BINANCE" "BINANCE_FUTURES") foreach(SERVICE IN LISTS SERVICE_LIST) message(STATUS "SERVICE=${SERVICE}") if("${SERVICE}" STREQUAL "MARKET_DATA") @@ -14,11 +14,11 @@ foreach(SERVICE IN LISTS SERVICE_LIST) message(STATUS "EXCHANGE=${EXCHANGE}") set(CCAPI_CPP_TARGET_NAME "${SERVICE}__${EXCHANGE}") add_executable("${CCAPI_CPP_TARGET_NAME}" ${SOURCE_LOGGER} test.cpp) - target_compile_definitions("${CCAPI_CPP_TARGET_NAME}" PRIVATE "ENABLE_SERVICE_${SERVICE}" "ENABLE_EXCHANGE_${EXCHANGE}") + target_compile_definitions("${CCAPI_CPP_TARGET_NAME}" PRIVATE "CCAPI_ENABLE_SERVICE_${SERVICE}" "CCAPI_ENABLE_EXCHANGE_${EXCHANGE}") if("${EXCHANGE}" STREQUAL "HUOBI" OR "${EXCHANGE}" STREQUAL "OKEX") message(STATUS "need zlib") find_package(ZLIB REQUIRED) target_link_libraries("${CCAPI_CPP_TARGET_NAME}" PRIVATE ZLIB::ZLIB) endif() endforeach() -endforeach() \ No newline at end of file +endforeach() diff --git a/test/build_test/test.cpp b/test/test_build/test.cpp similarity index 100% rename from test/build_test/test.cpp rename to test/test_build/test.cpp diff --git a/test/unit_test/CMakeLists.txt b/test/test_unit/CMakeLists.txt similarity index 66% rename from test/unit_test/CMakeLists.txt rename to test/test_unit/CMakeLists.txt index 00bda508..547ffa1e 100644 --- a/test/unit_test/CMakeLists.txt +++ b/test/test_unit/CMakeLists.txt @@ -1,6 +1,7 @@ set(NAME unit_test) project(${NAME}) find_package(GTest REQUIRED) +include(CTest) add_subdirectory(src/common) add_subdirectory(src/execution_management/binance_us) -add_subdirectory(src/execution_management/binance_futures) \ No newline at end of file +add_subdirectory(src/execution_management/binance_futures) diff --git a/test/unit_test/src/common/CMakeLists.txt b/test/test_unit/src/common/CMakeLists.txt similarity index 100% rename from test/unit_test/src/common/CMakeLists.txt rename to test/test_unit/src/common/CMakeLists.txt diff --git a/test/unit_test/src/common/ccapi_decimal_test.cpp b/test/test_unit/src/common/ccapi_decimal_test.cpp similarity index 100% rename from test/unit_test/src/common/ccapi_decimal_test.cpp rename to test/test_unit/src/common/ccapi_decimal_test.cpp diff --git a/test/unit_test/src/common/ccapi_hmac_test.cpp b/test/test_unit/src/common/ccapi_hmac_test.cpp similarity index 100% rename from test/unit_test/src/common/ccapi_hmac_test.cpp rename to test/test_unit/src/common/ccapi_hmac_test.cpp diff --git a/test/unit_test/src/execution_management/binance_futures/CMakeLists.txt b/test/test_unit/src/execution_management/binance_futures/CMakeLists.txt similarity index 60% rename from test/unit_test/src/execution_management/binance_futures/CMakeLists.txt rename to test/test_unit/src/execution_management/binance_futures/CMakeLists.txt index 908f450b..9cb95761 100644 --- a/test/unit_test/src/execution_management/binance_futures/CMakeLists.txt +++ b/test/test_unit/src/execution_management/binance_futures/CMakeLists.txt @@ -1,7 +1,7 @@ set(NAME execution_management_binance_futures) project(${NAME}) -add_compile_definitions(ENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_compile_definitions(ENABLE_EXCHANGE_BINANCE_FUTURES) +add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES) add_executable(${NAME} ${SOURCE_LOGGER} test.cpp) target_link_libraries(${NAME} GTest::GTest GTest::Main) gtest_discover_tests(${NAME}) diff --git a/test/unit_test/src/execution_management/binance_futures/test.cpp b/test/test_unit/src/execution_management/binance_futures/test.cpp similarity index 96% rename from test/unit_test/src/execution_management/binance_futures/test.cpp rename to test/test_unit/src/execution_management/binance_futures/test.cpp index 8efe9182..c9505fde 100644 --- a/test/unit_test/src/execution_management/binance_futures/test.cpp +++ b/test/test_unit/src/execution_management/binance_futures/test.cpp @@ -1,5 +1,5 @@ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_BINANCE_FUTURES +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES #include "gtest/gtest.h" #include "ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h" namespace ccapi { diff --git a/test/unit_test/src/execution_management/binance_us/CMakeLists.txt b/test/test_unit/src/execution_management/binance_us/CMakeLists.txt similarity index 60% rename from test/unit_test/src/execution_management/binance_us/CMakeLists.txt rename to test/test_unit/src/execution_management/binance_us/CMakeLists.txt index 9345c379..c99ac5c5 100644 --- a/test/unit_test/src/execution_management/binance_us/CMakeLists.txt +++ b/test/test_unit/src/execution_management/binance_us/CMakeLists.txt @@ -1,7 +1,7 @@ set(NAME execution_management_binance_us) project(${NAME}) -add_compile_definitions(ENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_compile_definitions(ENABLE_EXCHANGE_BINANCE_US) +add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US) add_executable(${NAME} ${SOURCE_LOGGER} test.cpp) target_link_libraries(${NAME} GTest::GTest GTest::Main) gtest_discover_tests(${NAME}) diff --git a/test/unit_test/src/execution_management/binance_us/test.cpp b/test/test_unit/src/execution_management/binance_us/test.cpp similarity index 98% rename from test/unit_test/src/execution_management/binance_us/test.cpp rename to test/test_unit/src/execution_management/binance_us/test.cpp index 2b70b896..7134e54c 100644 --- a/test/unit_test/src/execution_management/binance_us/test.cpp +++ b/test/test_unit/src/execution_management/binance_us/test.cpp @@ -1,5 +1,5 @@ -#ifdef ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef ENABLE_EXCHANGE_BINANCE_US +#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT +#ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US #include "gtest/gtest.h" #include "ccapi_cpp/service/ccapi_execution_management_service_binance_us.h" namespace ccapi { @@ -29,7 +29,7 @@ void verifySignature(const std::string& paramString, const std::string& apiSecre auto pos = paramString.find_last_of("&"); auto paramStringWithoutSignature = paramString.substr(0, pos); auto signature = paramString.substr(pos + 11, paramString.length() - pos - 1); - EXPECT_EQ(UtilAlgorithm::hmacHex(apiSecret, paramStringWithoutSignature), signature); + EXPECT_EQ("", signature); } void verifyCorrelationId(const std::vector& messageList, const std::string& correlationId) { From 64df97442e51995795da911c710100800e85d731 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Wed, 30 Dec 2020 21:56:49 -0800 Subject: [PATCH 09/18] test: update tests --- .github/workflows/cpplint.yml | 4 +++- .github/workflows/test.yml | 3 +-- README.md | 4 ++-- include/ccapi_cpp/ccapi_session.h | 2 +- test/CMakeLists.txt | 1 + test/test_unit/CMakeLists.txt | 1 - test/test_unit/src/execution_management/binance_us/test.cpp | 2 +- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/cpplint.yml b/.github/workflows/cpplint.yml index c29c1883..e9eb4a7b 100644 --- a/.github/workflows/cpplint.yml +++ b/.github/workflows/cpplint.yml @@ -14,4 +14,6 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 - run: pip install cpplint - - run: cpplint --recursive --exclude=include/ccapi_cpp/websocketpp_decompress_workaround.h --filter -legal/copyright,-whitespace/line_length,-build/c++11,-runtime/references,-build/include_what_you_use,-runtime/int include/**/* example/src/* + - run: cpplint --recursive --exclude=include/ccapi_cpp/websocketpp_decompress_workaround.h \ + --filter -legal/copyright,-whitespace/line_length,-build/c++11,-runtime/references,-build/include_what_you_use,-runtime/int \ + include/**/* example/**/* test/**/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d499f911..c0ac45c8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -168,7 +168,6 @@ jobs: message(FATAL_ERROR "Bad exit status") endif() - - name: Build shell: cmake -P {0} run: | @@ -212,12 +211,12 @@ jobs: execute_process(COMMAND ccache -s) - - name: Test shell: cmake -P {0} run: | execute_process( COMMAND ctest -j + WORKING_DIRECTORY build RESULT_VARIABLE result ) if (NOT result EQUAL 0) diff --git a/README.md b/README.md index 36902856..bcb1bb25 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ Session session(sessionOptions, sessionConfigs); Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH"); session.subscribe(subscription); std::this_thread::sleep_for(std::chrono::seconds(5)); -std::vector eventList = session.eventQueue.purge(); +std::vector eventList = session.getEventQueue().purge(); ``` #### Enable library logging @@ -195,7 +195,7 @@ namespace ccapi { class MyLogger final: public Logger { virtual void logMessage(std::string severity, std::string threadId, std::string timeISO, - std::string fileName, int lineNumber, + std::string fileName, std::string lineNumber, std::string message) override { ... } diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 1eac4136..2e53dbb3 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -349,7 +349,7 @@ class Session CCAPI_FINAL { } CCAPI_LOGGER_FUNCTION_EXIT; } - const Queue& getEventQueue() const { + Queue& getEventQueue() { return eventQueue; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 58efdf82..4f2dfe0e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,5 +22,6 @@ if(BUILD_TEST_BUILD) add_subdirectory(test_build) endif() if(BUILD_TEST_UNIT) + enable_testing() add_subdirectory(test_unit) endif() diff --git a/test/test_unit/CMakeLists.txt b/test/test_unit/CMakeLists.txt index 547ffa1e..dadf7e7c 100644 --- a/test/test_unit/CMakeLists.txt +++ b/test/test_unit/CMakeLists.txt @@ -1,7 +1,6 @@ set(NAME unit_test) project(${NAME}) find_package(GTest REQUIRED) -include(CTest) add_subdirectory(src/common) add_subdirectory(src/execution_management/binance_us) add_subdirectory(src/execution_management/binance_futures) diff --git a/test/test_unit/src/execution_management/binance_us/test.cpp b/test/test_unit/src/execution_management/binance_us/test.cpp index 7134e54c..5dc8303c 100644 --- a/test/test_unit/src/execution_management/binance_us/test.cpp +++ b/test/test_unit/src/execution_management/binance_us/test.cpp @@ -29,7 +29,7 @@ void verifySignature(const std::string& paramString, const std::string& apiSecre auto pos = paramString.find_last_of("&"); auto paramStringWithoutSignature = paramString.substr(0, pos); auto signature = paramString.substr(pos + 11, paramString.length() - pos - 1); - EXPECT_EQ("", signature); + EXPECT_EQ(Hmac::hmac(Hmac::ShaVersion::SHA256, apiSecret, paramStringWithoutSignature, true), signature); } void verifyCorrelationId(const std::vector& messageList, const std::string& correlationId) { From 1fc43cd5eb4aec8acc2e8702d94733ef9e3a69b6 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Wed, 30 Dec 2020 22:28:25 -0800 Subject: [PATCH 10/18] ci: update github workflow --- .github/workflows/test.yml | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c0ac45c8..79037ce0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -115,6 +115,38 @@ jobs: restore-keys: | ${{ matrix.config.name }}-ccache- + - name: Install GoogleTest + shell: cmake -P {0} + run: | + execute_process(COMMAND git clone https://github.com/google/googletest.git -b release-1.10.0) + execute_process( + COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake + -DBUILD_GMOCK=OFF + -S googletest + -B googletest/build + -D CMAKE_BUILD_TYPE=$ENV{BUILD_TYPE} + RESULT_VARIABLE result + ) + if (NOT result EQUAL 0) + message(FATAL_ERROR "Bad exit status") + endif() + + execute_process( + COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build googletest/build -j + RESULT_VARIABLE result + ) + if (NOT result EQUAL 0) + message(FATAL_ERROR "Bad exit status") + endif() + + execute_process( + COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --install googletest/build + RESULT_VARIABLE result + ) + if (NOT result EQUAL 0) + message(FATAL_ERROR "Bad exit status") + endif() + - name: Install OpenSSL shell: cmake -P {0} run: | @@ -156,7 +188,7 @@ jobs: -DBUILD_TEST_BUILD=ON -DBUILD_TEST_UNIT=ON -S test - -B build + -B test/build -D CMAKE_BUILD_TYPE=$ENV{BUILD_TYPE} -G Ninja -D CMAKE_MAKE_PROGRAM=ninja @@ -202,7 +234,7 @@ jobs: execute_process(COMMAND ccache -z) execute_process( - COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build build -j + COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build test/build -j RESULT_VARIABLE result ) if (NOT result EQUAL 0) @@ -216,7 +248,7 @@ jobs: run: | execute_process( COMMAND ctest -j - WORKING_DIRECTORY build + WORKING_DIRECTORY test/build RESULT_VARIABLE result ) if (NOT result EQUAL 0) From c3c5620116cced923b4f63a86542e583f615c000 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Thu, 31 Dec 2020 14:49:29 -0800 Subject: [PATCH 11/18] fix: small fix --- .github/workflows/test.yml | 2 +- .../execution_management_simple/CMakeLists.txt | 2 +- .../src/execution_management_simple/main.cpp | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79037ce0..13ba2560 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -140,7 +140,7 @@ jobs: endif() execute_process( - COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --install googletest/build + COMMAND sudo ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --install googletest/build RESULT_VARIABLE result ) if (NOT result EQUAL 0) diff --git a/example/src/execution_management_simple/CMakeLists.txt b/example/src/execution_management_simple/CMakeLists.txt index 0815f8c5..5d4f70b4 100644 --- a/example/src/execution_management_simple/CMakeLists.txt +++ b/example/src/execution_management_simple/CMakeLists.txt @@ -1,5 +1,5 @@ set(NAME execution_management_simple) project(${NAME}) add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT) -add_compile_definitions(CCAPI_ENABLE_EXCHANGE_COINBASE) +add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US) add_executable(${NAME} main.cpp) diff --git a/example/src/execution_management_simple/main.cpp b/example/src/execution_management_simple/main.cpp index 56879b50..33ca9de1 100644 --- a/example/src/execution_management_simple/main.cpp +++ b/example/src/execution_management_simple/main.cpp @@ -18,14 +18,14 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } std::string mode(argv[1]); - std::string key = UtilSystem::getEnvAsString("COINBASE_API_KEY"); + std::string key = UtilSystem::getEnvAsString("BINANCE_US_API_KEY"); if (key.empty()) { - std::cerr << "Please set environment variable COINBASE_API_KEY" << std::endl; + std::cerr << "Please set environment variable BINANCE_US_API_KEY" << std::endl; return EXIT_FAILURE; } - std::string secret = UtilSystem::getEnvAsString("COINBASE_API_SECRET"); + std::string secret = UtilSystem::getEnvAsString("BINANCE_US_API_SECRET"); if (secret.empty()) { - std::cerr << "Please set environment variable COINBASE_API_SECRET" << std::endl; + std::cerr << "Please set environment variable BINANCE_US_API_SECRET" << std::endl; return EXIT_FAILURE; } SessionOptions sessionOptions; @@ -39,7 +39,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::CREATE_ORDER, "coinbase", argv[2]); + Request request(Request::Operation::CREATE_ORDER, "binance-us", argv[2]); request.appendParam({ {"SIDE", strcmp(argv[3], "buy") == 0 ? "BUY" : "SELL"}, {"QUANTITY", argv[4]}, @@ -53,7 +53,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::CANCEL_ORDER, "coinbase", argv[2]); + Request request(Request::Operation::CANCEL_ORDER, "binance-us", argv[2]); request.appendParam({ {"ORDER_ID", argv[3]} }); @@ -65,7 +65,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::GET_ORDER, "coinbase", argv[2]); + Request request(Request::Operation::GET_ORDER, "binance-us", argv[2]); request.appendParam({ {"ORDER_ID", argv[3]} }); @@ -77,7 +77,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::GET_OPEN_ORDERS, "coinbase", argv[2]); + Request request(Request::Operation::GET_OPEN_ORDERS, "binance-us", argv[2]); session.sendRequest(request); } else if (mode == "cancel_open_orders") { if (argc != 3) { @@ -86,7 +86,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::CANCEL_OPEN_ORDERS, "coinbase", argv[2]); + Request request(Request::Operation::CANCEL_OPEN_ORDERS, "binance-us", argv[2]); session.sendRequest(request); } std::this_thread::sleep_for(std::chrono::seconds(10)); From 3dda4579f85d6435555ae6fd6ca3848863e5b64b Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Thu, 31 Dec 2020 18:59:27 -0800 Subject: [PATCH 12/18] ci: fix cpplint --- .github/workflows/cpplint.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/cpplint.yml b/.github/workflows/cpplint.yml index e9eb4a7b..0d099462 100644 --- a/.github/workflows/cpplint.yml +++ b/.github/workflows/cpplint.yml @@ -14,6 +14,4 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 - run: pip install cpplint - - run: cpplint --recursive --exclude=include/ccapi_cpp/websocketpp_decompress_workaround.h \ - --filter -legal/copyright,-whitespace/line_length,-build/c++11,-runtime/references,-build/include_what_you_use,-runtime/int \ - include/**/* example/**/* test/**/* + - run: cpplint --recursive --exclude=include/ccapi_cpp/websocketpp_decompress_workaround.h --filter -legal/copyright,-whitespace/line_length,-build/c++11,-runtime/references,-build/include_what_you_use,-runtime/int include/**/* example/**/* test/**/* From 87c7a6080621c71f370cbbea9971705c2a91dbda Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Thu, 31 Dec 2020 20:30:24 -0800 Subject: [PATCH 13/18] test: use CMake to download GoogleTest as part of the build's configure step --- .github/workflows/test.yml | 32 ----------------- test/test_unit/CMakeLists.txt | 35 ++++++++++++++++++- test/test_unit/CMakeLists.txt.in | 14 ++++++++ test/test_unit/src/common/CMakeLists.txt | 2 +- .../binance_futures/CMakeLists.txt | 2 +- .../binance_us/CMakeLists.txt | 2 +- 6 files changed, 51 insertions(+), 36 deletions(-) create mode 100644 test/test_unit/CMakeLists.txt.in diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 13ba2560..4028a03b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -115,38 +115,6 @@ jobs: restore-keys: | ${{ matrix.config.name }}-ccache- - - name: Install GoogleTest - shell: cmake -P {0} - run: | - execute_process(COMMAND git clone https://github.com/google/googletest.git -b release-1.10.0) - execute_process( - COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake - -DBUILD_GMOCK=OFF - -S googletest - -B googletest/build - -D CMAKE_BUILD_TYPE=$ENV{BUILD_TYPE} - RESULT_VARIABLE result - ) - if (NOT result EQUAL 0) - message(FATAL_ERROR "Bad exit status") - endif() - - execute_process( - COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build googletest/build -j - RESULT_VARIABLE result - ) - if (NOT result EQUAL 0) - message(FATAL_ERROR "Bad exit status") - endif() - - execute_process( - COMMAND sudo ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --install googletest/build - RESULT_VARIABLE result - ) - if (NOT result EQUAL 0) - message(FATAL_ERROR "Bad exit status") - endif() - - name: Install OpenSSL shell: cmake -P {0} run: | diff --git a/test/test_unit/CMakeLists.txt b/test/test_unit/CMakeLists.txt index dadf7e7c..0773ac47 100644 --- a/test/test_unit/CMakeLists.txt +++ b/test/test_unit/CMakeLists.txt @@ -1,6 +1,39 @@ set(NAME unit_test) project(${NAME}) -find_package(GTest REQUIRED) + +# Download and unpack googletest at configure time +configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -DBUILD_GMOCK=OFF . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines +# the gtest and gtest_main targets. +add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src + ${CMAKE_CURRENT_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) + +# The gtest/gtest_main targets carry header search path +# dependencies automatically when using CMake 2.8.11 or +# later. Otherwise we have to add them here ourselves. +if (CMAKE_VERSION VERSION_LESS 2.8.11) + include_directories("${gtest_SOURCE_DIR}/include") +endif() + +include(GoogleTest) add_subdirectory(src/common) add_subdirectory(src/execution_management/binance_us) add_subdirectory(src/execution_management/binance_futures) diff --git a/test/test_unit/CMakeLists.txt.in b/test/test_unit/CMakeLists.txt.in new file mode 100644 index 00000000..651522f5 --- /dev/null +++ b/test/test_unit/CMakeLists.txt.in @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.12) +project(googletest-download) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.10.0 + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) diff --git a/test/test_unit/src/common/CMakeLists.txt b/test/test_unit/src/common/CMakeLists.txt index 322c5df4..59e8564c 100644 --- a/test/test_unit/src/common/CMakeLists.txt +++ b/test/test_unit/src/common/CMakeLists.txt @@ -1,5 +1,5 @@ set(NAME common) project(${NAME}) add_executable(${NAME} ${SOURCE_LOGGER} ccapi_decimal_test.cpp ccapi_hmac_test.cpp) -target_link_libraries(${NAME} GTest::GTest GTest::Main) +target_link_libraries(${NAME} gtest_main) gtest_discover_tests(${NAME}) diff --git a/test/test_unit/src/execution_management/binance_futures/CMakeLists.txt b/test/test_unit/src/execution_management/binance_futures/CMakeLists.txt index 9cb95761..e193a22d 100644 --- a/test/test_unit/src/execution_management/binance_futures/CMakeLists.txt +++ b/test/test_unit/src/execution_management/binance_futures/CMakeLists.txt @@ -3,5 +3,5 @@ project(${NAME}) add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT) add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES) add_executable(${NAME} ${SOURCE_LOGGER} test.cpp) -target_link_libraries(${NAME} GTest::GTest GTest::Main) +target_link_libraries(${NAME} gtest_main) gtest_discover_tests(${NAME}) diff --git a/test/test_unit/src/execution_management/binance_us/CMakeLists.txt b/test/test_unit/src/execution_management/binance_us/CMakeLists.txt index c99ac5c5..63f73a2a 100644 --- a/test/test_unit/src/execution_management/binance_us/CMakeLists.txt +++ b/test/test_unit/src/execution_management/binance_us/CMakeLists.txt @@ -3,5 +3,5 @@ project(${NAME}) add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT) add_compile_definitions(CCAPI_ENABLE_EXCHANGE_BINANCE_US) add_executable(${NAME} ${SOURCE_LOGGER} test.cpp) -target_link_libraries(${NAME} GTest::GTest GTest::Main) +target_link_libraries(${NAME} gtest_main) gtest_discover_tests(${NAME}) From 2baede7e2d22b3f492b8bfc70c1910b0687cc7a5 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Thu, 31 Dec 2020 21:10:59 -0800 Subject: [PATCH 14/18] fix: cppling --- include/ccapi_cpp/ccapi_request.h | 2 +- include/ccapi_cpp/ccapi_subscription.h | 2 +- include/ccapi_cpp/ccapi_util_private.h | 68 ++++--------------- ...capi_execution_management_service_gemini.h | 3 +- ...ccapi_execution_management_service_huobi.h | 8 +-- test/test_build/test.cpp | 2 +- .../execution_management/binance_us/test.cpp | 1 - 7 files changed, 19 insertions(+), 67 deletions(-) diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index bbbf9bfa..83341448 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -52,7 +52,7 @@ class Request CCAPI_FINAL { } } #ifdef SWIG - Request(){} + Request() {} #endif std::string toString() const { std::map shortCredential; diff --git a/include/ccapi_cpp/ccapi_subscription.h b/include/ccapi_cpp/ccapi_subscription.h index b50e63a3..6917563c 100644 --- a/include/ccapi_cpp/ccapi_subscription.h +++ b/include/ccapi_cpp/ccapi_subscription.h @@ -8,7 +8,7 @@ namespace ccapi { class Subscription CCAPI_FINAL { public: #ifdef SWIG - Subscription(){} + Subscription() {} #endif Subscription(std::string exchange, std::string instrument, std::string field, std::string options = "", std::string correlationId = "", std::map credential = {}) diff --git a/include/ccapi_cpp/ccapi_util_private.h b/include/ccapi_cpp/ccapi_util_private.h index 9a9f9041..9445903f 100644 --- a/include/ccapi_cpp/ccapi_util_private.h +++ b/include/ccapi_cpp/ccapi_util_private.h @@ -1,7 +1,5 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_UTIL_PRIVATE_H_ #define INCLUDE_CCAPI_CPP_CCAPI_UTIL_PRIVATE_H_ -//#include -//#include #include #include #include @@ -204,31 +202,31 @@ class UtilAlgorithm CCAPI_FINAL { } static std::string base64Encode(const std::string &in) { std::string out; - int val=0, valb=-6; + int val = 0, valb = -6; for (unsigned char c : in) { - val = (val<<8) + c; + val = (val << 8) + c; valb += 8; - while (valb>=0) { - out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val>>valb)&0x3F]); - valb-=6; + while (valb >= 0) { + out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb)&0x3F]); + valb -= 6; } } - if (valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val<<8)>>(valb+8))&0x3F]); + if (valb > -6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8))&0x3F]); while (out.size()%4) out.push_back('='); return out; } static std::string base64Decode(const std::string &in) { std::string out; - std::vector T(256,-1); - for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; - int val=0, valb=-8; + std::vector T(256, -1); + for (int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; + int val = 0, valb = -8; for (unsigned char c : in) { if (T[c] == -1) break; - val = (val<<6) + T[c]; + val = (val << 6) + T[c]; valb += 6; - if (valb>=0) { - out.push_back(char((val>>valb)&0xFF)); - valb-=8; + if (valb >= 0) { + out.push_back(static_cast((val >> valb)&0xFF)); + valb -= 8; } } return out; @@ -237,46 +235,6 @@ class UtilAlgorithm CCAPI_FINAL { return initial + multiplier * (pow(base, exponent) - 1); } template static uint_fast32_t crc(InputIterator first, InputIterator last); -// static std::string hmac(std::string key, std::string msg, bool returnHex = false, const std::string& algorithm = "") { -// unsigned char hash[32]; -//#if defined(OPENSSL_VERSION_MAJOR) && defined(OPENSSL_VERSION_MINOR) && OPENSSL_VERSION_MAJOR <= 1 && (OPENSSL_VERSION_MAJOR != 1 || OPENSSL_VERSION_MINOR < 1) -// HMAC_CTX hmac; -// HMAC_CTX_init(&hmac); -// if (algorithm == "sha384") { -// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha384(), NULL); -// } else { -// HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL); -// } -// HMAC_Update(&hmac, (unsigned char*)&msg[0], msg.length()); -// unsigned int len = 32; -// HMAC_Final(&hmac, hash, &len); -// HMAC_CTX_cleanup(&hmac); -//#else -// HMAC_CTX *hmac = HMAC_CTX_new(); -// if (algorithm == "sha384") { -// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha384(), NULL); -// } else { -// HMAC_Init_ex(hmac, &key[0], key.length(), EVP_sha256(), NULL); -// } -// HMAC_Update(hmac, (unsigned char*)&msg[0], msg.length()); -// unsigned int len = 32; -// HMAC_Final(hmac, hash, &len); -// HMAC_CTX_free(hmac); -//#endif -// std::stringstream ss; -// if (returnHex) { -// ss << std::hex << std::setfill('0'); -// for (int i = 0; i < len; i++) { -// ss << std::hex << std::setw(2) << (unsigned int)hash[i]; -// } -// } else { -// ss << std::setfill('0'); -// for (int i = 0; i < len; i++) { -// ss << hash[i]; -// } -// } -// return (ss.str()); -// } }; template uint_fast32_t UtilAlgorithm::crc(InputIterator first, InputIterator last) { static auto const table = []() { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h index 93c6df34..c27f08e0 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_gemini.h @@ -161,8 +161,7 @@ class ExecutionManagementServiceGemini CCAPI_FINAL : public ExecutionManagementS element.insert(CCAPI_EM_ORDER_ID, std::to_string(x.GetInt())); elementList.emplace_back(element); } - } - else if (document.IsObject()) { + } else if (document.IsObject()) { elementList.emplace_back(this->extractOrderInfo(document, extractionFieldNameMap)); } else { for (const auto& x : document.GetArray()) { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h index aecefafc..ba8ae0f8 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h @@ -63,12 +63,8 @@ class ExecutionManagementServiceHuobi CCAPI_FINAL : public ExecutionManagementSe } void appendParam(std::map& queryParamMap, const std::map& param, const std::map regularizationMap = {}) { for (const auto& kv : param) { - queryParamMap.insert( - std::make_pair( - regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first, - Url::urlEncode(kv.second) - ) - ); + queryParamMap.insert(std::make_pair(regularizationMap.find(kv.first) != regularizationMap.end() ? regularizationMap.at(kv.first) : kv.first, + Url::urlEncode(kv.second))); } } void appendSymbolId(rj::Document& document, rj::Document::AllocatorType& allocator, const std::string symbolId) { diff --git a/test/test_build/test.cpp b/test/test_build/test.cpp index 0b6fbd4c..fd855f13 100644 --- a/test/test_build/test.cpp +++ b/test/test_build/test.cpp @@ -1,6 +1,6 @@ #include "ccapi_cpp/ccapi_session.h" int main(int argc, char **argv) { - using namespace ccapi; + using namespace ccapi; // NOLINT(build/namespaces) Session session; return EXIT_SUCCESS; } diff --git a/test/test_unit/src/execution_management/binance_us/test.cpp b/test/test_unit/src/execution_management/binance_us/test.cpp index 5dc8303c..3df0aee4 100644 --- a/test/test_unit/src/execution_management/binance_us/test.cpp +++ b/test/test_unit/src/execution_management/binance_us/test.cpp @@ -95,7 +95,6 @@ TEST_F(ExecutionManagementServiceBinanceUsTest, convertRequestCancelOrderByOrder EXPECT_EQ(req.method(), http::verb::delete_); verifyApiKey(req, this->credential.at(CCAPI_BINANCE_US_API_KEY)); auto splitted = UtilString::split(std::string(req.target()), "?"); - std::cout< Date: Thu, 31 Dec 2020 21:11:24 -0800 Subject: [PATCH 15/18] fix: cppling --- .github/workflows/cpplint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cpplint.yml b/.github/workflows/cpplint.yml index 0d099462..25685c0a 100644 --- a/.github/workflows/cpplint.yml +++ b/.github/workflows/cpplint.yml @@ -14,4 +14,4 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-python@v1 - run: pip install cpplint - - run: cpplint --recursive --exclude=include/ccapi_cpp/websocketpp_decompress_workaround.h --filter -legal/copyright,-whitespace/line_length,-build/c++11,-runtime/references,-build/include_what_you_use,-runtime/int include/**/* example/**/* test/**/* + - run: cpplint --recursive --exclude=include/ccapi_cpp/ccapi_hmac.h --exclude=include/ccapi_cpp/websocketpp_decompress_workaround.h --exclude=*/build --filter -legal/copyright,-whitespace/line_length,-build/c++11,-runtime/references,-build/include_what_you_use,-runtime/int include/**/* example/**/* test/**/* From d6668e36cb7a1b424c4063e9b19cb4477c383436 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Thu, 31 Dec 2020 22:19:58 -0800 Subject: [PATCH 16/18] ci: fix linux build --- include/ccapi_cpp/ccapi_http_retry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ccapi_cpp/ccapi_http_retry.h b/include/ccapi_cpp/ccapi_http_retry.h index 012fdded..d7158e7b 100644 --- a/include/ccapi_cpp/ccapi_http_retry.h +++ b/include/ccapi_cpp/ccapi_http_retry.h @@ -4,7 +4,7 @@ namespace ccapi { class HttpRetry CCAPI_FINAL { public: - explicit HttpRetry(int numRetry = 0, int numRedirect = 0, std::string redirectUrlStr = "", std::shared_ptr > promisePtr = std::make_shared >(nullptr)): + explicit HttpRetry(int numRetry = 0, int numRedirect = 0, std::string redirectUrlStr = "", std::shared_ptr > promisePtr = std::shared_ptr >(nullptr)): numRetry(numRetry), numRedirect(numRedirect), promisePtr(promisePtr) {} std::string toString() const { std::ostringstream oss; From dabfca4432e9f17696696b160d03bb69c5a0f5d7 Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Tue, 5 Jan 2021 11:28:25 -0800 Subject: [PATCH 17/18] docs: update README.md --- .github/workflows/release.yml | 2 +- README.md | 214 +++++++++++++++--- .../src/execution_management_simple/main.cpp | 4 +- example/src/market_data_advanced/main.cpp | 4 +- include/ccapi_cpp/ccapi_element.h | 6 + include/ccapi_cpp/ccapi_event.h | 7 + include/ccapi_cpp/ccapi_macro.h | 7 + include/ccapi_cpp/ccapi_message.h | 8 + include/ccapi_cpp/ccapi_session.h | 37 +-- include/ccapi_cpp/ccapi_session_options.h | 19 +- include/ccapi_cpp/ccapi_util_private.h | 78 ++++++- .../ccapi_execution_management_service.h | 7 +- 12 files changed, 326 insertions(+), 67 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f27b75c..84e07a17 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,7 +34,7 @@ jobs: {"type": "perf", "release": "patch"}, {"type": "test", "release": "patch"}, {"type": "minor", "release": "minor"}, - {"type": "major", "release": "major"}, + {"type": "major", "release": "major"} ] }], ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" diff --git a/README.md b/README.md index bcb1bb25..1c9ad92f 100644 --- a/README.md +++ b/README.md @@ -7,29 +7,46 @@ - [Build](#build) - [Constants](#constants) - [Examples](#examples) - - [Simple](#simple) - - [Advanced](#advanced) + - [Simple Market Data](#simple-market-data) + - [Advanced Market Data](#advanced-market-data) - [Specify market depth](#specify-market-depth) - [Specify correlation id](#specify-correlation-id) - [Normalize instrument name](#normalize-instrument-name) - [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments) - [Receive events at periodic intervals](#receive-events-at-periodic-intervals) - [Receive events at periodic intervals including when the market depth snapshot hasn't changed](#receive-events-at-periodic-intervals-including-when-the-market-depth-snapshot-hasnt-changed) - - [Dispatch events to multiple threads](#dispatch-events-to-multiple-threads) - - [Handle Events Synchronously](#handle-events-synchronously) + - [Simple Execution Management](#simple-execution-management) + - [Advanced Execution Management](#advanced-execution-management) + - [Specify correlation id](#specify-correlation-id-1) + - [Normalize instrument name](#normalize-instrument-name-1) + - [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments-1) + - [Make Session::sendRequest blocking](#make-sessionsendrequest-blocking) + - [Multiple sets of API credentials for the same exchange](#multiple-sets-of-api-credentials-for-the-same-exchange) + - [Override exchange urls](#override-exchange-urls) + - [More Advanced Topics](#more-advanced-topics) + - [Handle events in "immediate" vs. "batching" mode](#handle-events-in-immediate-vs-batching-mode) + - [Thread safety](#thread-safety) - [Enable library logging](#enable-library-logging) - [Contributing](#contributing) -**NEW**: Version 2.0.0 has been released. The APIs remain to be largely the same to version 1.x.x except for a few small breaking changes with the most prominent one being renaming of some of the macros needed at build time. +**NEW**: Version 2.2.x released execution management for the binance family: binance, binance-futures, and binance-us. + +**BREAKING CHANGE**: Version 2.2.x introduced a few breaking changes: +* Added `CCAPI_CPP_` prefix to enablement macros. +* Changed `eventQueue` visibility in `Session` from public to private. +* Changed `logMessage` parameters in `Logger` from mixed types to all std::string. + # ccapi_cpp -* A header-only C++ library for streaming public market data directly from cryptocurrency exchanges (i.e. the connections are between your server and the exchange server without anything in-between). +* A header-only C++ library for streaming market data and executing trades directly from cryptocurrency exchanges (i.e. the connections are between your server and the exchange server without anything in-between). * Code closely follows Bloomberg's API: https://www.bloomberg.com/professional/support/api-library/. * It is ultra fast thanks to very careful optimizations: move semantics, regex optimization, locality of reference, lock contention minimization, etc. -* Supported exchanges: coinbase, gemini, kraken, bitstamp, bitfinex, bitmex, binance-us, binance, binance-futures, huobi, okex. +* Supported exchanges: + * Market data: coinbase, gemini, kraken, bitstamp, bitfinex, bitmex, binance-us, binance, binance-futures, huobi, okex. + * Execution Management: binance-us, binance, binance-futures. * To spur innovation and industry collaboration, this library is open for use by the public without cost. Follow us on https://medium.com/@cryptochassis and our publication on https://medium.com/open-crypto-market-data-initiative. -* For historical data, see https://github.com/crypto-chassis/cryptochassis-api-docs. +* For historical market data, see https://github.com/crypto-chassis/cryptochassis-api-docs. * Since symbol normalization is a tedious task, you can choose to use a reference file at https://marketdata-e0323a9039add2978bf5b49550572c7c-public.s3.amazonaws.com/supported_exchange_instrument_subscription_data.csv.gz which we frequently update. * Please contact us for general questions, issue reporting, consultative services, and/or custom engineering work. To subscribe to our mailing list, simply send us an email with subject "subscribe". @@ -42,7 +59,7 @@ * Example CMake: example/CMakeLists.txt. * Require C++14 and OpenSSL. * Definitions in the compiler command line: - * Define service enablement macro `CCAPI_ENABLE_SERVICE_MARKET_DATA` and exchange enablement macros such as `CCAPI_ENABLE_EXCHANGE_COINBASE`, etc. These macros can be found at the top of `include/ccapi_cpp/ccapi_session.h`. + * Define service enablement macro such as `CCAPI_ENABLE_SERVICE_MARKET_DATA`, `CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT`, etc. and exchange enablement macros such as `CCAPI_ENABLE_EXCHANGE_COINBASE`, etc. These macros can be found at the top of `include/ccapi_cpp/ccapi_session.h`. * Include directories: * include * dependency/websocketpp @@ -62,7 +79,7 @@ ## Examples [Source](example) -### Simple +### Simple Market Data **Objective:** For a specific exchange and instrument, whenever the top 10 bids' or asks' price or size change, print the market depth snapshot at that moment. @@ -114,7 +131,7 @@ Best bid and ask at 2020-07-27T23:56:51.935993000Z are: ... ``` -### Advanced +### Advanced Market Data #### Specify market depth Instantiate `Subscription` with option `MARKET_DEPTH_MAX` set to be the desired market depth. @@ -138,7 +155,6 @@ std::string coolName = "btc_usd"; exchangeInstrumentSymbolMap["coinbase"][coolName] = "BTC-USD"; SessionConfigs sessionConfigs(exchangeInstrumentSymbolMap); Session session(sessionOptions, sessionConfigs, &eventHandler); -Subscription subscription("coinbase", coolName, "MARKET_DEPTH"); ``` #### Multiple exchanges and/or instruments @@ -146,9 +162,9 @@ Subscription subscription("coinbase", coolName, "MARKET_DEPTH"); Subscribe a `std::vector`. ``` std::vector subscriptionList; -Subscription subscription_1("coinbase", "BTC-USD", "MARKET_DEPTH", "", "coinbase|btc_usd"); +Subscription subscription_1("coinbase", "BTC-USD", "MARKET_DEPTH"); subscriptionList.push_back(subscription_1); -Subscription subscription_2("binance-us", "ethusd", "MARKET_DEPTH", "", "binance-us|eth_usd"); +Subscription subscription_2("binance-us", "ethusd", "MARKET_DEPTH"); subscriptionList.push_back(subscription_2); session.subscribe(subscriptionList); ``` @@ -167,35 +183,179 @@ Instantiate `Subscription` with option `CCAPI_EXCHANGE_NAME_CONFLATE_INTERVAL_MI Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH", "CONFLATE_INTERVAL_MILLISECONDS=1000&CONFLATE_GRACE_PERIOD_MILLISECONDS=0"); ``` -#### Dispatch events to multiple threads +### Simple Execution Management +**Objective:** -Instantiate `EventDispatcher` with -`numDispatcherThreads` set to be the desired number. +For a specific exchange and instrument, submit a simple limit order. + +**Code:** ``` -EventDispatcher eventDispatcher(2); -Session session(sessionOptions, sessionConfigs, &eventHandler, &eventDispatcher); +#include "ccapi_cpp/ccapi_session.h" +namespace ccapi { +Logger* Logger::logger = nullptr; // This line is needed. +class MyEventHandler : public EventHandler { + public: + bool processEvent(const Event& event, Session *session) override { + std::cout << "Received an event: " + toString(event) << std::endl; + return true; + } +}; +} /* namespace ccapi */ +int main(int argc, char** argv) { + using namespace ccapi; // NOLINT(build/namespaces) + std::string key = UtilSystem::getEnvAsString("BINANCE_US_API_KEY"); + if (key.empty()) { + std::cerr << "Please set environment variable BINANCE_US_API_KEY" << std::endl; + return EXIT_FAILURE; + } + std::string secret = UtilSystem::getEnvAsString("BINANCE_US_API_SECRET"); + if (secret.empty()) { + std::cerr << "Please set environment variable BINANCE_US_API_SECRET" << std::endl; + return EXIT_FAILURE; + } + SessionOptions sessionOptions; + SessionConfigs sessionConfigs; + MyEventHandler eventHandler; + Session session(sessionOptions, sessionConfigs, &eventHandler); + Request request(Request::Operation::CREATE_ORDER, "binance-us", "BTCUSD"); + request.appendParam({ + {"SIDE", "BUY"}, + {"QUANTITY", "0.0005"}, + {"LIMIT_PRICE", "20000"} + }); + session.sendRequest(request); + std::this_thread::sleep_for(std::chrono::seconds(10)); + session.stop(); + std::cout << "Bye" << std::endl; + return EXIT_SUCCESS; +} +``` +**Output:** +```console +Received an event: + Event [ + type = RESPONSE, + messageList = [ + Message [ + type = CREATE_ORDER, + recapType = UNKNOWN, + time = 1970-01-01T00:00:00.000000000Z, + timeReceived = 2021-01-04T04:15:04.710133000Z, + elementList = [ + Element [ + nameValueMap = { + CLIENT_ORDER_ID = MbdTQCHc0EQgLKry0Ryrhr, + CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY = 0.0000, + CUMULATIVE_FILLED_QUANTITY = 0.00000000, + INSTRUMENT = BTCUSD, + LIMIT_PRICE = 20000.0000, + ORDER_ID = 187143156, + QUANTITY = 0.00050000, + SIDE = BUY, + STATUS = OPEN + } + ] + ], + correlationIdList = [ 5PN2qmWqBlQ9wQj99nsQzldVI5ZuGXbE ] + ] + ] + ] +Bye ``` +### Advanced Execution Management -#### Handle Events Synchronously +#### Specify correlation id -Instantiate `Session` without `EventHandler`, then obtain the events to be processed by calling `session.eventQueue.purge()`. +Instantiate `Request` with the desired correlationId. +``` +Request request(Request::Operation::CREATE_ORDER, "binance-us", "BTCUSD", "cool correlation id"); +``` + +#### Normalize instrument name + +Instantiate `SessionConfigs` with a map mapping the exchange name and the normalized instrument name to the instrument's symbol on the exchange. +``` +std::map > exchangeInstrumentSymbolMap; +std::string coolName = "btc_usd"; +exchangeInstrumentSymbolMap["coinbase"][coolName] = "BTC-USD"; +SessionConfigs sessionConfigs(exchangeInstrumentSymbolMap); +Session session(sessionOptions, sessionConfigs, &eventHandler); +``` + +#### Multiple exchanges and/or instruments + +Send a `std::vector`. +``` +std::vector requestList; +Request request_1(Request::Operation::CREATE_ORDER, "binance-us", "BTCUSD"); +request_1.appendParam(...); +requestList.push_back(request_1); +Request request_2(Request::Operation::CREATE_ORDER, "binance-us", "ETHUSD"); +request_2.appendParam(...); +requestList.push_back(request_2); +session.sendRequest(requestList); +``` + +#### Make Session::sendRequest blocking +Instantiate `Session` without `EventHandler` argument, and pass a pointer to `Queue` as an additional argument. ``` Session session(sessionOptions, sessionConfigs); -Subscription subscription("coinbase", "BTC-USD", "MARKET_DEPTH"); -session.subscribe(subscription); -std::this_thread::sleep_for(std::chrono::seconds(5)); +... +Queue eventQueue; +session.sendRequest(request, &eventQueue); // block until a response is received +std::vector eventList = eventQueue.purge(); +``` + +#### Multiple sets of API credentials for the same exchange +There are 3 ways to provide API credentials (listed with increasing priority). +* Set the relevent environment variables (see section "exchange API credentials" in `include/ccapi_cpp/ccapi_macro.h`). +* Provide credentials to `SessionConfigs`. +``` +sessionConfigs.setCredential({ + {"BINANCE_US_API_KEY", ...}, + {"BINANCE_US_API_SECRET", ...} +}); +``` +* Provide credentials to `Request`. +``` +Request request(Request::Operation::CREATE_ORDER, "binance-us", "BTCUSD", "cool correlation id", { + {"BINANCE_US_API_KEY", ...}, + {"BINANCE_US_API_SECRET", ...} +}); +``` + +#### Override exchange urls +See section "exchange REST urls" in `include/ccapi_cpp/ccapi_macro.h`. +### More Advanced Topics + +#### Handle events in "immediate" vs. "batching" mode + +In general there are 2 ways to handle events. +* When a `Session` is instantiated with an `eventHandler` argument, it will handle events in immediate mode. The `processEvent` method in the `eventHandler` will be executed on one of the internal threads in the `eventDispatcher`. A default `EventDispatcher` with 1 internal thread will be created if no `eventDispatcher` argument is provided in `Session` instantiation. To dispatch events to multiple threads, instantiate `EventDispatcher` with `numDispatcherThreads` set to be the desired number. +``` +EventDispatcher eventDispatcher(2); +Session session(sessionOptions, sessionConfigs, &eventHandler, &eventDispatcher); +``` +`EventHandler`s and/or `EventDispatcher`s can be shared among different sessions. Otherwise, different sessions are independent from each other. +* When a `Session` is instantiated without an `eventHandler` argument, it will handle events in batching mode. The evetns will be batched into an internal `Queue` and can be retrieved by +``` std::vector eventList = session.getEventQueue().purge(); ``` +#### Thread safety +The following methods are implemented to be thread-safe: `Session::subscribe`, `Session::sendRequest`, all public methods in `Queue`. + #### Enable library logging Extend a subclass, e.g. `MyLogger`, from class `Logger` and override method `logMessage`. Assign a `MyLogger` pointer to `Logger::logger`. Add one of the following macros in the compiler command line: `CCAPI_ENABLE_LOG_TRACE`, `CCAPI_ENABLE_LOG_DEBUG`, `CCAPI_ENABLE_LOG_INFO`, `CCAPI_ENABLE_LOG_WARN`, `CCAPI_ENABLE_LOG_ERROR`, `CCAPI_ENABLE_LOG_FATAL`. ``` namespace ccapi { class MyLogger final: public Logger { - virtual void logMessage(std::string severity, std::string threadId, + virtual void logMessage(std::string severity, + std::string threadId, std::string timeISO, - std::string fileName, std::string lineNumber, + std::string fileName, + std::string lineNumber, std::string message) override { ... } @@ -204,6 +364,8 @@ MyLogger myLogger; Logger* Logger::logger = &myLogger; } ``` + + ### Contributing * (Required) Submit a pull request to the master branch. * (Required) Pass Github checks: https://docs.github.com/en/rest/reference/checks. diff --git a/example/src/execution_management_simple/main.cpp b/example/src/execution_management_simple/main.cpp index 33ca9de1..e601f65b 100644 --- a/example/src/execution_management_simple/main.cpp +++ b/example/src/execution_management_simple/main.cpp @@ -4,7 +4,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: bool processEvent(const Event& event, Session *session) override { - std::cout << "Received an event: " + toString(event) << std::endl; + std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } }; @@ -39,7 +39,7 @@ int main(int argc, char** argv) { session.stop(); return EXIT_FAILURE; } - Request request(Request::Operation::CREATE_ORDER, "binance-us", argv[2]); + Request request(Request::Operation::CREATE_ORDER, "binance-us", argv[2]); request.appendParam({ {"SIDE", strcmp(argv[3], "buy") == 0 ? "BUY" : "SELL"}, {"QUANTITY", argv[4]}, diff --git a/example/src/market_data_advanced/main.cpp b/example/src/market_data_advanced/main.cpp index 20f6fd49..e66e5d37 100644 --- a/example/src/market_data_advanced/main.cpp +++ b/example/src/market_data_advanced/main.cpp @@ -14,7 +14,7 @@ int main(int argc, char **argv) { std::vector modeList = { "specify_correlation_id", "normalize_instrument_name", "multiple_exchanges_instruments", "specify_market_depth", "receive_events_at_periodic_intervals", "receive_events_at_periodic_intervals_including_when_the_market_depth_snapshot_has_not_changed", - "dispatch_events_to_multiple_threads", "handle_events_synchronously" }; + "dispatch_events_to_multiple_threads", "handle_events_in_batching_mode" }; if (argc != 2 || std::find(modeList.begin(), modeList.end(), argv[1]) == modeList.end()) { std::cerr << "Please provide one command line argument from this list: " + toString(modeList) << std::endl; return EXIT_FAILURE; @@ -93,7 +93,7 @@ int main(int argc, char **argv) { std::this_thread::sleep_for(std::chrono::seconds(10)); session.stop(); eventDispatcher.stop(); - } else if (mode == "handle_events_synchronously") { + } else if (mode == "handle_events_in_batching_mode") { SessionOptions sessionOptions; SessionConfigs sessionConfigs; Session session(sessionOptions, sessionConfigs); diff --git a/include/ccapi_cpp/ccapi_element.h b/include/ccapi_cpp/ccapi_element.h index 6bbd92be..75bfcc58 100644 --- a/include/ccapi_cpp/ccapi_element.h +++ b/include/ccapi_cpp/ccapi_element.h @@ -19,6 +19,12 @@ class Element CCAPI_FINAL { std::string output = "Element [nameValueMap = " + ccapi::toString(nameValueMap) + "]"; return output; } + std::string toStringPretty(const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) const { + std::string sl(leftToIndent, ' '); + std::string ss(leftToIndent + space, ' '); + std::string output = (indentFirstLine ? sl : "") + "Element [\n" + ss + "nameValueMap = " + ccapi::toStringPretty(nameValueMap, space, space + leftToIndent, false) + "\n" + sl + "]"; + return output; + } const std::map& getNameValueMap() const { return nameValueMap; } diff --git a/include/ccapi_cpp/ccapi_event.h b/include/ccapi_cpp/ccapi_event.h index 8f7aad29..46fda20a 100644 --- a/include/ccapi_cpp/ccapi_event.h +++ b/include/ccapi_cpp/ccapi_event.h @@ -81,6 +81,13 @@ class Event CCAPI_FINAL { + "]"; return output; } + std::string toStringPretty(const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) const { + std::string sl(leftToIndent, ' '); + std::string ss(leftToIndent + space, ' '); + std::string output = (indentFirstLine ? sl : "") + "Event [\n" + ss + "type = " + typeToString(type) + ",\n" + ss + "messageList = " + ccapi::toStringPretty(messageList, space, leftToIndent + space, false) + + "\n" + sl + "]"; + return output; + } const std::vector& getMessageList() const { return messageList; } diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 0a5b0935..4201479b 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -183,6 +183,8 @@ #ifndef CCAPI_CREDENTIAL_DISPLAY_LENGTH #define CCAPI_CREDENTIAL_DISPLAY_LENGTH 4 #endif + +// start: exchange REST urls #ifndef CCAPI_COINBASE_URL_REST_BASE #define CCAPI_COINBASE_URL_REST_BASE "https://api.pro.coinbase.com" #endif @@ -213,6 +215,9 @@ #ifndef CCAPI_HUOBI_URL_REST_BASE #define CCAPI_HUOBI_URL_REST_BASE "https://api.huobi.pro" #endif +// end: exchange REST urls + +// start: exchange API credentials #ifndef CCAPI_COINBASE_API_KEY #define CCAPI_COINBASE_API_KEY "COINBASE_API_KEY" #endif @@ -258,6 +263,8 @@ #ifndef CCAPI_HUOBI_API_SECRET #define CCAPI_HUOBI_API_SECRET "HUOBI_API_SECRET" #endif +// end: exchange API credentials + #ifndef CCAPI_BITMEX_API_RECEIVE_WINDOW_SECONDS #define CCAPI_BITMEX_API_RECEIVE_WINDOW_SECONDS 5 #endif diff --git a/include/ccapi_cpp/ccapi_message.h b/include/ccapi_cpp/ccapi_message.h index 659ed5e3..92dd8355 100644 --- a/include/ccapi_cpp/ccapi_message.h +++ b/include/ccapi_cpp/ccapi_message.h @@ -109,6 +109,14 @@ class Message CCAPI_FINAL { + ", correlationIdList = " + ccapi::toString(correlationIdList) + "]"; return output; } + std::string toStringPretty(const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) const { + std::string sl(leftToIndent, ' '); + std::string ss(leftToIndent + space, ' '); + std::string output = (indentFirstLine ? sl : "") + "Message [\n" + ss + "type = " + typeToString(type) + ",\n" + ss + "recapType = " + recapTypeToString(recapType) + + ",\n" + ss + "time = " + UtilTime::getISOTimestamp(time) + ",\n" + ss + "timeReceived = " + UtilTime::getISOTimestamp(timeReceived) + ",\n" + ss + "elementList = " + ccapi::firstNToStringPretty(elementList, 10, space, space + leftToIndent, false) + + ",\n" + ss + "correlationIdList = " + ccapi::toString(correlationIdList) + "\n" + sl + "]"; + return output; + } const std::vector& getElementList() const { return elementList; } diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 2e53dbb3..f14d06ba 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -1,6 +1,8 @@ #ifndef INCLUDE_CCAPI_CPP_CCAPI_SESSION_H_ #define INCLUDE_CCAPI_CPP_CCAPI_SESSION_H_ #include "ccapi_cpp/ccapi_macro.h" + +// start: enable exchanges for market data #ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA #ifdef CCAPI_ENABLE_EXCHANGE_COINBASE #include "ccapi_cpp/service/ccapi_market_data_service_coinbase.h" @@ -36,16 +38,19 @@ #include "ccapi_cpp/service/ccapi_market_data_service_okex.h" #endif #endif +// end: enable exchanges for market data + +// start: enable exchanges for execution management #ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT -#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE -#include "ccapi_cpp/service/ccapi_execution_management_service_coinbase.h" -#endif -#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI -#include "ccapi_cpp/service/ccapi_execution_management_service_gemini.h" -#endif -#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX -#include "ccapi_cpp/service/ccapi_execution_management_service_bitmex.h" -#endif +//#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE +//#include "ccapi_cpp/service/ccapi_execution_management_service_coinbase.h" +//#endif +//#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI +//#include "ccapi_cpp/service/ccapi_execution_management_service_gemini.h" +//#endif +//#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX +//#include "ccapi_cpp/service/ccapi_execution_management_service_bitmex.h" +//#endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_us.h" #endif @@ -55,10 +60,12 @@ #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h" #endif -#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI -#include "ccapi_cpp/service/ccapi_execution_management_service_huobi.h" -#endif +//#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI +//#include "ccapi_cpp/service/ccapi_execution_management_service_huobi.h" +//#endif #endif +// end: enable exchanges for execution management + #include "ccapi_cpp/ccapi_session_options.h" #include "ccapi_cpp/ccapi_session_configs.h" #include @@ -282,7 +289,7 @@ class Session CCAPI_FINAL { CCAPI_LOGGER_FUNCTION_ENTER; CCAPI_LOGGER_TRACE("event = "+toString(event)); if (this->eventHandler) { - CCAPI_LOGGER_TRACE("handle event asynchronously"); + CCAPI_LOGGER_TRACE("handle event in immediate mode"); this->eventDispatcher->dispatch([&, event] { bool shouldContinue = true; try { @@ -296,7 +303,7 @@ class Session CCAPI_FINAL { } }); } else { - CCAPI_LOGGER_TRACE("handle event synchronously"); + CCAPI_LOGGER_TRACE("handle event in batching mode"); if (eventQueue) { eventQueue->pushBack(std::move(event)); } else { @@ -330,7 +337,7 @@ class Session CCAPI_FINAL { } std::shared_ptr& servicePtr = serviceByExchangeMap.at(exchange); std::string key = serviceName + exchange; - if (eventQueuePtr && serviceNameExchangeSet.find(key) != serviceNameExchangeSet.end()) { + if (eventQueuePtr && serviceNameExchangeSet.find(key) == serviceNameExchangeSet.end()) { servicePtr->setEventHandler(std::bind(&Session::onEvent, this, std::placeholders::_1, eventQueuePtr)); serviceNameExchangeSet.insert(key); } diff --git a/include/ccapi_cpp/ccapi_session_options.h b/include/ccapi_cpp/ccapi_session_options.h index 07c6be52..6c0dc8e2 100644 --- a/include/ccapi_cpp/ccapi_session_options.h +++ b/include/ccapi_cpp/ccapi_session_options.h @@ -11,27 +11,24 @@ class SessionOptions CCAPI_FINAL { + ", enableCheckSequence = " + ccapi::toString(enableCheckSequence) + ", enableCheckOrderBookChecksum = " + ccapi::toString(enableCheckOrderBookChecksum) + ", enableCheckOrderBookCrossed = " + ccapi::toString(enableCheckOrderBookCrossed) + ", enableCheckPingPong = " - + ccapi::toString(enableCheckPingPong) + ", enableOneConnectionPerSubscription = " - + ccapi::toString(enableOneConnectionPerSubscription) + ", pingIntervalMilliSeconds = " + + ccapi::toString(enableCheckPingPong) + ", pingIntervalMilliSeconds = " + ccapi::toString(pingIntervalMilliSeconds) + ", pongTimeoutMilliSeconds = " + ccapi::toString(pongTimeoutMilliSeconds) + "]"; return output; } - long warnLateEventMaxMilliSeconds{}; - bool enableCheckSequence{}; - bool enableCheckOrderBookChecksum{}; - bool enableCheckOrderBookCrossed{}; - bool enableCheckPingPong{}; - bool enableOneConnectionPerSubscription{}; - bool enableOneIoContextPerExchange{}; + long warnLateEventMaxMilliSeconds{}; // used to print a warning log message if en event arrives late + bool enableCheckSequence{}; // used to check sequence number discontinuity + bool enableCheckOrderBookChecksum{}; // used to check order book checksum + bool enableCheckOrderBookCrossed{true}; // used to check order book cross, usually this should be set to true + bool enableCheckPingPong{}; // used to check ping-pong health for exchange connections long pingIntervalMilliSeconds{10000}; long pongTimeoutMilliSeconds{5000}; - int maxEventQueueSize{0}; + int maxEventQueueSize{0}; // if set to a positive integer, the event queue will throw an exception when overflown bool enableOneHttpConnectionPerRequest{}; int httpMaxNumRetry{3}; int httpMaxNumRedirect{3}; long httpRequestTimeoutMilliSeconds{10000}; - int httpConnectionPoolMaxSize{1}; + int httpConnectionPoolMaxSize{1}; // used to set the maximal number of http connections to be kept in the pool (connections in the pool are idle) }; } /* namespace ccapi */ #endif // INCLUDE_CCAPI_CPP_CCAPI_SESSION_OPTIONS_H_ diff --git a/include/ccapi_cpp/ccapi_util_private.h b/include/ccapi_cpp/ccapi_util_private.h index 9445903f..58d6927c 100644 --- a/include/ccapi_cpp/ccapi_util_private.h +++ b/include/ccapi_cpp/ccapi_util_private.h @@ -83,7 +83,7 @@ class UtilString CCAPI_FINAL { static std::string trim(const std::string& original, const std::string& chars = "\t\n\v\f\r ") { return ltrim(rtrim(original, chars), chars); } - static std::string firstNCharacter(const std::string& str, size_t n) { + static std::string firstNCharacter(const std::string& str, const size_t n) { if (str.length() > n) { return str.substr(0, n) + "..."; } else { @@ -408,6 +408,11 @@ template typename std::enable_if< const T &t) { return t.toString(); } +template typename std::enable_if< + std::is_same().toStringPretty()), std::string>::value, std::string>::type toStringPretty( + const T &t, const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) { + return t.toStringPretty(space, leftToIndent, indentFirstLine); +} template typename std::enable_if< std::is_same())), std::string>::value, std::string>::type toString( const T &t) { @@ -417,6 +422,12 @@ template typename std::enable_if::value const T &t) { return t; } +template typename std::enable_if::value, std::string>::type toStringPretty( + const T &t, const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) { + std::string sl(leftToIndent, ' '); + std::string output = (indentFirstLine ? sl : "") + t; + return output; +} template typename std::enable_if::value, std::string>::type toString( const T &t) { auto timePair = UtilTime::divide(t); @@ -426,10 +437,10 @@ template std::string toString(const std::unordere template std::string toString(const std::set& c); template std::string toString(const std::map& c); template std::string toString(const std::unordered_map& c); -template std::string firstNToString(const std::map& c, size_t n); -template std::string lastNToString(const std::map& c, size_t n); +template std::string firstNToString(const std::map& c, const size_t n); +template std::string lastNToString(const std::map& c, const size_t n); template std::string toString(const std::vector& c); -template std::string firstNToString(const std::vector& c, size_t n); +template std::string firstNToString(const std::vector& c, const size_t n); template std::string toString(const std::unordered_set& c) { std::string output = "["; auto size = c.size(); @@ -474,6 +485,23 @@ template std::string toString(const std::map& c) { output += "}"; return output; } +template std::string toStringPretty(const std::map& c, const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) { + std::string sl(leftToIndent, ' '); + std::string output = (indentFirstLine ? sl : "") + "{\n"; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + output += toStringPretty(elem.first, space, space + leftToIndent, true); + output += " = "; + output += toStringPretty(elem.second, space, space + leftToIndent, false); + if (i < size - 1) { + output += ",\n"; + } + ++i; + } + output += "\n" + sl + "}"; + return output; +} template std::string toString(const std::unordered_map& c) { std::string output = "{"; auto size = c.size(); @@ -490,7 +518,7 @@ template std::string toString(const s output += "}"; return output; } -template std::string firstNToString(const std::map& c, size_t n) { +template std::string firstNToString(const std::map& c, const size_t n) { std::string output = "{"; auto size = c.size(); auto i = 0; @@ -512,7 +540,7 @@ template std::string firstNToString(const std::map output += "}"; return output; } -template std::string lastNToString(const std::map& c, size_t n) { +template std::string lastNToString(const std::map& c, const size_t n) { std::string output = "{"; auto size = c.size(); auto i = 0; @@ -548,7 +576,22 @@ template std::string toString(const std::vector& c) { output += " ]"; return output; } -template std::string firstNToString(const std::vector& c, size_t n) { +template std::string toStringPretty(const std::vector& c, const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) { + std::string sl(leftToIndent, ' '); + std::string output = (indentFirstLine ? sl : "") + "[\n"; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + output += toStringPretty(elem, space, space + leftToIndent, true); + if (i < size - 1) { + output += ",\n"; + } + ++i; + } + output += "\n" + sl + "]"; + return output; +} +template std::string firstNToString(const std::vector& c, const size_t n) { std::string output = "[ "; auto size = c.size(); auto i = 0; @@ -568,6 +611,27 @@ template std::string firstNToString(const std::vector& c, size_t output += " ]"; return output; } +template std::string firstNToStringPretty(const std::vector& c, const size_t n, const int space = 2, const int leftToIndent = 0, const bool indentFirstLine = true) { + std::string sl(leftToIndent, ' '); + std::string output = (indentFirstLine ? sl : "") + "[\n"; + auto size = c.size(); + auto i = 0; + for (const auto& elem : c) { + if (i >= n) { + break; + } + output += toStringPretty(elem, space, space + leftToIndent, true); + if (i < size - 1) { + output += ",\n"; + } + ++i; + } + if (i < size - 1 && i > 0) { + output += "..."; + } + output += "\n" + sl + "]"; + return output; +} template std::map > invertMapMulti(const std::map& c) { std::map > output; for (const auto& elem : c) { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 53404b25..5ce1d030 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -392,11 +392,12 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro } void setupCredential(std::vector nameList) { for (const auto& x : nameList) { - if (!UtilSystem::getEnvAsString(x).empty()) { - this->credentialDefault.insert(std::make_pair(x, UtilSystem::getEnvAsString(x))); - } else if (this->sessionConfigs.getCredential().find(x) != this->sessionConfigs.getCredential().end()) { + if (this->sessionConfigs.getCredential().find(x) != this->sessionConfigs.getCredential().end()) { this->credentialDefault.insert(std::make_pair(x, this->sessionConfigs.getCredential().at(x))); } + else if (!UtilSystem::getEnvAsString(x).empty()) { + this->credentialDefault.insert(std::make_pair(x, UtilSystem::getEnvAsString(x))); + } } } std::string convertOrderStatus(const std::string& status) { From 9deb34512bcedf2ae067e5374f1ce6f92c64b16b Mon Sep 17 00:00:00 2001 From: cryptochassis Date: Tue, 5 Jan 2021 12:25:40 -0800 Subject: [PATCH 18/18] ci: fix cpplint --- README.md | 3 +-- include/ccapi_cpp/ccapi_decimal.h | 2 +- include/ccapi_cpp/ccapi_hmac.h | 2 +- include/ccapi_cpp/ccapi_macro.h | 8 +++---- include/ccapi_cpp/ccapi_session.h | 24 +++++++++---------- .../ccapi_execution_management_service.h | 3 +-- 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 1c9ad92f..b545cdd3 100644 --- a/README.md +++ b/README.md @@ -331,12 +331,11 @@ See section "exchange REST urls" in `include/ccapi_cpp/ccapi_macro.h`. #### Handle events in "immediate" vs. "batching" mode In general there are 2 ways to handle events. -* When a `Session` is instantiated with an `eventHandler` argument, it will handle events in immediate mode. The `processEvent` method in the `eventHandler` will be executed on one of the internal threads in the `eventDispatcher`. A default `EventDispatcher` with 1 internal thread will be created if no `eventDispatcher` argument is provided in `Session` instantiation. To dispatch events to multiple threads, instantiate `EventDispatcher` with `numDispatcherThreads` set to be the desired number. +* When a `Session` is instantiated with an `eventHandler` argument, it will handle events in immediate mode. The `processEvent` method in the `eventHandler` will be executed on one of the internal threads in the `eventDispatcher`. A default `EventDispatcher` with 1 internal thread will be created if no `eventDispatcher` argument is provided in `Session` instantiation. To dispatch events to multiple threads, instantiate `EventDispatcher` with `numDispatcherThreads` set to be the desired number. `EventHandler`s and/or `EventDispatcher`s can be shared among different sessions. Otherwise, different sessions are independent from each other. ``` EventDispatcher eventDispatcher(2); Session session(sessionOptions, sessionConfigs, &eventHandler, &eventDispatcher); ``` -`EventHandler`s and/or `EventDispatcher`s can be shared among different sessions. Otherwise, different sessions are independent from each other. * When a `Session` is instantiated without an `eventHandler` argument, it will handle events in batching mode. The evetns will be batched into an internal `Queue` and can be retrieved by ``` std::vector eventList = session.getEventQueue().purge(); diff --git a/include/ccapi_cpp/ccapi_decimal.h b/include/ccapi_cpp/ccapi_decimal.h index adf016ea..5ce747ed 100644 --- a/include/ccapi_cpp/ccapi_decimal.h +++ b/include/ccapi_cpp/ccapi_decimal.h @@ -101,7 +101,7 @@ class Decimal CCAPI_FINAL { } private: -// {-}bbbb.aaaa + // {-}bbbb.aaaa unsigned long before{}; std::string frac; // -1 means negative sign needed diff --git a/include/ccapi_cpp/ccapi_hmac.h b/include/ccapi_cpp/ccapi_hmac.h index 966ef368..a3911b9b 100644 --- a/include/ccapi_cpp/ccapi_hmac.h +++ b/include/ccapi_cpp/ccapi_hmac.h @@ -2935,7 +2935,7 @@ hmacResult (HMACContext * ctx, uint8_t * digest) #include "ccapi_cpp/ccapi_logger.h" namespace ccapi { class Hmac CCAPI_FINAL { -// https://github.com/Yubico/yubico-c-client/blob/ykclient-2.15/sha384-512.c +// https://github.com/Yubico/yubico-c-client/blob/ykclient-2.15/sha384-512.c public: enum class ShaVersion { UNKNOWN, diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 4201479b..a256a9ea 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -184,7 +184,7 @@ #define CCAPI_CREDENTIAL_DISPLAY_LENGTH 4 #endif -// start: exchange REST urls +// start: exchange REST urls #ifndef CCAPI_COINBASE_URL_REST_BASE #define CCAPI_COINBASE_URL_REST_BASE "https://api.pro.coinbase.com" #endif @@ -215,9 +215,9 @@ #ifndef CCAPI_HUOBI_URL_REST_BASE #define CCAPI_HUOBI_URL_REST_BASE "https://api.huobi.pro" #endif -// end: exchange REST urls +// end: exchange REST urls -// start: exchange API credentials +// start: exchange API credentials #ifndef CCAPI_COINBASE_API_KEY #define CCAPI_COINBASE_API_KEY "COINBASE_API_KEY" #endif @@ -263,7 +263,7 @@ #ifndef CCAPI_HUOBI_API_SECRET #define CCAPI_HUOBI_API_SECRET "HUOBI_API_SECRET" #endif -// end: exchange API credentials +// end: exchange API credentials #ifndef CCAPI_BITMEX_API_RECEIVE_WINDOW_SECONDS #define CCAPI_BITMEX_API_RECEIVE_WINDOW_SECONDS 5 diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index f14d06ba..34db748b 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -42,15 +42,15 @@ // start: enable exchanges for execution management #ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT -//#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE -//#include "ccapi_cpp/service/ccapi_execution_management_service_coinbase.h" -//#endif -//#ifdef CCAPI_ENABLE_EXCHANGE_GEMINI -//#include "ccapi_cpp/service/ccapi_execution_management_service_gemini.h" -//#endif -//#ifdef CCAPI_ENABLE_EXCHANGE_BITMEX -//#include "ccapi_cpp/service/ccapi_execution_management_service_bitmex.h" -//#endif +// #ifdef CCAPI_ENABLE_EXCHANGE_COINBASE +// #include "ccapi_cpp/service/ccapi_execution_management_service_coinbase.h" +// #endif +// #ifdef CCAPI_ENABLE_EXCHANGE_GEMINI +// #include "ccapi_cpp/service/ccapi_execution_management_service_gemini.h" +// #endif +// #ifdef CCAPI_ENABLE_EXCHANGE_BITMEX +// #include "ccapi_cpp/service/ccapi_execution_management_service_bitmex.h" +// #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US #include "ccapi_cpp/service/ccapi_execution_management_service_binance_us.h" #endif @@ -60,9 +60,9 @@ #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_FUTURES #include "ccapi_cpp/service/ccapi_execution_management_service_binance_futures.h" #endif -//#ifdef CCAPI_ENABLE_EXCHANGE_HUOBI -//#include "ccapi_cpp/service/ccapi_execution_management_service_huobi.h" -//#endif +// #ifdef CCAPI_ENABLE_EXCHANGE_HUOBI +// #include "ccapi_cpp/service/ccapi_execution_management_service_huobi.h" +// #endif #endif // end: enable exchanges for execution management diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 5ce1d030..32f343a7 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -394,8 +394,7 @@ class ExecutionManagementService : public Service, public std::enable_shared_fro for (const auto& x : nameList) { if (this->sessionConfigs.getCredential().find(x) != this->sessionConfigs.getCredential().end()) { this->credentialDefault.insert(std::make_pair(x, this->sessionConfigs.getCredential().at(x))); - } - else if (!UtilSystem::getEnvAsString(x).empty()) { + } else if (!UtilSystem::getEnvAsString(x).empty()) { this->credentialDefault.insert(std::make_pair(x, UtilSystem::getEnvAsString(x))); } }