1 // Aleth: Ethereum C++ client, tools and libraries. 2 // Copyright 2015-2019 Aleth Authors. 3 // Licensed under the GNU General Public License, Version 3. 4 5 #pragma once 6 7 #include <map> 8 #include <memory> 9 #include <string> 10 #include <tuple> 11 #include <vector> 12 13 #include <jsonrpccpp/common/exception.h> 14 #include <jsonrpccpp/common/procedure.h> 15 #include <jsonrpccpp/server/abstractserverconnector.h> 16 #include <jsonrpccpp/server/iprocedureinvokationhandler.h> 17 #include <jsonrpccpp/server/requesthandlerfactory.h> 18 19 template <class I> using AbstractMethodPointer = void(I::*)(Json::Value const& _parameter, Json::Value& _result); 20 template <class I> using AbstractNotificationPointer = void(I::*)(Json::Value const& _parameter); 21 22 template <class I> 23 class ServerInterface 24 { 25 public: 26 using MethodPointer = AbstractMethodPointer<I>; 27 using NotificationPointer = AbstractNotificationPointer<I>; 28 29 using MethodBinding = std::tuple<jsonrpc::Procedure, AbstractMethodPointer<I>>; 30 using NotificationBinding = std::tuple<jsonrpc::Procedure, AbstractNotificationPointer<I>>; 31 using Methods = std::vector<MethodBinding>; 32 using Notifications = std::vector<NotificationBinding>; 33 struct RPCModule { std::string name; std::string version; }; 34 using RPCModules = std::vector<RPCModule>; 35 ~ServerInterface()36 virtual ~ServerInterface() {} methods()37 Methods const& methods() const { return m_methods; } notifications()38 Notifications const& notifications() const { return m_notifications; } 39 /// @returns which interfaces (eth, admin, db, ...) this class implements in which version. 40 virtual RPCModules implementedModules() const = 0; 41 42 protected: bindAndAddMethod(jsonrpc::Procedure const & _proc,MethodPointer _pointer)43 void bindAndAddMethod(jsonrpc::Procedure const& _proc, MethodPointer _pointer) { m_methods.emplace_back(_proc, _pointer); } bindAndAddNotification(jsonrpc::Procedure const & _proc,NotificationPointer _pointer)44 void bindAndAddNotification(jsonrpc::Procedure const& _proc, NotificationPointer _pointer) { m_notifications.emplace_back(_proc, _pointer); } 45 46 private: 47 Methods m_methods; 48 Notifications m_notifications; 49 }; 50 51 template <class... Is> 52 class ModularServer: public jsonrpc::IProcedureInvokationHandler 53 { 54 public: ModularServer()55 ModularServer() 56 : m_handler(jsonrpc::RequestHandlerFactory::createProtocolHandler(jsonrpc::JSONRPC_SERVER_V2, *this)) 57 { 58 m_handler->AddProcedure(jsonrpc::Procedure("rpc_modules", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, NULL)); 59 m_implementedModules = Json::objectValue; 60 } modules(const Json::Value & request,Json::Value & response)61 inline virtual void modules(const Json::Value &request, Json::Value &response) 62 { 63 (void)request; 64 response = m_implementedModules; 65 } 66 ~ModularServer()67 virtual ~ModularServer() { StopListening(); } 68 StartListening()69 virtual void StartListening() 70 { 71 for (auto const& connector: m_connectors) 72 connector->StartListening(); 73 } 74 StopListening()75 virtual void StopListening() 76 { 77 for (auto const& connector: m_connectors) 78 connector->StopListening(); 79 } 80 HandleMethodCall(jsonrpc::Procedure & _proc,Json::Value const & _input,Json::Value & _output)81 virtual void HandleMethodCall(jsonrpc::Procedure& _proc, Json::Value const& _input, Json::Value& _output) override 82 { 83 if (_proc.GetProcedureName() == "rpc_modules") 84 modules(_input, _output); 85 } 86 HandleNotificationCall(jsonrpc::Procedure & _proc,Json::Value const & _input)87 virtual void HandleNotificationCall(jsonrpc::Procedure& _proc, Json::Value const& _input) override 88 { 89 (void)_proc; 90 (void)_input; 91 } 92 93 /// server takes ownership of the connector addConnector(jsonrpc::AbstractServerConnector * _connector)94 unsigned addConnector(jsonrpc::AbstractServerConnector* _connector) 95 { 96 m_connectors.emplace_back(_connector); 97 _connector->SetHandler(m_handler.get()); 98 return m_connectors.size() - 1; 99 } 100 connector(unsigned _i)101 jsonrpc::AbstractServerConnector* connector(unsigned _i) const 102 { 103 return m_connectors.at(_i).get(); 104 } 105 106 protected: 107 std::vector<std::unique_ptr<jsonrpc::AbstractServerConnector>> m_connectors; 108 std::unique_ptr<jsonrpc::IProtocolHandler> m_handler; 109 /// Mapping for implemented modules, to be filled by subclasses during construction. 110 Json::Value m_implementedModules; 111 }; 112 113 template <class I, class... Is> 114 class ModularServer<I, Is...> : public ModularServer<Is...> 115 { 116 public: 117 using MethodPointer = AbstractMethodPointer<I>; 118 using NotificationPointer = AbstractNotificationPointer<I>; 119 120 ModularServer<I, Is...>(I* _i, Is*... _is): ModularServer<Is...>(_is...), m_interface(_i) 121 { 122 if (!m_interface) 123 return; 124 for (auto const& method: m_interface->methods()) 125 { 126 m_methods[std::get<0>(method).GetProcedureName()] = std::get<1>(method); 127 this->m_handler->AddProcedure(std::get<0>(method)); 128 } 129 130 for (auto const& notification: m_interface->notifications()) 131 { 132 m_notifications[std::get<0>(notification).GetProcedureName()] = std::get<1>(notification); 133 this->m_handler->AddProcedure(std::get<0>(notification)); 134 } 135 // Store module with version. 136 for (auto const& module: m_interface->implementedModules()) 137 this->m_implementedModules[module.name] = module.version; 138 } 139 HandleMethodCall(jsonrpc::Procedure & _proc,Json::Value const & _input,Json::Value & _output)140 virtual void HandleMethodCall(jsonrpc::Procedure& _proc, Json::Value const& _input, Json::Value& _output) override 141 { 142 auto pointer = m_methods.find(_proc.GetProcedureName()); 143 if (pointer != m_methods.end()) 144 { 145 try 146 { 147 (m_interface.get()->*(pointer->second))(_input, _output); 148 } 149 catch (Json::Exception const& ex) 150 { 151 throw jsonrpc::JsonRpcException( 152 jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS, ex.what()); 153 } 154 } 155 else 156 ModularServer<Is...>::HandleMethodCall(_proc, _input, _output); 157 } 158 HandleNotificationCall(jsonrpc::Procedure & _proc,Json::Value const & _input)159 virtual void HandleNotificationCall( 160 jsonrpc::Procedure& _proc, Json::Value const& _input) override 161 { 162 auto pointer = m_notifications.find(_proc.GetProcedureName()); 163 if (pointer != m_notifications.end()) 164 { 165 try 166 { 167 (m_interface.get()->*(pointer->second))(_input); 168 } 169 catch (Json::Exception const& ex) 170 { 171 throw jsonrpc::JsonRpcException( 172 jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS, ex.what()); 173 } 174 } 175 else 176 ModularServer<Is...>::HandleNotificationCall(_proc, _input); 177 } 178 179 private: 180 std::unique_ptr<I> m_interface; 181 std::map<std::string, MethodPointer> m_methods; 182 std::map<std::string, NotificationPointer> m_notifications; 183 }; 184