rpc: Allow named and positional arguments to be used together

It's nice to be able to use named options and positional arguments together.

Most shell tools accept both, and python functions combine options and
arguments allowing them to be passed with even more flexibility. This change
adds support for python's approach so as a motivating example:

    bitcoin-cli -named createwallet wallet_name=mywallet load_on_startup=1

Can be shortened to:

    bitcoin-cli -named createwallet mywallet load_on_startup=1

JSON-RPC standard doesn't have a convention for passing named and positional
parameters together, so this implementation makes one up and interprets any
unused "args" named parameter as a positional parameter array.
This commit is contained in:
Ryan Ofsky
2020-08-18 11:43:42 -04:00
parent 50422b770a
commit d8b12a75db
9 changed files with 147 additions and 5 deletions

View File

@@ -277,11 +277,13 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
UniValue params(UniValue::VOBJ);
UniValue positional_args{UniValue::VARR};
for (const std::string &s: strParams) {
size_t pos = s.find('=');
if (pos == std::string::npos) {
throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)"));
positional_args.push_back(rpcCvtTable.convert(strMethod, positional_args.size()) ? ParseNonRFCJSONValue(s) : s);
continue;
}
std::string name = s.substr(0, pos);
@@ -296,5 +298,9 @@ UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<s
}
}
if (!positional_args.empty()) {
params.pushKV("args", positional_args);
}
return params;
}