From 1af385fa05c05446365162292f67c3a8151d79a8 Mon Sep 17 00:00:00 2001 From: Markus Frank <Markus.Frank@cern.ch> Date: Thu, 24 Mar 2022 11:46:30 +0100 Subject: [PATCH] Fixes to Property UI implementation --- MyOnline/ROMon.xml/DATAFLOW02.xml | 23 +++ MyOnline/ROMon.xml/TaskInventory.xml | 95 +--------- .../src/interactive/PropertyManip.cpp | 2 +- Online/GauchoServer/src/GauchoRPC.cpp | 7 +- Online/HTTP/include/HTTP/Cache.inl.h | 177 +++++++++--------- Online/HTTP/src/Cache.cpp | 2 +- Online/ROMon/src/NodeStatsPublisher.cpp | 4 +- Online/RPC/include/RPC/HttpRpcServer.h | 2 +- Online/RPC/include/RPC/JSONRPC.h | 26 ++- Online/RPC/src/HttpRpcServer.cpp | 2 +- Online/RPC/src/JSONRPC.cpp | 43 ++--- Online/RPCServer/CMakeLists.txt | 2 +- Online/RPCServer/cli/run_http_rpc_bridge.cpp | 26 ++- Online/RPCServer/include/RPC/DimServer.h | 8 +- .../include/RPC/HttpJsonRpcHandler.h | 8 + .../RPCServer/include/RPC/HttpXmlRpcHandler.h | 5 +- .../RPC/RpcPropertyUI.h} | 51 +---- Online/RPCServer/src/DimServer.cpp | 10 +- Online/RPCServer/src/HttpDimRpcBridge.h | 14 +- Online/RPCServer/src/HttpHttpRpcBridge.h | 3 +- Online/RPCServer/src/HttpJsonRpcHandler.cpp | 171 +++++++++++++---- Online/RPCServer/src/HttpXmlRpcHandler.cpp | 2 + Online/RPCServer/src/RpcPropertyUI.cpp | 65 +++++++ Online/RPCServer/tests/src/RODomainRPC.cpp | 84 ++++++--- Online/RPCServer/tests/src/test_jsonrpc.cpp | 0 25 files changed, 491 insertions(+), 341 deletions(-) create mode 100644 MyOnline/ROMon.xml/DATAFLOW02.xml rename Online/RPCServer/{src/RpcObjectPropertyUI.cpp => include/RPC/RpcPropertyUI.h} (58%) create mode 100644 Online/RPCServer/src/RpcPropertyUI.cpp delete mode 100644 Online/RPCServer/tests/src/test_jsonrpc.cpp diff --git a/MyOnline/ROMon.xml/DATAFLOW02.xml b/MyOnline/ROMon.xml/DATAFLOW02.xml new file mode 100644 index 000000000..f8751bc1e --- /dev/null +++ b/MyOnline/ROMon.xml/DATAFLOW02.xml @@ -0,0 +1,23 @@ +<TaskInventory> + <NodeList name="UCEB"> + <Name>DATAFLOW01</Name> + <Node name="UCEB01" type="EventBuilder"/> + <Node name="UCEB02" type="EventBuilder"/> + <Node name="UCEB03" type="EventBuilder"/> + <Node name="UCEB04" type="EventBuilder"/> + <Node name="UCEB05" type="EventBuilder"/> + <Node name="UCEB06" type="EventBuilder"/> + <Node name="UCEB07" type="EventBuilder"/> + <Node name="UCEB08" type="EventBuilder"/> + <Node name="UCEB09" type="EventBuilder"/> + <Node name="UCEB10" type="EventBuilder"/> + <Node name="UCEB11" type="EventBuilder"/> + <Node name="UCEB12" type="EventBuilder"/> + <Node name="UCEB13" type="EventBuilder"/> + <Node name="UCEB14" type="EventBuilder"/> + <Node name="UCEB15" type="EventBuilder"/> + <Node name="UCEB16" type="EventBuilder"/> + <Node name="UCEB17" type="EventBuilder"/> + <Node name="UCEB18" type="EventBuilder"/> + </NodeList> +</TaskInventory> diff --git a/MyOnline/ROMon.xml/TaskInventory.xml b/MyOnline/ROMon.xml/TaskInventory.xml index 94e970ab5..b2ea5d645 100755 --- a/MyOnline/ROMon.xml/TaskInventory.xml +++ b/MyOnline/ROMon.xml/TaskInventory.xml @@ -120,21 +120,9 @@ <TaskList name="StandardMonitoring"> </TaskList> -<TaskList name="StandardStorage"> -</TaskList> - -<TaskList name="StorageControl"> -</TaskList> - -<TaskList name="ReconstructionControl"> -</TaskList> - <TaskList name="MonitoringWorker"> </TaskList> -<TaskList name="ReconstructionWorker"> -</TaskList> - <TaskList name="MonitoringControl"> </TaskList> @@ -156,50 +144,6 @@ <Connection name="storectl01"/> </ConnectionList> -<ConnectionList name="StorageReceiver"> -<!-- - <Connection name="storerecv01-d1"/> - <Connection name="storerecv02-d1"/> - <Connection name="storerecv03-d1"/> - <Connection name="storerecv04-d1"/> ---> -</ConnectionList> - -<ConnectionList name="StorageControl"> -<!-- - <Connection name="storerecv02"/> - <Connection name="storerecv03"/> - <Connection name="storerecv04"/> - <Connection name="storerecv01"/> - - <Connection name="storestrm01"/> - <Connection name="storestrm02"/> - <Connection name="storestrm03"/> - <Connection name="storestrm04"/> ---> -</ConnectionList> - -<ConnectionList name="StorageWorker"> -<!-- - <Connection name="storerecv02-d1"/> - <Connection name="storerecv03-d1"/> - <Connection name="storerecv04-d1"/> - <Connection name="storerecv01-d1"/> - - <Connection name="storestrm01-d1"/> - <Connection name="storestrm02-d1"/> - <Connection name="storestrm03-d1"/> - <Connection name="storestrm04-d1"/> ---> -</ConnectionList> - -<ConnectionList name="StorageWriters"> -<!-- - <Connection name="store01-d1"/> - <Connection name="store02-d1"/> - <Connection name="store03-d1"/> ---> -</ConnectionList> <NodeType name="DefaultNode"> <TaskList name="FMC"/> @@ -213,7 +157,6 @@ <Task name="MBMMON_0"/> --> <ConnectionList name="Standard"/> - <ConnectionList name="StorageWorker"/> </NodeType> <NodeType name="HLTControl"> @@ -312,7 +255,6 @@ <Task name="TaskDBCheck"/> <ConnectionList name="Standard"/> <ConnectionList name="HLTWorker"/> - <ConnectionList name="StorageReceiver"/> </NodeType> <NodeType name="DQControl"> @@ -394,45 +336,12 @@ <TaskList name="StandardMonitoring"/> <TaskList name="MonitoringWorker"/> <ConnectionList name="Standard"/> - <ConnectionList name="StorageReceiver"/> -</NodeType> - -<NodeType name="ReconstructionControl"> - <TaskList name="FMC"/> - <TaskList name="ControlsPC"/> - <TaskList name="StandardReconstruction"/> - <TaskList name="ReconstructionControl"/> - <ConnectionList name="ControlsPC"/> - <Project name="RECONSTRUCTION"/> </NodeType> -<NodeType name="ReconstructionWorker"> +<NodeType name="EventBuilder"> <TaskList name="FMC"/> - <TaskList name="StandardReconstruction"/> - <TaskList name="ReconstructionWorker"/> <ConnectionList name="Standard"/> - <ConnectionList name="StorageReceiver"/> -</NodeType> - - -<NodeType name="StorageControl"> - <TaskList name="FMC"/> - <TaskList name="ControlsPC"/> - <TaskList name="StandardStorage"/> - <TaskList name="StorageControl"/> - <ConnectionList name="ControlsPC"/> - <ConnectionList name="StorageControl"/> - <Project name="LBECS"/> - <Project name="STORAGE"/> -</NodeType> - -<NodeType name="StorageWorker"> - <TaskList name="FMC"/> - <TaskList name="StandardStorage"/> - <TaskList name="StorageWorker"/> - <ConnectionList name="Standard"/> - <ConnectionList name="StorageWorker"/> - <ConnectionList name="StorageWriter"/> + <Task name="TaskDBCheck"/> </NodeType> <NodeType name="PublisherNode"> diff --git a/Online/Dataflow/src/interactive/PropertyManip.cpp b/Online/Dataflow/src/interactive/PropertyManip.cpp index 808336473..1097cc554 100644 --- a/Online/Dataflow/src/interactive/PropertyManip.cpp +++ b/Online/Dataflow/src/interactive/PropertyManip.cpp @@ -90,7 +90,7 @@ void PropertyManip::startServices() { dimSvcID = ::dis_add_service(svc.c_str(),"C",0,0,feedProperties,(long)this); } if ( 0 == rpc ) { - rpc = new rpc::DimServer(RTL::processName()); + rpc = new rpc::DimServer(RTL::processName(), "/RPC2"); rpc->setDebug(true); rpc->define("clients", xmlrpc::Call(this).make(&PropertyManip::clients)); rpc->define("allProperties", xmlrpc::Call(this).make(&PropertyManip::allProperties)); diff --git a/Online/GauchoServer/src/GauchoRPC.cpp b/Online/GauchoServer/src/GauchoRPC.cpp index 9e1e0aa63..ce2fec1fb 100644 --- a/Online/GauchoServer/src/GauchoRPC.cpp +++ b/Online/GauchoServer/src/GauchoRPC.cpp @@ -544,10 +544,11 @@ extern "C" int run_gaucho_rpc(int argc, char** argv) { } GauchoRPC callable; - auto json_handler = std::make_unique<rpc::RpcHandlerImp<rpc::HttpJsonRpcHandler> >(); printout(INFO,"HTTPSERVER","TEST> Starting test JSONRPC server with URI:%s:%d threads:%d cache:%d debug:%d %s", host.c_str(), port, threads, cache, debug, debug ? "YES" : "NO"); callable.debug = (debug&4) != 0; + + auto json_handler = std::make_unique<rpc::RpcHandlerImp<rpc::HttpJsonRpcHandler> >(); (*json_handler)->define("counter_tasks", jsonrpc::Call(&callable).make(&GauchoRPC::counter_tasks)); (*json_handler)->define("task_counter_directory", jsonrpc::Call(&callable).make(&GauchoRPC::task_counter_directory)); (*json_handler)->define("task_counters_regex", jsonrpc::Call(&callable).make(&GauchoRPC::task_counters_regex)); @@ -582,8 +583,8 @@ extern "C" int run_gaucho_rpc(int argc, char** argv) { (*file_handler)->debug = (debug&1) != 0; auto handler = std::make_unique<rpc::HttpServer::Handler>(); - auto json_clean = std::make_unique<http::HttpCacheCheck>(**json_handler, handler->io_service, 20); - auto file_clean = std::make_unique<http::HttpCacheCheck>(**file_handler, handler->io_service, 200); + auto json_clean = std::make_shared<http::HttpCacheCheck>(**json_handler, handler->io_service, 20); + auto file_clean = std::make_shared<http::HttpCacheCheck>(**file_handler, handler->io_service, 200); handler->mountPoints.handlers.emplace("/monitoring/FILES", std::move(file_handler)); handler->mountPoints.handlers.emplace("/monitoring/JSONRPC", std::move(json_handler)); diff --git a/Online/HTTP/include/HTTP/Cache.inl.h b/Online/HTTP/include/HTTP/Cache.inl.h index 251ab0a36..2e01ca24b 100644 --- a/Online/HTTP/include/HTTP/Cache.inl.h +++ b/Online/HTTP/include/HTTP/Cache.inl.h @@ -19,109 +19,112 @@ // C/C++ include files #include <cstring> -/// Initializing constructor -template <typename DATA> http::Cache<DATA>::Cache() { -} +namespace http { -/// Default destructor -template <typename DATA> http::Cache<DATA>::~Cache() { -} + /// Initializing constructor + template <typename DATA> Cache<DATA>::Cache() { + } -/// Access number of entries in the cache -template <typename DATA> std::size_t http::Cache<DATA>::size() const { - return this->cache.size(); -} + /// Default destructor + template <typename DATA> Cache<DATA>::~Cache() { + } -/// Find a cache entry by path -template <typename DATA> const typename http::Cache<DATA>::entry_type* -http::Cache<DATA>::find(const std::string& key_name, const std::string& encoding) const { - return this->find(this->hash(key_name), encoding); -} + /// Access number of entries in the cache + template <typename DATA> std::size_t Cache<DATA>::size() const { + return this->cache.size(); + } -/// Find a cache entry by hash key -template <typename DATA> const typename http::Cache<DATA>::entry_type* -http::Cache<DATA>::find(key_type key, const std::string& encoding) const { - auto range = this->cache.equal_range(key); - for( auto it = range.first; it != range.second; ++it ) { - if( encoding.find(it->second->encoding) != std::string::npos ) { - return it->second.get(); - } + /// Find a cache entry by path + template <typename DATA> const typename Cache<DATA>::entry_type* + Cache<DATA>::find(const std::string& key_name, const std::string& encoding) const { + return this->find(this->hash(key_name), encoding); } - return nullptr; -} -/// Drop a cache entry by key -template <typename DATA> std::size_t http::Cache<DATA>::drop(key_type key) { - auto& c = this->cache; - std::size_t removed = 0; - for( auto it = c.find(key); it != c.end(); it = c.find(key) ) { - c.erase(it); - ++removed; + /// Find a cache entry by hash key + template <typename DATA> const typename Cache<DATA>::entry_type* + Cache<DATA>::find(key_type key, const std::string& encoding) const { + auto range = this->cache.equal_range(key); + for( auto it = range.first; it != range.second; ++it ) { + if( encoding.find(it->second->encoding) != std::string::npos ) { + return it->second.get(); + } + } + return nullptr; } - return removed; -} -/// Insert new entry into the cache -template <typename DATA> -bool http::Cache<DATA>::insert(key_type key, - std::time_t tmo, - const std::string& path, - const std::string& encoding, - const http::HttpReply& reply) -{ - auto range = cache.equal_range(key); - for( auto it = range.first; it != range.second; ++it ) { - if( encoding == it->second->encoding ) { - _set(it->second.get(), key, tmo, path, encoding, reply); - return false; + /// Drop a cache entry by key + template <typename DATA> std::size_t Cache<DATA>::drop(key_type key) { + auto& c = this->cache; + std::size_t removed = 0; + for( auto it = c.find(key); it != c.end(); it = c.find(key) ) { + c.erase(it); + ++removed; } + return removed; } - auto e = std::make_unique<entry_type>(); - _set(e.get(), key, tmo, path, encoding, reply); - this->cache.emplace(key, std::move(e)); - return true; -} -/// Clean "old" entries from cache [Thread safe, locked] -template <typename DATA> -std::size_t http::Cache<DATA>::drop_key(key_type key) { - std::lock_guard<std::mutex> lock(this->lock); - return this->drop(key); -} + /// Insert new entry into the cache + template <typename DATA> + bool Cache<DATA>::insert(key_type key, + std::time_t tmo, + const std::string& path, + const std::string& encoding, + const HttpReply& reply) + { + auto range = cache.equal_range(key); + for( auto it = range.first; it != range.second; ++it ) { + if( encoding == it->second->encoding ) { + _set(it->second.get(), key, tmo, path, encoding, reply); + return false; + } + } + auto e = std::make_unique<entry_type>(); + _set(e.get(), key, tmo, path, encoding, reply); + this->cache.emplace(key, std::move(e)); + return true; + } -/// Drop a cache entries by key [Thread safe, locked] -template <typename DATA> -std::size_t http::Cache<DATA>::drop_keys(const std::vector<key_type>& keys) { - std::size_t cnt = 0; - Cache<DATA>::cache_type& c = this->cache; - std::lock_guard<std::mutex> lock(this->lock); - for( auto key : keys ) { - for( auto it = c.find(key); it != c.end(); it = c.find(key) ) { - ++cnt; - c.erase(it); + /// Clean "old" entries from cache [Thread safe, locked] + template <typename DATA> + std::size_t Cache<DATA>::drop_key(key_type key) { + std::lock_guard<std::mutex> lock(this->lock); + return this->drop(key); + } + + /// Drop a cache entries by key [Thread safe, locked] + template <typename DATA> + std::size_t Cache<DATA>::drop_keys(const std::vector<key_type>& keys) { + std::size_t cnt = 0; + Cache<DATA>::cache_type& c = this->cache; + std::lock_guard<std::mutex> lock(this->lock); + for( auto key : keys ) { + for( auto it = c.find(key); it != c.end(); it = c.find(key) ) { + ++cnt; + c.erase(it); + } } + return cnt; } - return cnt; -} -/// Clean "old" entries from cache [Thread safe, locked] -template <typename DATA> -size_t http::Cache<DATA>::drop_expired() { - key_type last = 0; - std::size_t cnt = 0; - std::time_t now = ::time(0); - Cache<DATA>::cache_type& c = this->cache; - std::lock_guard<std::mutex> lock(this->lock); - for( auto it = c.begin(); it != c.end(); ++it ) { - auto* e = it->second.get(); - if ( now > e->timeout ) { - ++cnt; - c.erase(it); - it = (last != 0) ? c.find(last) : c.begin(); - if ( it == c.end() ) break; + /// Clean "old" entries from cache [Thread safe, locked] + template <typename DATA> + size_t Cache<DATA>::drop_expired() { + key_type last = 0; + std::size_t cnt = 0; + std::time_t now = ::time(0); + Cache<DATA>::cache_type& c = this->cache; + std::lock_guard<std::mutex> lock(this->lock); + for( auto it = c.begin(); it != c.end(); ++it ) { + auto* e = it->second.get(); + if ( now > e->timeout ) { + ++cnt; + c.erase(it); + it = (last != 0) ? c.find(last) : c.begin(); + if ( it == c.end() ) break; + } + last = it->first; } - last = it->first; + return cnt; } - return cnt; } diff --git a/Online/HTTP/src/Cache.cpp b/Online/HTTP/src/Cache.cpp index 286756577..0ca2d79bb 100644 --- a/Online/HTTP/src/Cache.cpp +++ b/Online/HTTP/src/Cache.cpp @@ -28,7 +28,7 @@ void http::Cache<http::HttpReply>::_set(http::Cache<http::HttpReply>::entry_type const std::string& encoding, const http::HttpReply& reply) { - e->data = std::move(reply.clone()); + e->data = reply.clone(); e->timeout = ::time(0) + tmo; e->encoding = encoding; e->path = path; diff --git a/Online/ROMon/src/NodeStatsPublisher.cpp b/Online/ROMon/src/NodeStatsPublisher.cpp index e3f895f9c..3703f7cb7 100755 --- a/Online/ROMon/src/NodeStatsPublisher.cpp +++ b/Online/ROMon/src/NodeStatsPublisher.cpp @@ -294,8 +294,8 @@ NodeStatsPublisher::~NodeStatsPublisher() { /// Help printout in case of -h /? or wrong arguments void NodeStatsPublisher::help() { ::lib_rtl_output(LIB_RTL_ALWAYS,"romon_syspublish -opt [-opt]\n" - " -from=<string> Node which offers the data service(s)\n" - " -to=<string> Node to publish the data to.\n" + " -from=<string> DNS Node which offers the data service(s)\n" + " -to=<string> DNS Node to publish the data to.\n" " -verbose Switch to verbose mode.\n" " -match=<string> String to match service names.\n" " -publish=<string> Service name to publish results.\n" diff --git a/Online/RPC/include/RPC/HttpRpcServer.h b/Online/RPC/include/RPC/HttpRpcServer.h index 802578b11..7bed13b67 100644 --- a/Online/RPC/include/RPC/HttpRpcServer.h +++ b/Online/RPC/include/RPC/HttpRpcServer.h @@ -118,7 +118,7 @@ namespace rpc { class HttpServer::Handler : public http::HttpRequestHandler { struct ClientBridge { /// Known servers in the DNS domain - std::map<std::string, std::unique_ptr<HttpRpcHandler> > handlers; + std::map<std::string, std::shared_ptr<HttpRpcHandler> > handlers; /// Default constructor ClientBridge() = default; /// Default destructor diff --git a/Online/RPC/include/RPC/JSONRPC.h b/Online/RPC/include/RPC/JSONRPC.h index 24769689e..f94d781ec 100644 --- a/Online/RPC/include/RPC/JSONRPC.h +++ b/Online/RPC/include/RPC/JSONRPC.h @@ -224,6 +224,7 @@ public: int faultCode() const; /// Access the fault message string (requires a fault element in the response) std::string faultString() const; + template <typename T> static MethodResponse encode(const T& p); /// Decode the response of a server static MethodResponse decode(const std::string& json); /// Decode the response of a server @@ -695,6 +696,18 @@ struct CallSequence { } }; +template <typename T> inline MethodResponse MethodResponse::encode(const T& p) { + MethodResponse r(0UL); + json_h res = p; + r.root["result"] = res; + return r; +} +template <> inline MethodResponse MethodResponse::encode(const json_h& p) { + MethodResponse r(0UL); + r.root["result"] = p; + return r; +} + JSONRPC_NS_END #include <vector> @@ -721,6 +734,13 @@ template <typename T, typename V> void container_from_json(const json_h& j, T& c throw std::runtime_error("Cannot convert non-array json to STL containers"); } +template <typename T> MethodResponse _make_result(const T& b) { + MethodResponse r(0UL); json_h res; + to_json(res, b); + r.root["result"] = res; + return r; +} + JSONRPC_NS_END #define JSONRPC_IMPLEMENT_OBJECT_MARSCHALLING(typ,clazz) \ @@ -728,9 +748,9 @@ JSONRPC_NS_END /* Add a new parameter to the response */ \ template <> \ MethodResponse MethodResponse::make<clazz>(const clazz& b) { \ - MethodResponse r(0); \ - to_json(r.root, b); \ - return r; \ + json_h res; \ + to_json(res, b); \ + return MethodResponse::encode(res); \ } \ \ /* Add a new parameter to the response */ \ diff --git a/Online/RPC/src/HttpRpcServer.cpp b/Online/RPC/src/HttpRpcServer.cpp index 91a02d0e4..d04d9e555 100644 --- a/Online/RPC/src/HttpRpcServer.cpp +++ b/Online/RPC/src/HttpRpcServer.cpp @@ -147,7 +147,7 @@ void rpc::HttpServer::Handler::remove_all() { rpc::HttpServer::Handler::continue_action rpc::HttpServer::Handler::handle_mount_request(const http::Request& req, http::Reply& rep) { size_t idx = req.uri.rfind("/"); - std::string uri = req.uri.substr(0, idx); + std::string uri = req.uri.substr(0, idx==0 ? string::npos : idx); while ( uri.length() > 0 ) { auto handler = this->mountPoints.handlers.find(uri); if ( handler != this->mountPoints.handlers.end() ) { diff --git a/Online/RPC/src/JSONRPC.cpp b/Online/RPC/src/JSONRPC.cpp index 7e25206b9..a25f2724a 100644 --- a/Online/RPC/src/JSONRPC.cpp +++ b/Online/RPC/src/JSONRPC.cpp @@ -289,62 +289,57 @@ template <> const MethodCall& MethodCall::addParam<Array>(const Array& arr) { this->params().push_back(arr.root); return *this; } //--------------------------------------------------------------------------------- -template <typename T> static MethodResponse _resp(const T& p) { - MethodResponse r(0); - r.root[_rpcU(result)] = p; - return r; -} /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<bool>(const bool& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<char>(const char& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<signed char>(const signed char& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<unsigned char>(const unsigned char& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<short>(const short& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<unsigned short>(const unsigned short& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<int>(const int& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<unsigned int>(const unsigned int& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<long>(const long& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<unsigned long>(const unsigned long& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<double>(const double& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<float>(const float& p) -{ return _resp(p); } +{ return encode(p); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<string>(const string& p) -{ return _resp(string_encode(p)); } +{ return encode(string_encode(p)); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<struct tm>(const struct tm& p) -{ return _resp(_toString(p)); } +{ return encode(_toString(p)); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<p_char>(const p_char& p) -{ return _resp(p ? string_encode(p) : string()); } +{ return encode(p ? string_encode(p) : string()); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<Structure>(const Structure& s) -{ return _resp(s.root); } +{ return encode(s.root); } /// Add a new parameter to the response template <> MethodResponse MethodResponse::make<Array>(const Array& a) -{ return _resp(a.root); } +{ return encode(a.root); } /// Access data element by true type template <> string MethodResponse::data<string>() const @@ -713,9 +708,7 @@ void CallSequence::checkTypes(const type_info& typ1, const type_info& typ2, void #define JSONRPC_IMPLEMENT_PRIMITIVE_MARSCHALLING(X) JSONRPC_NS_BEGIN \ template <> MethodResponse MethodResponse::make< X >(const X& b) { \ - MethodResponse r(0); \ - r.root = b; \ - return r; \ + return MethodResponse::encode(b); \ } \ template <> X MethodCall::arg< X >(size_t handle) const { \ return this->params()[handle].get< X >(); \ diff --git a/Online/RPCServer/CMakeLists.txt b/Online/RPCServer/CMakeLists.txt index f08ef3bd1..de2673a82 100644 --- a/Online/RPCServer/CMakeLists.txt +++ b/Online/RPCServer/CMakeLists.txt @@ -21,7 +21,7 @@ gaudi_add_library(RPCServer src/DimServer.cpp src/HttpXmlRpcHandler.cpp src/HttpJsonRpcHandler.cpp - src/RpcObjectPropertyUI.cpp + src/RpcPropertyUI.cpp LINK PUBLIC Online::RPC diff --git a/Online/RPCServer/cli/run_http_rpc_bridge.cpp b/Online/RPCServer/cli/run_http_rpc_bridge.cpp index 34e773c4c..0b77b767e 100644 --- a/Online/RPCServer/cli/run_http_rpc_bridge.cpp +++ b/Online/RPCServer/cli/run_http_rpc_bridge.cpp @@ -16,7 +16,9 @@ //========================================================================== /// Framework includes +#include <RPC/HttpJsonRpcHandler.h> #include <RPC/HttpXmlRpcHandler.h> +#include <RPC/HttpRpcHandler.h> #include <XML/Printout.h> #include <RTL/Logger.h> #include <dim/dis.h> @@ -60,8 +62,28 @@ extern "C" int run_http_rpc_bridge(int argc, char** argv) { help_server(); } RTL::Logger::install_log(RTL::Logger::log_args(debug ? LIB_RTL_DEBUG : LIB_RTL_INFO)); - rpc::HttpServer server(std::make_unique<rpc::HttpXmlRpcHandler>(), - host,port,rpc::HttpServer::BRIDGE); + + + auto json_handler = std::make_shared<rpc::RpcHandlerImp<rpc::HttpJsonRpcHandler> >(); + (*json_handler)->mode = rpc::HttpServer::BRIDGE; + (*json_handler)->server_uri = "/JSONRPC"; + (*json_handler)->debug = debug != 0; + auto xml_handler1 = std::make_shared<rpc::RpcHandlerImp<rpc::HttpXmlRpcHandler> >(); + (*xml_handler1)->mode = rpc::HttpServer::BRIDGE; + (*xml_handler1)->server_uri = "/XMLRPC"; + (*xml_handler1)->debug = debug != 0; + auto xml_handler2 = std::make_shared<rpc::RpcHandlerImp<rpc::HttpXmlRpcHandler> >(); + (*xml_handler2)->mode = rpc::HttpServer::BRIDGE; + (*xml_handler2)->server_uri = "/RPC2"; + (*xml_handler2)->debug = (debug&1) != 0; + + auto handler = std::make_unique<rpc::HttpServer::Handler>(); + handler->mountPoints.handlers.emplace((*json_handler)->server_uri, std::move(json_handler)); + handler->mountPoints.handlers.emplace((*xml_handler1)->server_uri, std::move(xml_handler1)); + handler->mountPoints.handlers.emplace((*xml_handler2)->server_uri, std::move(xml_handler2)); + + rpc::HttpServer server(std::move(handler), host, port, rpc::HttpServer::SERVER); + server.setDebug(debug != 0); printout(INFO,"HTTPSERVER", "TEST> Starting test XMLRPC server with URI:%s:%d [%d threads]\n", diff --git a/Online/RPCServer/include/RPC/DimServer.h b/Online/RPCServer/include/RPC/DimServer.h index 72cf607c2..30cb9a9ec 100644 --- a/Online/RPCServer/include/RPC/DimServer.h +++ b/Online/RPCServer/include/RPC/DimServer.h @@ -58,9 +58,9 @@ namespace rpc { public: /// Initializing constructor with user defined handler - DimServer(std::unique_ptr<Handler>&& handler, const std::string& srv_name, const std::string& dns_name=""); + DimServer(std::unique_ptr<Handler>&& handler, const std::string& server, const std::string& dns_name=""); /// Initializing constructor - DimServer(const std::string& server, const std::string& dns=""); + DimServer(const std::string& server, const std::string& mount, const std::string& dns=""); /// Default destructor virtual ~DimServer(); /// Modify debug flag @@ -98,7 +98,7 @@ namespace rpc { class DimServer::Handler { public: /// Standard constructor - explicit Handler(); + explicit Handler(const std::string& mount); /// Default destructor virtual ~Handler(); /// Run the server's io_service loop. @@ -115,6 +115,8 @@ namespace rpc { typedef std::map<std::string,xmlrpc::Call> XmlCalls; typedef std::map<std::string,jsonrpc::Call> JsonCalls; + /// Server mount point + std::string mount; /// Object Lock to ensure we have no race conditions when editing the call-map std::mutex lock; /// The map of registered XML-RPC calls diff --git a/Online/RPCServer/include/RPC/HttpJsonRpcHandler.h b/Online/RPCServer/include/RPC/HttpJsonRpcHandler.h index e05787658..b129140c8 100644 --- a/Online/RPCServer/include/RPC/HttpJsonRpcHandler.h +++ b/Online/RPCServer/include/RPC/HttpJsonRpcHandler.h @@ -45,6 +45,14 @@ namespace rpc { /// HttpServer::Handler overload: Handle a request and produce a reply. virtual continue_action handle_request(const http::Request& req, http::Reply& rep) override; + + /// Handle a request and produce a reply. + virtual void handle_server_request(const http::Request& req, http::Reply& rep); + + /// Handle a request and produce a reply. + virtual void handle_bridge_request(const std::string& dns, + const std::string& server, + const http::Request& req, http::Reply& rep); }; } /* End namespace jsonrpc */ #endif /* ONLINE_RPC_HTTPJSONRPCHANDLER_H */ diff --git a/Online/RPCServer/include/RPC/HttpXmlRpcHandler.h b/Online/RPCServer/include/RPC/HttpXmlRpcHandler.h index bffd56955..162eaec06 100644 --- a/Online/RPCServer/include/RPC/HttpXmlRpcHandler.h +++ b/Online/RPCServer/include/RPC/HttpXmlRpcHandler.h @@ -16,19 +16,22 @@ #define ONLINE_RPC_HTTPXMLRPCHANDLER_H // Framework include files +#include <HTTP/HttpCacheHandler.h> #include <RPC/HttpRpcServer.h> #include <RPC/XMLRPC.h> /// Namespace for the http based xmlrpc implementation namespace rpc { - class HttpXmlRpcHandler : public HttpServer::Handler { + class HttpXmlRpcHandler : public HttpServer::Handler, public http::HttpCacheHandler { public: /// Definition of the RPC callback map typedef std::map<std::string, xmlrpc::Call> Calls; /// The map of registered XML-RPC calls Calls calls; + /// Compression parameters + compression_params_t compression; public: /// Standard constructor diff --git a/Online/RPCServer/src/RpcObjectPropertyUI.cpp b/Online/RPCServer/include/RPC/RpcPropertyUI.h similarity index 58% rename from Online/RPCServer/src/RpcObjectPropertyUI.cpp rename to Online/RPCServer/include/RPC/RpcPropertyUI.h index 46f110dd8..06abc8f44 100644 --- a/Online/RPCServer/src/RpcObjectPropertyUI.cpp +++ b/Online/RPCServer/include/RPC/RpcPropertyUI.h @@ -12,6 +12,11 @@ // // Author : Markus Frank //========================================================================== +#ifndef ONLINE_RPC_RPCPROPERTYUI_H +#define ONLINE_RPC_RPCPROPERTYUI_H + +// C/C++ include files +#include <memory> // Framework include files #include <CPP/ObjectProperty.h> @@ -49,19 +54,6 @@ namespace rpc { void start_server() override; void stop_server() override; }; -} - -#include <stdexcept> -#include <RPC/XMLRPC.h> -#include <RPC/JSONRPC.h> -#include <RPC/DimServer.h> -#include <RPC/HttpRpcServer.h> -#include <RPC/HttpXmlRpcHandler.h> -#include <RPC/HttpJsonRpcHandler.h> - -using namespace std; - -namespace rpc { template <typename SERVER, typename CALL> inline int define_server(SERVER& server, CALL& call) { @@ -79,16 +71,6 @@ namespace rpc { return 1; } - unique_ptr<DimServer> create_srv(DimServer::Handler* hdlr, const vector<string>& args) { - return make_unique<DimServer>(move(unique_ptr<DimServer::Handler>(hdlr)), args[0], args[1]); - } - - unique_ptr<HttpServer> create_srv(HttpServer::Handler* hdlr, const vector<string>& args) { - return ( args.size() > 3 ) - ? make_unique<HttpServer>(move(unique_ptr<HttpServer::Handler>(hdlr)), args[0], args[1], args[2], args[3]) - : make_unique<HttpServer>(move(unique_ptr<HttpServer::Handler>(hdlr)), args[0], args[1], args[2]); - } - template <typename SERVER, typename PROTOCOL> void RpcPropertyUI<SERVER, PROTOCOL>::start_server() { define_server(this->get_server(), this->get_call()); @@ -100,26 +82,5 @@ namespace rpc { this->get_server().stop(); this->get_server().remove_all(); } - - template <typename SERVER, typename HANDLER, typename CALL> inline - RpcUI* create_rpc_property_ui(UI* ui, HANDLER* hdlr, const vector<string>& args) { - auto* rpc_ui = new RpcPropertyUI<SERVER,CALL>(); - rpc_ui->call = make_unique<CALL>(ui); - rpc_ui->server = create_srv(hdlr, args); - rpc_ui->start_server(); - return rpc_ui; - } -} - -extern "C" rpc::RpcUI* create_rpc_ui(const string& type, rpc::UI* ui, const vector<string>& args) { - using namespace rpc; - if ( ::strcasecmp(type.c_str(),"dimxmlrpc") == 0 ) - return create_rpc_property_ui<DimServer,DimServer::Handler,xmlrpc::Call>(ui, new DimServer::Handler(), args); - if ( ::strcasecmp(type.c_str(),"dimjsonrpc") == 0 ) - return create_rpc_property_ui<DimServer,DimServer::Handler,jsonrpc::Call>(ui, new DimServer::Handler(), args); - if ( ::strcasecmp(type.c_str(),"httpxmlrpc") == 0 ) - return create_rpc_property_ui<HttpServer,HttpXmlRpcHandler,xmlrpc::Call>(ui, new HttpXmlRpcHandler(), args); - if ( ::strcasecmp(type.c_str(),"httpjsonrpc") == 0 ) - return create_rpc_property_ui<HttpServer,HttpJsonRpcHandler,jsonrpc::Call>(ui, new HttpJsonRpcHandler(), args); - return nullptr; } +#endif // ONLINE_RPC_RPCPROPERTYUI_H diff --git a/Online/RPCServer/src/DimServer.cpp b/Online/RPCServer/src/DimServer.cpp index 2f29f752c..5313b0ea6 100644 --- a/Online/RPCServer/src/DimServer.cpp +++ b/Online/RPCServer/src/DimServer.cpp @@ -70,7 +70,7 @@ namespace { } } -DimServer::Handler::Handler() { +DimServer::Handler::Handler(const string& m) : mount(m) { } DimServer::Handler::~Handler() { @@ -83,12 +83,12 @@ void DimServer::Handler::open(const std::string& server,const std::string& dns) if ( response_id != -1 ) ::dis_remove_service(response_id); if ( !dns.empty() ) ::dis_set_dns_node(dns.c_str()); - string name = server + "/RPC2"; + string name = server + mount; request_id = ::dis_add_cmnd(name.c_str(),"C",handle_request,(long)this); if ( request_id <= 0 ) { throw runtime_error("Failed dis_add_cmnd("+name+")"); } - name = server + "/RPC2/Reply"; + name = server + mount + "/Reply"; response_id = ::dis_add_service(name.c_str(),"C",0,0,feed_result,(long)this); if ( response_id <= 0 ) { throw runtime_error("Failed dis_add_service("+name+")"); @@ -221,8 +221,8 @@ int DimServer::Handler::update_client(const DimRequest* req, string&& answer) } /// Initializing constructor -DimServer::DimServer(const string& srv_name, const string& dns_name) - : implementation(new Handler()), server(srv_name), dns(dns_name) +DimServer::DimServer(const string& srv_name, const string& mount, const string& dns_name) + : implementation(new Handler(mount)), server(srv_name), dns(dns_name) { } diff --git a/Online/RPCServer/src/HttpDimRpcBridge.h b/Online/RPCServer/src/HttpDimRpcBridge.h index 0063108db..bcb1a0a01 100644 --- a/Online/RPCServer/src/HttpDimRpcBridge.h +++ b/Online/RPCServer/src/HttpDimRpcBridge.h @@ -80,11 +80,11 @@ namespace { } catch(const std::exception& e) { boost::system::error_code errcode(errno,boost::system::system_category()); - client->response = http::to_vector(xmlrpc::MethodResponse::makeFault(errcode.value(),e.what()).str()); + client->response = http::to_vector(MethodResponse::makeFault(errcode.value(),e.what()).str()); } catch( ... ) { boost::system::error_code errcode(errno,boost::system::system_category()); - client->response = http::to_vector(xmlrpc::MethodResponse::makeFault(errcode.value(),errcode.message()).str()); + client->response = http::to_vector(MethodResponse::makeFault(errcode.value(),errcode.message()).str()); } client->ready = 1; client->message_id = 0; @@ -98,7 +98,7 @@ namespace { } /// Standard constructor -rpc::HttpDimBridgeHandler::HttpDimBridgeHandler(const std::string& server_name,int dbg) +inline rpc::HttpDimBridgeHandler::HttpDimBridgeHandler(const std::string& server_name,int dbg) : debug(dbg) { /// Initialize structure @@ -123,12 +123,12 @@ rpc::HttpDimBridgeHandler::HttpDimBridgeHandler(const std::string& server_name,i } /// Standard destructor -rpc::HttpDimBridgeHandler::~HttpDimBridgeHandler() { +inline rpc::HttpDimBridgeHandler::~HttpDimBridgeHandler() { if ( response_id != -1 ) ::dic_release_service(response_id); } /// Execute RPC call -rpc::HttpDimBridgeHandler::continue_action +inline rpc::HttpDimBridgeHandler::continue_action rpc::HttpDimBridgeHandler::handle_request(const http::Request& req, http::Reply& rep) { using namespace chrono; stringstream str; @@ -171,7 +171,7 @@ rpc::HttpDimBridgeHandler::handle_request(const http::Request& req, http::Reply& if ( condition.wait_for(lck,chrono::milliseconds(timeout)) == cv_status::timeout ) { if ( !ready ) { message_id = 0; - throw std::runtime_error("XML-RPC: Command timeout "+name); + throw std::runtime_error("RPC: Command timeout "+name); } } } @@ -214,7 +214,7 @@ rpc::HttpDimBridgeHandler::handle_request(const http::Request& req, http::Reply& } catch( ... ) { std::error_code errcode(errno, std::system_category()); - str << "XMLRPC fault [" << errcode.value() << "] (UNKOWN Exception): " << errcode.message(); + str << "RPC fault [" << errcode.value() << "] (UNKOWN Exception): " << errcode.message(); } throw std::runtime_error(str.str()); } diff --git a/Online/RPCServer/src/HttpHttpRpcBridge.h b/Online/RPCServer/src/HttpHttpRpcBridge.h index 551f9e647..157c8b069 100644 --- a/Online/RPCServer/src/HttpHttpRpcBridge.h +++ b/Online/RPCServer/src/HttpHttpRpcBridge.h @@ -83,7 +83,8 @@ rpc::HttpHttpBridgeHandler::handle_request(const http::Request& req, http::Reply printout(INFO,"RPCClient","HttpHttpBridgeHandler: Handling request(%s:%s)", client.host.c_str(), client.port.c_str()); } - rep.content = client.request(req.content.data(), req.content.size(), acceptedEncoding, dataEncoding); + client.mount = req.uri; + rep.content = client.request(req.content.data(), req.content.size(), acceptedEncoding, dataEncoding); copy(client.userReplyHeaders.begin(),client.userReplyHeaders.end(),back_inserter(rep.userHeaders)); if ( !dataEncoding.empty() ) { rep.userHeaders.push_back(http::HttpHeader("Content-Encoding", dataEncoding)); diff --git a/Online/RPCServer/src/HttpJsonRpcHandler.cpp b/Online/RPCServer/src/HttpJsonRpcHandler.cpp index 0f63db5a9..2e9fe0bea 100644 --- a/Online/RPCServer/src/HttpJsonRpcHandler.cpp +++ b/Online/RPCServer/src/HttpJsonRpcHandler.cpp @@ -76,49 +76,41 @@ rpc::HttpJsonRpcHandler::handle_request(const http::Request& req, http::Reply& r // ERROR: call user callbacks for (const auto& c : onError ) c.execute(args); - goto Done; } - - const char* data_ptr = (const char*)req.content.data(); - std::string call_data ( data_ptr, data_ptr + req.content.size() ); - jsonrpc::MethodCall call(call_data); - call_id = call.id(); - call.root["id"] = 0; - call_key = call.str(); - - /// First check if the requested entry is already in the cache: - if ( this->use_cache(this->lock) ) { - auto [use,reply] = this->check_cache(call_key, req); - if ( use ) { - rep = std::move(reply); - return HttpRequestHandler::write; + else { + string server, dns; + for(const auto& h : req.headers) { + if ( h.name == "Dim-Server" ) { + server = h.value; + break; + } + } + for(const auto& h : req.headers) { + if ( h.name == "Dim-DNS" ) { + dns = h.value; + break; + } + } + rep = http::Reply::stock_reply(http::Reply::ok); + switch(mode) { + case rpc::HttpServer::SERVER: + handle_server_request(req, rep); + break; + case rpc::HttpServer::BRIDGE: + handle_bridge_request(dns, server, req, rep); + break; + default: + server.empty() ? + handle_server_request(req, rep) : + handle_bridge_request(dns, server, req, rep); + break; } } - - string method = call.method(); - const auto& callback = calls.find(method); - - rep = http::Reply::stock_reply(http::Reply::ok); - if ( callback == calls.end() ) { - jsonrpc::MethodResponse response = jsonrpc::MethodResponse::makeFault(call_id, EOPNOTSUPP); - rep.content = http::to_vector(response.str()); - // Unhandled call: call user callbacks - for (const auto& c : onUnhandled ) - c.execute(args); - goto Done; - } - const jsonrpc::Call& c = (*callback).second; - jsonrpc::MethodResponse response = c.execute(call); - rep.content = http::to_vector(response.str()); - #if defined(RPC_HAVE_COMPRESSION) if ( this->compression.enable ) { this->compress_reply(req, rep, encoding); } #endif - // Successfully handled call: call user callbacks - for (const auto& cb : onHandled ) - cb.execute(args); } catch(const std::exception& e) { jsonrpc::MethodResponse response = jsonrpc::MethodResponse::makeFault(call_id, EINVAL, e.what()); @@ -134,7 +126,6 @@ rpc::HttpJsonRpcHandler::handle_request(const http::Request& req, http::Reply& r for (const auto& c : onError ) c.execute(args); } - Done: time_t now = ::time(0); char nowstr[64]; string tim = ::ctime_r(&now,nowstr); @@ -175,3 +166,111 @@ rpc::HttpJsonRpcHandler::handle_request(const http::Request& req, http::Reply& r } return write; } + +/// Handle a request and produce a reply. +void rpc::HttpJsonRpcHandler::handle_server_request(const http::Request& req, http::Reply& rep) { + const void* args[] = { &req, 0 }; + const char* data_ptr = (const char*)req.content.data(); + std::string call_data ( data_ptr, data_ptr + req.content.size() ); + std::string call_key; + jsonrpc::MethodCall call(call_data); + int call_id = 0; + + try { // Python jsonrpc does not handle ids properly... + call_id = call.id(); + } + catch(...) { + } + call.root["id"] = 0; + call_key = call.str(); + + /// First check if the requested entry is already in the cache: + if ( this->use_cache(this->lock) ) { + auto [use,reply] = this->check_cache(call_key, req); + if ( use ) { + rep = std::move(reply); + return; + } + } + string method = call.method(); + const auto& callback = calls.find(method); + rep = http::Reply::stock_reply(http::Reply::ok); + if ( callback == calls.end() ) { + jsonrpc::MethodResponse response = jsonrpc::MethodResponse::makeFault(call_id, EOPNOTSUPP); + rep.content = http::to_vector(response.str()); + // Unhandled call: call user callbacks + for (const auto& c : onUnhandled ) + c.execute(args); + return; + } + const jsonrpc::Call& c = (*callback).second; + jsonrpc::MethodResponse response = c.execute(call); + rep.content = http::to_vector(response.str()); + + // Successfully handled call: call user callbacks + for (const auto& cb : onHandled ) + cb.execute(args); +} + +using jsonrpc::MethodResponse; + +// This is the bridge implementation to HTTP +#include "HttpHttpRpcBridge.h" + +// This is the bridge implementation to DIM +#include "HttpDimRpcBridge.h" + +/// Handle a request and produce a reply. +void rpc::HttpJsonRpcHandler::handle_bridge_request(const std::string& dns, + const std::string& server, + const http::Request& req, + http::Reply& rep) +{ + if ( !server.empty() ) { + HttpRpcHandler* h = 0; + if ( dns.empty() ) { { + /// Handle http-dim request. Locked access due to multithreading. + Lock lck(lock); + auto i = dimBridge.handlers.find(server); + if ( i == dimBridge.handlers.end() ) { + auto ptr = std::make_unique<rpc::HttpDimBridgeHandler>(server, debug); + h = ptr.get(); + dimBridge.handlers.emplace(server, std::move(ptr)); + } + else { + h = (*i).second.get(); + } + } + h->setDebug(debug); + h->handle_request(req, rep); + return; + } + /// Handle http-http request. Locked access due to multithreading. + { string port = "2600"; + for(const auto& h : req.headers) { + if ( h.name == "RPC-Port" ) { + port = h.value; + break; + } + } + Lock lck(lock); + auto i = httpBridge.handlers.find(server); + if ( i == httpBridge.handlers.end() ) { + auto ptr = std::make_unique<rpc::HttpHttpBridgeHandler>(dns, server, port, debug); + h = ptr.get(); + httpBridge.handlers.emplace(server, std::move(ptr)); + } + else { + h = (*i).second.get(); + } + } + if ( debug > 1 ) { + printout(ALWAYS,"HttpHttpBridge", + "Sending request: %s **to** %s", &req.content[0], dns.c_str()); + } + h->setDebug(debug); + h->handle_request(req, rep); + return; + } + throw std::runtime_error("XML-RPC: Invalid request. Missing \"Dim-Server\" http header."); +} diff --git a/Online/RPCServer/src/HttpXmlRpcHandler.cpp b/Online/RPCServer/src/HttpXmlRpcHandler.cpp index 46d22ed57..3ae9cd275 100644 --- a/Online/RPCServer/src/HttpXmlRpcHandler.cpp +++ b/Online/RPCServer/src/HttpXmlRpcHandler.cpp @@ -188,6 +188,8 @@ void rpc::HttpXmlRpcHandler::handle_server_request(const http::Request& req, htt cb.execute(args); } +using xmlrpc::MethodResponse; + // This is the bridge implementation to HTTP #include "HttpHttpRpcBridge.h" diff --git a/Online/RPCServer/src/RpcPropertyUI.cpp b/Online/RPCServer/src/RpcPropertyUI.cpp new file mode 100644 index 000000000..9708275a5 --- /dev/null +++ b/Online/RPCServer/src/RpcPropertyUI.cpp @@ -0,0 +1,65 @@ +//========================================================================== +// LHCb Online software suite +//-------------------------------------------------------------------------- +// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN) +// All rights reserved. +// +// For the licensing terms see OnlineSys/LICENSE. +// +//-------------------------------------------------------------------------- +// +// Package : RPC +// +// Author : Markus Frank +//========================================================================== + +// Framework include files +#include <RPC/RpcPropertyUI.h> +#include <stdexcept> +#include <RPC/XMLRPC.h> +#include <RPC/JSONRPC.h> +#include <RPC/DimServer.h> +#include <RPC/HttpRpcServer.h> +#include <RPC/HttpXmlRpcHandler.h> +#include <RPC/HttpJsonRpcHandler.h> + +using namespace std; + +namespace rpc { + + unique_ptr<DimServer> create_srv(unique_ptr<DimServer::Handler>&& handler, const vector<string>& args) { + return make_unique<DimServer>(move(handler), args[0], args[1]); + } + + unique_ptr<HttpServer> create_srv(unique_ptr<HttpServer::Handler>&& handler, const vector<string>& args) { + return ( args.size() > 3 ) + ? make_unique<HttpServer>(move(handler), args[0], args[1], args[2], args[3]) + : make_unique<HttpServer>(move(handler), args[0], args[1], args[2]); + } + + template <typename SERVER, typename HANDLER, typename CALL> inline + unique_ptr<RpcPropertyUI<SERVER,CALL> > create_rpc_property_ui(UI* ui, unique_ptr<HANDLER>&& handler, const vector<string>& args) { + auto rpc_ui = make_unique<RpcPropertyUI<SERVER,CALL> >(); + rpc_ui->call = make_unique<CALL>(ui); + rpc_ui->server = create_srv(move(handler), args); + rpc_ui->start_server(); + return rpc_ui; + } +} + +extern "C" rpc::RpcUI* create_rpc_ui(const string& type, rpc::UI* ui, const vector<string>& args) { + using namespace rpc; + if ( ::strcasecmp(type.c_str(),"dimxmlrpc") == 0 ) { + auto handler = make_unique<DimServer::Handler>(args.size() > 2 ? args[2] : "/RPC2"); + return create_rpc_property_ui<DimServer,DimServer::Handler,xmlrpc::Call>(ui, move(handler), args).release(); + } + if ( ::strcasecmp(type.c_str(),"dimjsonrpc") == 0 ) { + auto handler = make_unique<DimServer::Handler>(args.size() > 2 ? args[2] : "/JSONRPC"); + return create_rpc_property_ui<DimServer,DimServer::Handler,jsonrpc::Call>(ui, move(handler), args).release(); + } + if ( ::strcasecmp(type.c_str(),"httpxmlrpc") == 0 ) + return create_rpc_property_ui<HttpServer,HttpXmlRpcHandler,xmlrpc::Call>(ui, make_unique<HttpXmlRpcHandler>(), args).release(); + if ( ::strcasecmp(type.c_str(),"httpjsonrpc") == 0 ) + return create_rpc_property_ui<HttpServer,HttpJsonRpcHandler,jsonrpc::Call>(ui, make_unique<HttpJsonRpcHandler>(), args).release(); + return nullptr; +} diff --git a/Online/RPCServer/tests/src/RODomainRPC.cpp b/Online/RPCServer/tests/src/RODomainRPC.cpp index ad9c848d5..c99d949d4 100644 --- a/Online/RPCServer/tests/src/RODomainRPC.cpp +++ b/Online/RPCServer/tests/src/RODomainRPC.cpp @@ -25,9 +25,12 @@ #include <RTL/strdef.h> #include <CPP/Interactor.h> #include <ROMon/FMCMonListener.h> +#include <RPC/JSONRPC.h> // C++ include files #include <vector> +#include <memory> +#include <thread> #include <mutex> #include <set> @@ -81,14 +84,13 @@ namespace ROMon { typedef std::map<std::string,RpcListener*> Servers; /// Cluster container Servers m_servers; - //xmlrpc::RPCServer* m_server = 0; /// Process name std::string m_name; /// Prefix for resulting service names std::string m_prefix; /// Printout level long m_print; - + std::unique_ptr<std::thread> m_httpThread; std::mutex m_mtx; std::set<std::string> m_domains; DimContext<std::string> m_domains_wincc; @@ -118,6 +120,7 @@ namespace ROMon { virtual void handle(const CPP::Event& ev) override; /// Access all known DNS domains std::set<std::string> domains(); + nlohmann::json domains2(); /// Access all nodes known to a DNS domain std::set<std::string> nodes(const std::string& dns); /// Access all nodes known to a DNS domain matching the regular expression @@ -159,12 +162,12 @@ namespace ROMon { #include <ROMon/PartitionListener.h> #include <MBM/bmstruct.h> #include <ROMon/ROMon.h> +#include <RPC/HttpRpcHandler.h> #include <RPC/HttpXmlRpcHandler.h> +#include <RPC/HttpJsonRpcHandler.h> #include <RPC/DimServer.h> #include <algorithm> -#include <memory> -#include <thread> using namespace ROMon; using namespace std; @@ -196,13 +199,12 @@ namespace { *buff = (void*)data; *size = 0; } - template <typename T> T* setupServer(RODomainRPC* obj, T* server) { - server->define("domains", xmlrpc::Call(obj).make(&RODomainRPC::domains)); - server->define("nodes", xmlrpc::Call(obj).make(&RODomainRPC::nodes)); - server->define("nodesByRegex", xmlrpc::Call(obj).make(&RODomainRPC::nodesByRegex)); - server->define("tasks", xmlrpc::Call(obj).make(&RODomainRPC::tasks)); - server->define("tasksByRegex", xmlrpc::Call(obj).make(&RODomainRPC::tasksByRegex)); - server->start(true); + template <typename T, typename C> T* setupHandler(C& rpc_call, T* server) { + server->define("domains", rpc_call.make(&RODomainRPC::domains)); + server->define("nodes", rpc_call.make(&RODomainRPC::nodes)); + server->define("nodesByRegex", rpc_call.make(&RODomainRPC::nodesByRegex)); + server->define("tasks", rpc_call.make(&RODomainRPC::tasks)); + server->define("tasksByRegex", rpc_call.make(&RODomainRPC::tasksByRegex)); return server; } } @@ -285,7 +287,7 @@ void RpcListener::update(void* param) { RODomainRPC::RODomainRPC(int argc, char** argv) : m_print(LIB_RTL_WARNING) { string PUBLISHING_NODE = "ECS03", from=PUBLISHING_NODE, to=PUBLISHING_NODE; string addr = "0.0.0.0", type="http"; - int port = 2600, threads = 0; + int port = 2600, threads = 0, compress = 1; RTL::CLI cli(argc, argv, RODomainRPC::help); m_name = "/"+RTL::processName(); cli.getopt("prefix", 3, m_prefix=""); @@ -297,6 +299,7 @@ RODomainRPC::RODomainRPC(int argc, char** argv) : m_print(LIB_RTL_WARNING) { cli.getopt("port", 3, port); cli.getopt("address",3, addr); cli.getopt("threads",3, threads); + cli.getopt("compress",3, compress); bool debug = cli.getopt("debug",2) != 0; string dbg_opt = debug ? "[Debugging ON]" : "[Debugging OFF]"; if ( m_name[0] != '/' ) m_name = '/'+m_name; @@ -307,22 +310,47 @@ RODomainRPC::RODomainRPC(int argc, char** argv) : m_print(LIB_RTL_WARNING) { m_status_id = ::dis_add_service((m_name+"/Counters").c_str(),"L",&m_counters,sizeof(m_counters),0,0); { lock_guard<mutex> lock(m_mtx); + xmlrpc::Call xmlrpc_call(this); + jsonrpc::Call jsonrpc_call(this); string name = m_name+"/WinCCOA/Domains"; m_domains_wincc.id = ::dis_add_service(name.c_str(),"C",0,0,feedString,(long)&m_domains_wincc); - if ( type == "http" ) { + if ( type.find("http") != string::npos ) { + auto json_handler = std::make_shared<rpc::RpcHandlerImp<rpc::HttpJsonRpcHandler> >(); + (*json_handler)->compression.enable = (compress != 0); + (*json_handler)->debug = debug; + (*json_handler)->define("domains2", jsonrpc_call.make(&RODomainRPC::domains2)); + + auto xml_handler = std::make_shared<rpc::RpcHandlerImp<rpc::HttpXmlRpcHandler> >(); + (*xml_handler)->compression.enable = (compress != 0); + (*xml_handler)->debug = debug; + setupHandler(jsonrpc_call, json_handler->get()); + setupHandler(xmlrpc_call, xml_handler->get()); + + auto handler = std::make_unique<rpc::HttpServer::Handler>(); + handler->mountPoints.handlers.emplace("/JSONRPC", json_handler); + handler->mountPoints.handlers.emplace("/XMLRPC", xml_handler); + handler->mountPoints.handlers.emplace("/RPC2", xml_handler); rpc::HttpServer* server - = new rpc::HttpServer(std::make_unique<rpc::HttpXmlRpcHandler>(), - addr,port,rpc::HttpServer::SERVER); + = new rpc::HttpServer(move(handler), addr, port, rpc::HttpServer::SERVER); server->setDebug(debug); - setupServer(this, server)->setDebug(debug); - new thread([server,threads] { - ::lib_rtl_output(LIB_RTL_INFO, - "[RODomainRPC] Running HTTP xmlrpc service with %d additional threads.",threads); - server->run(threads); - }); + server->start(true); + //setupServer(call, server)->setDebug(debug); + m_httpThread.reset(new thread([server,threads] { + ::lib_rtl_output(LIB_RTL_INFO, + "[RODomainRPC] Running HTTP xmlrpc service with %d additional threads.",threads); + server->run(threads); + })); } - else { - setupServer(this, new rpc::DimServer(m_name, to))->setDebug(debug); + if ( type.find("dim") != string::npos ) { + auto* server = setupHandler(xmlrpc_call, new rpc::DimServer(m_name, "/RPC2", to)); + server->setDebug(debug); + server->start(true); + server = setupHandler(xmlrpc_call, new rpc::DimServer(m_name, "/XMLRPC", to)); + server->setDebug(debug); + server->start(true); + server = setupHandler(jsonrpc_call, new rpc::DimServer(m_name, "/JSONRPC", to)); + server->setDebug(debug); + server->start(true); } } PartitionListener p(this,"Subfarms","*",true); @@ -334,6 +362,7 @@ RODomainRPC::RODomainRPC(int argc, char** argv) : m_print(LIB_RTL_WARNING) { /// Default destructor RODomainRPC::~RODomainRPC() { + m_httpThread.reset(); } /// Add cluster data points to bridge @@ -382,6 +411,15 @@ set<string> RODomainRPC::domains() { return m_domains; } +/// Access all known DNS domains +nlohmann::json RODomainRPC::domains2() { + lock_guard<mutex> lock(m_mtx); + ::lib_rtl_output(LIB_RTL_INFO,"[RODomainRPC] domains: %ld entries",m_domains.size()); + ++m_counters.numRequest; + ++m_counters.numSuccess; + return m_domains; +} + /// Access all nodes known to a DNS domain set<string> RODomainRPC::nodes(const string& dns) { set<string> res; diff --git a/Online/RPCServer/tests/src/test_jsonrpc.cpp b/Online/RPCServer/tests/src/test_jsonrpc.cpp deleted file mode 100644 index e69de29bb..000000000 -- GitLab