Browse Source

Merge pull request #1512 from jgarzik/json-batch

Support JSON-RPC 2.0 request batches
tags/v0.15.1
Jeff Garzik 9 years ago
parent
commit
c729dbb6d2
1 changed files with 101 additions and 32 deletions
  1. 101
    32
      src/bitcoinrpc.cpp

+ 101
- 32
src/bitcoinrpc.cpp View File

@@ -2552,7 +2552,7 @@ string JSONRPCRequest(const string& strMethod, const Array& params, const Value&
return write_string(Value(request), false) + "\n";
}

string JSONRPCReply(const Value& result, const Value& error, const Value& id)
Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
{
Object reply;
if (error.type() != null_type)
@@ -2561,6 +2561,12 @@ string JSONRPCReply(const Value& result, const Value& error, const Value& id)
reply.push_back(Pair("result", result));
reply.push_back(Pair("error", error));
reply.push_back(Pair("id", id));
return reply;
}

string JSONRPCReply(const Value& result, const Value& error, const Value& id)
{
Object reply = JSONRPCReplyObj(result, error, id);
return write_string(Value(reply), false) + "\n";
}

@@ -2905,6 +2911,80 @@ void ThreadRPCServer2(void* parg)
StopRequests();
}

class JSONRequest
{
public:
Value id;
string strMethod;
Array params;

JSONRequest() { id = Value::null; }
void parse(const Value& valRequest);
};

void JSONRequest::parse(const Value& valRequest)
{
// Parse request
if (valRequest.type() != obj_type)
throw JSONRPCError(-32600, "Invalid Request object");
const Object& request = valRequest.get_obj();

// Parse id now so errors from here on will have the id
id = find_value(request, "id");

// Parse method
Value valMethod = find_value(request, "method");
if (valMethod.type() == null_type)
throw JSONRPCError(-32600, "Missing method");
if (valMethod.type() != str_type)
throw JSONRPCError(-32600, "Method must be a string");
strMethod = valMethod.get_str();
if (strMethod != "getwork" && strMethod != "getmemorypool")
printf("ThreadRPCServer method=%s\n", strMethod.c_str());

// Parse params
Value valParams = find_value(request, "params");
if (valParams.type() == array_type)
params = valParams.get_array();
else if (valParams.type() == null_type)
params = Array();
else
throw JSONRPCError(-32600, "Params must be an array");
}

static Object JSONRPCExecOne(const Value& req)
{
Object rpc_result;

JSONRequest jreq;
try {
jreq.parse(req);

Value result = tableRPC.execute(jreq.strMethod, jreq.params);
rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
}
catch (Object& objError)
{
rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
}
catch (std::exception& e)
{
rpc_result = JSONRPCReplyObj(Value::null,
JSONRPCError(-32700, e.what()), jreq.id);
}

return rpc_result;
}

static string JSONRPCExecBatch(const Array& vReq)
{
Array ret;
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
ret.push_back(JSONRPCExecOne(vReq[reqIdx]));

return write_string(Value(ret), false) + "\n";
}

static CCriticalSection cs_THREAD_RPCHANDLER;

void ThreadRPCServer3(void* parg)
@@ -2954,52 +3034,41 @@ void ThreadRPCServer3(void* parg)
if (mapHeaders["connection"] == "close")
fRun = false;

Value id = Value::null;
JSONRequest jreq;
try
{
// Parse request
Value valRequest;
if (!read_string(strRequest, valRequest) || valRequest.type() != obj_type)
if (!read_string(strRequest, valRequest))
throw JSONRPCError(-32700, "Parse error");
const Object& request = valRequest.get_obj();

// Parse id now so errors from here on will have the id
id = find_value(request, "id");

// Parse method
Value valMethod = find_value(request, "method");
if (valMethod.type() == null_type)
throw JSONRPCError(-32600, "Missing method");
if (valMethod.type() != str_type)
throw JSONRPCError(-32600, "Method must be a string");
string strMethod = valMethod.get_str();
if (strMethod != "getwork" && strMethod != "getmemorypool")
printf("ThreadRPCServer method=%s\n", strMethod.c_str());

// Parse params
Value valParams = find_value(request, "params");
Array params;
if (valParams.type() == array_type)
params = valParams.get_array();
else if (valParams.type() == null_type)
params = Array();
else
throw JSONRPCError(-32600, "Params must be an array");

Value result = tableRPC.execute(strMethod, params);
string strReply;

// Send reply
string strReply = JSONRPCReply(result, Value::null, id);
// singleton request
if (valRequest.type() == obj_type) {
jreq.parse(valRequest);

Value result = tableRPC.execute(jreq.strMethod, jreq.params);

// Send reply
strReply = JSONRPCReply(result, Value::null, jreq.id);

// array of requests
} else if (valRequest.type() == array_type)
strReply = JSONRPCExecBatch(valRequest.get_array());
else
throw JSONRPCError(-32700, "Top-level object parse error");
conn->stream() << HTTPReply(200, strReply, fRun) << std::flush;
}
catch (Object& objError)
{
ErrorReply(conn->stream(), objError, id);
ErrorReply(conn->stream(), objError, jreq.id);
break;
}
catch (std::exception& e)
{
ErrorReply(conn->stream(), JSONRPCError(-32700, e.what()), id);
ErrorReply(conn->stream(), JSONRPCError(-32700, e.what()), jreq.id);
break;
}
}

Loading…
Cancel
Save