#pragma once #include #include #include "configuration.hpp" #include "curl.hpp" #include "json.hpp" #include "sign.hpp" #include namespace rublon { class CoreHandlerError { public: enum ErrorClass { BadSigature, CoreException, ConnectionError, BrokenData }; CoreHandlerError(ErrorClass e) : errorClass{e} {} CoreHandlerError(ErrorClass e, std::string r) : errorClass{e}, reson{std::move(r)} {} ErrorClass errorClass; std::string reson; }; template < typename Impl > class CoreHandlerInterface { public: tl::expected< rublon::Document, CoreHandlerError > request(std::string_view path, const rublon::Document & body) const { rublon::debugLog("[TMP] request",__PRETTY_FUNCTION__); return static_cast< const Impl * >(this)->request(path, body); } }; template < typename HttpHandler = CURL > class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > { std::string secretKey; std::string url; std::pmr::string xRublonSignature(std::pmr::memory_resource & mr, std::string_view body) const { return {signData(body, secretKey.c_str()).data(), &mr}; } void signRequest(std::pmr::monotonic_buffer_resource & mr, Request & request) const { rublon::debugLog("[TMP]",__PRETTY_FUNCTION__); request.headers["X-Rublon-Signature"] = xRublonSignature(mr, request.body); } bool responseSigned(const Response & response) const { rublon::debugLog("[TMP]",__PRETTY_FUNCTION__); const auto & xRubResp = response.headers.at("x-rublon-signature"); const auto & sign = signData(response.body, secretKey); return xRubResp == sign.data(); } protected: HttpHandler http{}; public: void debugLog(const char *, const char *) {} CoreHandler(const rublon::Configuration & config) : secretKey{config.parameters.secretKey}, url{config.parameters.apiServer} {} tl::expected< rublon::Document, CoreHandlerError > request(std::string_view path, const rublon::Document & body) const { rublon::debugLog("[TMP] request",__PRETTY_FUNCTION__); std::byte _buffer[16 * 1024]; std::pmr::monotonic_buffer_resource mr{_buffer, sizeof(_buffer)}; rublon::RapidJSONPMRAlloc alloc{&mr}; rublon::StringBuffer jsonStr{&alloc}; rublon::Writer writer{jsonStr, &alloc}; body.Accept(writer); Request request; request.headers["Content-Type"] = "application/json"; request.headers["Accept"] = "application/json"; request.body = jsonStr.GetString(); rublon::debugLog("[TMP] request", "sign"); signRequest(mr, request); // std::pmr::string uri{url + path.data(), &mr}; // rublon::debugLog("[TMP] send", request.body.c_str()); // auto response = http.request(uri, request); // if(not response.has_value()) { return tl::unexpected{CoreHandlerError::ConnectionError}; // } // if(not responseSigned(*response)) { // return tl::unexpected{CoreHandlerError::BadSigature}; // } // rublon::Document resp{&alloc}; // resp.Parse(response->body.c_str()); // if(resp.HasParseError() or not resp.HasMember("result")) { // return tl::unexpected{CoreHandlerError::BrokenData}; // } // if(resp["result"].HasMember("exception")) { // return tl::unexpected{CoreHandlerError{CoreHandlerError::CoreException, resp["result"]["exception"].GetString()}}; // } // return resp; } }; } // namespace rublon