diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -139,10 +139,13 @@ random.h \ reverselock.h \ rpc/blockchain.h \ + rpc/command.h \ + rpc/commandname.h \ rpc/client.h \ rpc/jsonrpcrequest.h \ rpc/mining.h \ rpc/misc.h \ + rpc/parameter.h \ rpc/protocol.h \ rpc/server.h \ rpc/tojson.h \ diff --git a/src/rpc/command.h b/src/rpc/command.h new file mode 100644 --- /dev/null +++ b/src/rpc/command.h @@ -0,0 +1,81 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPC_COMMAND_H +#define BITCOIN_RPC_COMMAND_H + +#include "rpc/commandname.h" +#include "rpc/jsonrpcrequest.h" +#include "rpc/parameter.h" + +#include + +#include +#include +#include + +#include + +/** + * Abstract class to define RPC commands. + * Subclasses of RPCCommand will be instantiated on each RPC call. + */ +class RPCCommand : public boost::noncopyable { +private: + RPCCommandName name; + std::vector> params; + /** + * Subclasses of RPCCommand store parameter values as private member + * variables. + */ + +public: + RPCCommand(const RPCCommandName &nameIn, + std::vector> ¶msIn) + : name(nameIn) { + for (std::unique_ptr ¶mIn : paramsIn) { + params.push_back(std::move(paramIn)); + } + } + + RPCCommandName GetName() const { return name; } + + const std::vector> & + GetParameters() const { + return params; + } + + /** + * Validates incoming parameter values and saves them for future execution. + * Returns false if any of the parameters did not validate. + */ + bool ValidateAndSaveParameters(const JSONRPCRequest &jsonRequest) { + for (std::unique_ptr ¶m : params) { + // TODO maybe passing in the whole jsonRequest to Validate() and + // letting it decide which param names to examine is better? + UniValue input = jsonRequest.params[param->GetName()]; + if (!param->Validate(input)) { + return false; + } else { + SaveParameterValue(*(param.get())); + } + } + return true; + } + + /** + * Saves the value of a given parameter into it's respective private member + * variable. Typically, implementations will build a switch-statement + * using the parameter names as cases. + */ + virtual void SaveParameterValue(RPCParameterBase ¶m) = 0; + + /** + * Execute() defines the behavior of the command and must be defined for + * all commands. + */ + virtual UniValue Execute(const JSONRPCRequest &jsonRequest) const = 0; +}; + +#endif // BITCOIN_RPC_COMMAND_H diff --git a/src/rpc/commandfactory.h b/src/rpc/commandfactory.h new file mode 100644 --- /dev/null +++ b/src/rpc/commandfactory.h @@ -0,0 +1,74 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPC_COMMAND_FACTORY_H +#define BITCOIN_RPC_COMMAND_FACTORY_H + +#include "rpc/commandname.h" +#include "rpc/jsonrpcrequest.h" +#include "rpc/parameter.h" + +#include + +#include +#include + +#include + +/** + * Abstract class to define RPC command factories. + * Each factory is a singleton that is instantiated with the necessary + * dependencies at application init time. + */ +class RPCCommandFactory : public boost::noncopyable { +private: + /** + * Subclasses of RPCCommandFactory should store dependencies as private + * member variables. + */ + +public: + RPCCommandFactory() {} + + virtual ~RPCCommandFactory() {} + + /** + * Returns the command name. + */ + virtual RPCCommandName GetName() const = 0; + + /** + * Returns a new list of parameter definitions for the RPC command that is + * generated by this factory. + */ + virtual std::vector> + MakeParameters() const = 0; + + /** + * Instantiates a new RPCCommand with the parameter values received via + * jsonRequest, if they are valid. If the parameters are not valid, + * MakeCommand should return nullptr. + */ + std::unique_ptr + MakeCommand(const JSONRPCRequest &jsonRequest) const { + std::unique_ptr command = NewCommand(jsonRequest); + if (command) { + if (!command->ValidateAndSaveParameters(jsonRequest)) { + return nullptr; + } + } + + return command; + } + + /** + * Instantiates a new RPCCommand to be used for parsing and validation of a + * particular request. + * Returns nullptr in case of any errors. + */ + virtual std::unique_ptr + NewCommand(const JSONRPCRequest &jsonRequest) const = 0; +}; + +#endif // BITCOIN_RPC_COMMAND_FACTORY_H diff --git a/src/rpc/commandname.h b/src/rpc/commandname.h new file mode 100644 --- /dev/null +++ b/src/rpc/commandname.h @@ -0,0 +1,22 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPC_COMMAND_NAME_H +#define BITCOIN_RPC_COMMAND_NAME_H + +#include + +#include + +class RPCCommandName { +private: + std::string name; + +public: + RPCCommandName(std::string nameIn) : name(nameIn){}; + + std::string GetName() const { return name; } +}; + +#endif // BITCOIN_RPC_COMMAND_NAME_H diff --git a/src/rpc/parameter.h b/src/rpc/parameter.h new file mode 100644 --- /dev/null +++ b/src/rpc/parameter.h @@ -0,0 +1,54 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_RPC_PARAMETER_H +#define BITCOIN_RPC_PARAMETER_H + +#include + +#include + +class RPCParameterBase { +private: + std::string name; + std::string description; + +public: + RPCParameterBase(std::string nameIn, std::string descriptionIn) + : name(nameIn), description(descriptionIn){}; + + virtual ~RPCParameterBase() = default; + + std::string GetName() const { return name; } + + std::string GetDescription() const { return description; } + + /** + * Validate()'s input for this parameter. For example, this function + * could be defined to only accept a certain range for integer values. + * Validate() should return true if the input is valid, false otherwise. + */ + virtual bool Validate(UniValue input) const = 0; +}; + +/** + * Abstract class to define RPC parameters. + * Any class derived from RPCParameter may be used by multiple RPCCommands. + */ +template class RPCParameter : public RPCParameterBase { +private: + ParameterType value; + +public: + RPCParameter(std::string nameIn, std::string descriptionIn) + : RPCParameterBase(nameIn, descriptionIn), value(nullptr){}; + + /** + * GetValue() returns the value validated by Validate(). + * Returns nullptr if Validate() was never called or returned false. + */ + virtual ParameterType GetValue() const = 0; +}; + +#endif // BITCOIN_RPC_PARAMETER_H