98 lines
3.2 KiB
C++
98 lines
3.2 KiB
C++
#pragma once
|
|
|
|
#include <memory_resource>
|
|
#include <string>
|
|
|
|
#include "configuration.hpp"
|
|
#include "curl.hpp"
|
|
#include "json.hpp"
|
|
#include "sign.hpp"
|
|
|
|
#include <tl/expected.hpp>
|
|
|
|
#include <rublon/core_handler_interface.hpp>
|
|
|
|
namespace rublon {
|
|
|
|
|
|
|
|
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 {
|
|
request.headers["X-Rublon-Signature"] = xRublonSignature(mr, request.body);
|
|
}
|
|
|
|
bool responseSigned(const Response & response) const {
|
|
const auto & xRubResp = response.headers.at("x-rublon-signature");
|
|
const auto & sign = signData(response.body, secretKey);
|
|
const bool signatureMatch = xRubResp == sign.data();
|
|
if(not signatureMatch)
|
|
log(LogLevel::Error, "Signature mismatch %s != %s ", xRubResp.c_str(), sign.data());
|
|
return signatureMatch;
|
|
}
|
|
|
|
protected:
|
|
HttpHandler http{};
|
|
|
|
public:
|
|
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 {
|
|
log(Debug, "CoreHandler::Request prepare");
|
|
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();
|
|
|
|
signRequest(mr, request);
|
|
std::pmr::string uri{url + path.data(), &mr};
|
|
|
|
auto response = http.request(uri, request);
|
|
|
|
if(not response.has_value()) {
|
|
log(LogLevel::Error, "CoreHandlerError::ConnectionError");
|
|
return tl::unexpected{CoreHandlerError::ConnectionError};
|
|
}
|
|
|
|
if(not responseSigned(*response)) {
|
|
log(LogLevel::Error, "CoreHandlerError::BadSigature");
|
|
return tl::unexpected{CoreHandlerError::BadSigature};
|
|
}
|
|
|
|
rublon::Document resp{&alloc};
|
|
resp.Parse(response->body.c_str());
|
|
|
|
if(resp.HasParseError() or not resp.HasMember("result")) {
|
|
log(LogLevel::Error, "rublon Core responded with broken data");
|
|
return tl::unexpected{CoreHandlerError::BrokenData};
|
|
}
|
|
|
|
if(resp["result"].HasMember("exception")) {
|
|
const auto & exception = resp["result"]["exception"].GetString();
|
|
log(LogLevel::Error, "rublon Core exception %s", exception);
|
|
return tl::unexpected{CoreHandlerError{CoreHandlerError::CoreException, exception}};
|
|
}
|
|
|
|
return resp;
|
|
}
|
|
};
|
|
|
|
} // namespace rublon
|