danicoin/src/rpc/JsonRpc.h

224 lines
5.6 KiB
C
Raw Normal View History

2015-05-27 12:08:46 +00:00
// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers
//
// This file is part of Bytecoin.
//
// Bytecoin is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Bytecoin is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <boost/optional.hpp>
#include <boost/foreach.hpp>
#include <functional>
#include "misc_log_ex.h"
#include "storages/portable_storage_template_helper.h"
#include "serialization/enableable.h"
#include "serialization/keyvalue_serialization_overloads.h"
namespace CryptoNote {
class HttpClient;
namespace JsonRpc {
const int errParseError = -32700;
const int errInvalidRequest = -32600;
const int errMethodNotFound = -32601;
const int errInvalidParams = -32602;
const int errInternalError = -32603;
class JsonRpcError: public std::exception {
public:
JsonRpcError();
JsonRpcError(int c);
JsonRpcError(int c, const std::string& msg);
#ifdef _MSC_VER
virtual const char* what() const override {
#else
virtual const char* what() const noexcept override {
#endif
return message.c_str();
}
int code;
std::string message;
};
typedef boost::optional<epee::serialization::storage_entry> OptionalId;
class JsonRpcRequest {
public:
bool parseRequest(const std::string& requestBody) {
if (!psReq.load_from_json(requestBody)) {
throw JsonRpcError(errParseError);
}
OptionalId::value_type idValue;
if (psReq.get_value("id", idValue, nullptr)) {
id = idValue;
}
if (!psReq.get_value("method", method, nullptr)) {
throw JsonRpcError(errInvalidRequest);
}
return true;
}
template <typename T>
bool loadParams(T& v) const {
return epee::serialization::kv_unserialize(v,
const_cast<epee::serialization::portable_storage&>(psReq), nullptr, "params");
}
template <typename T>
bool setParams(const T& v) {
return epee::serialization::kv_serialize(v, psReq, nullptr, "params");
}
const std::string& getMethod() const {
return method;
}
void setMethod(const std::string& m) {
method = m;
}
const OptionalId& getId() const {
return id;
}
std::string getBody() {
std::string reqBody;
psReq.set_value("jsonrpc", std::string("2.0"), nullptr);
psReq.set_value("method", method, nullptr);
psReq.dump_as_json(reqBody);
return reqBody;
}
private:
epee::serialization::portable_storage psReq;
OptionalId id;
std::string method;
};
class JsonRpcResponse {
public:
void parse(const std::string& resonseBody) {
if (!psResp.load_from_json(resonseBody)) {
throw JsonRpcError(errParseError);
}
}
void setId(const OptionalId& id) {
if (id.is_initialized()) {
psResp.set_value("id", id.get(), nullptr);
}
}
void setError(const JsonRpcError& err) {
auto errorSection = psResp.open_section("error", nullptr, true);
psResp.set_value("code", err.code, errorSection);
psResp.set_value("message", err.message, errorSection);
}
bool getError(JsonRpcError& err) {
auto errorSection = psResp.open_section("error", nullptr, false);
if (!errorSection) {
return false;
}
psResp.get_value("code", err.code, errorSection);
psResp.get_value("message", err.message, errorSection);
return true;
}
std::string getBody() {
std::string responseBody;
psResp.set_value("jsonrpc", std::string("2.0"), nullptr);
psResp.dump_as_json(responseBody);
return responseBody;
}
template <typename T>
bool setResult(const T& v) {
return epee::serialization::kv_serialize(v, psResp, nullptr, "result");
}
template <typename T>
bool getResult(T& v) const {
return epee::serialization::kv_unserialize(v,
const_cast<epee::serialization::portable_storage&>(psResp), nullptr, "result");
}
private:
epee::serialization::portable_storage psResp;
};
void invokeJsonRpcCommand(HttpClient& httpClient, JsonRpcRequest& req, JsonRpcResponse& res);
template <typename Request, typename Response>
void invokeJsonRpcCommand(HttpClient& httpClient, const std::string& method, const Request& req, Response& res) {
JsonRpcRequest jsReq;
JsonRpcResponse jsRes;
jsReq.setMethod(method);
jsReq.setParams(req);
invokeJsonRpcCommand(httpClient, jsReq, jsRes);
jsRes.getResult(res);
}
template <typename Request, typename Response, typename Handler>
bool invokeMethod(const JsonRpcRequest& jsReq, JsonRpcResponse& jsRes, Handler handler) {
Request req;
Response res;
if (!jsReq.loadParams(req)) {
throw JsonRpcError(JsonRpc::errInvalidParams);
}
bool result = handler(req, res);
if (result) {
if (!jsRes.setResult(res)) {
throw JsonRpcError(JsonRpc::errInternalError);
}
}
return result;
}
typedef std::function<bool(void*, const JsonRpcRequest& req, JsonRpcResponse& res)> JsonMemberMethod;
template <typename Class, typename Params, typename Result>
JsonMemberMethod makeMemberMethod(bool (Class::*handler)(const Params&, Result&)) {
return [handler](void* obj, const JsonRpcRequest& req, JsonRpcResponse& res) {
return JsonRpc::invokeMethod<Params, Result>(
req, res, std::bind(handler, static_cast<Class*>(obj), std::placeholders::_1, std::placeholders::_2));
};
}
}
}