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>
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
#include "serialization/ISerializer.h"
|
|
|
|
#include "serialization/SerializationTools.h"
|
|
|
|
#include <Common/JsonValue.h>
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
void serialize(ISerializer& s) {
|
|
|
|
s(code, "code");
|
|
|
|
s(message, "message");
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
int code;
|
|
|
|
std::string message;
|
|
|
|
};
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
typedef boost::optional<Common::JsonValue> OptionalId;
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
class JsonRpcRequest {
|
|
|
|
public:
|
2015-07-15 12:23:00 +00:00
|
|
|
|
|
|
|
JsonRpcRequest() : psReq(Common::JsonValue::OBJECT) {}
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
bool parseRequest(const std::string& requestBody) {
|
2015-07-15 12:23:00 +00:00
|
|
|
try {
|
|
|
|
psReq = Common::JsonValue::fromString(requestBody);
|
|
|
|
} catch (std::exception&) {
|
2015-05-27 12:08:46 +00:00
|
|
|
throw JsonRpcError(errParseError);
|
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
if (!psReq.contains("method")) {
|
|
|
|
throw JsonRpcError(errInvalidRequest);
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
method = psReq("method").getString();
|
|
|
|
|
|
|
|
if (psReq.contains("id")) {
|
|
|
|
id = psReq("id");
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool loadParams(T& v) const {
|
2015-07-15 12:23:00 +00:00
|
|
|
loadFromJsonValue(v, psReq.contains("params") ?
|
|
|
|
psReq("params") : Common::JsonValue(Common::JsonValue::NIL));
|
|
|
|
return true;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool setParams(const T& v) {
|
2015-07-15 12:23:00 +00:00
|
|
|
psReq.set("params", storeToJsonValue(v));
|
|
|
|
return true;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::string& getMethod() const {
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setMethod(const std::string& m) {
|
|
|
|
method = m;
|
|
|
|
}
|
|
|
|
|
|
|
|
const OptionalId& getId() const {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getBody() {
|
2015-07-15 12:23:00 +00:00
|
|
|
psReq.set("jsonrpc", std::string("2.0"));
|
|
|
|
psReq.set("method", method);
|
|
|
|
return psReq.toString();
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
Common::JsonValue psReq;
|
2015-05-27 12:08:46 +00:00
|
|
|
OptionalId id;
|
|
|
|
std::string method;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class JsonRpcResponse {
|
|
|
|
public:
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
JsonRpcResponse() : psResp(Common::JsonValue::OBJECT) {}
|
|
|
|
|
|
|
|
void parse(const std::string& responseBody) {
|
|
|
|
try {
|
|
|
|
psResp = Common::JsonValue::fromString(responseBody);
|
|
|
|
} catch (std::exception&) {
|
2015-05-27 12:08:46 +00:00
|
|
|
throw JsonRpcError(errParseError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setId(const OptionalId& id) {
|
|
|
|
if (id.is_initialized()) {
|
2015-07-15 12:23:00 +00:00
|
|
|
psResp.insert("id", id.get());
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void setError(const JsonRpcError& err) {
|
2015-07-15 12:23:00 +00:00
|
|
|
psResp.set("error", storeToJsonValue(err));
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
bool getError(JsonRpcError& err) const {
|
|
|
|
if (!psResp.contains("error")) {
|
2015-05-27 12:08:46 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-07-15 12:23:00 +00:00
|
|
|
loadFromJsonValue(err, psResp("error"));
|
2015-05-27 12:08:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getBody() {
|
2015-07-15 12:23:00 +00:00
|
|
|
psResp.set("jsonrpc", std::string("2.0"));
|
|
|
|
return psResp.toString();
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool setResult(const T& v) {
|
2015-07-15 12:23:00 +00:00
|
|
|
psResp.set("result", storeToJsonValue(v));
|
|
|
|
return true;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
bool getResult(T& v) const {
|
2015-07-15 12:23:00 +00:00
|
|
|
if (!psResp.contains("result")) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
loadFromJsonValue(v, psResp("result"));
|
|
|
|
return true;
|
2015-05-27 12:08:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-07-15 12:23:00 +00:00
|
|
|
Common::JsonValue psResp;
|
2015-05-27 12:08:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|