From 009ed54ce29f6d96c538b9a9eddd6fc39a218237 Mon Sep 17 00:00:00 2001 From: csoler Date: Sat, 23 Nov 2019 00:17:17 +0100 Subject: [PATCH] changed layout of restbed/json/webui so that JsonApi is the only server (with thread functionality in a separate class) and webui is a resource provider --- libretroshare/src/jsonapi/jsonapi.cpp | 53 +++---- libretroshare/src/jsonapi/jsonapi.h | 38 +++-- libretroshare/src/jsonapi/restbedservice.cc | 162 ++++++-------------- libretroshare/src/jsonapi/restbedservice.h | 24 ++- libretroshare/src/retroshare/rsjsonapi.h | 5 + libretroshare/src/rsserver/p3webui.cc | 21 ++- libretroshare/src/rsserver/p3webui.h | 19 ++- libretroshare/src/rsserver/rsinit.cc | 4 +- 8 files changed, 156 insertions(+), 170 deletions(-) diff --git a/libretroshare/src/jsonapi/jsonapi.cpp b/libretroshare/src/jsonapi/jsonapi.cpp index dae45308c..22cc50148 100644 --- a/libretroshare/src/jsonapi/jsonapi.cpp +++ b/libretroshare/src/jsonapi/jsonapi.cpp @@ -376,33 +376,6 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config") #include "jsonapi-wrappers.inl" } -void JsonApiServer::run() -{ - std::shared_ptr settings(new rb::Settings); - settings->set_port(mPort); - settings->set_bind_address(mBindAddress); - settings->set_default_header("Cache-Control", "no-cache"); - - { - sockaddr_storage tmp; - sockaddr_storage_inet_pton(tmp, mBindAddress); - sockaddr_storage_setport(tmp, mPort); - sockaddr_storage_ipv6_to_ipv4(tmp); - RsUrl tmpUrl(sockaddr_storage_tostring(tmp)); - tmpUrl.setScheme("http"); - - std::cerr << "JSON API listening on " << tmpUrl.toString() - << std::endl; - } - - mService.start(settings); -} - -std::vector > JsonApiServer::getResources() const -{ - return _resources; -} - void JsonApiServer::registerHandler( const std::string& path, const std::function)>& handler, @@ -630,8 +603,32 @@ void JsonApiServer::handleCorsOptions( int JsonApiServer::status() const { - if(isRunning()) + if(RestbedService::isRunning() && RestbedService::isClient(this)) return JSONAPI_STATUS_RUNNING; else return JSONAPI_STATUS_NOT_RUNNING; } + +void JsonApiServer::registerResourceProvider(const JsonApiResourceProvider *rp) +{ + _resource_providers.insert(rp); +} +void JsonApiServer::unregisterResourceProvider(const JsonApiResourceProvider *rp) +{ + _resource_providers.erase(rp); +} +bool JsonApiServer::hasResourceProvider(const JsonApiResourceProvider *rp) +{ + return _resource_providers.find(rp) != _resource_providers.end(); +} + +std::vector > JsonApiServer::getResources() const +{ + auto tab = _resources; + + for(auto& rp: _resource_providers) + for(auto r: rp->getResources()) + tab.push_back(r); + + return tab; +} diff --git a/libretroshare/src/jsonapi/jsonapi.h b/libretroshare/src/jsonapi/jsonapi.h index 84d7d5e24..f505bc009 100644 --- a/libretroshare/src/jsonapi/jsonapi.h +++ b/libretroshare/src/jsonapi/jsonapi.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "util/rsthreads.h" #include "pqi/p3cfgmgr.h" @@ -35,6 +36,16 @@ namespace rb = restbed; +class JsonApiResourceProvider +{ +public: + JsonApiResourceProvider() {} + virtual ~JsonApiResourceProvider() = default; + + virtual std::string getName() const =0; + virtual std::vector > getResources() const =0; +}; + /** * Simple usage * \code{.cpp} @@ -50,13 +61,18 @@ public: JsonApiServer() ; virtual ~JsonApiServer() = default; - // public API + // implements RestbedService - virtual bool restart() override { return RestbedService::restart();} - virtual bool stop() override { return RestbedService::stop();} - virtual void setListeningPort(uint16_t port) override { RestbedService::setListeningPort(port) ;} - virtual void setBindingAddress(const std::string& address) override { RestbedService::setBindAddress(address); } - virtual int status() const override; + virtual std::vector > getResources() const override ; + + // RsJsonAPI public API + + bool restart() override { return RestbedService::restart(); } + bool stop() override { return RestbedService::stop();} + int status() const override; + + void setListeningPort(uint16_t port) override { return RestbedService::setListeningPort(port); } + void setBindingAddress(const std::string& bind_address) override { return RestbedService::setBindAddress(bind_address); } virtual void connectToConfigManager(p3ConfigMgr *cfgmgr); @@ -66,6 +82,10 @@ public: bool isAuthTokenValid(const std::string& token) override; bool requestNewTokenAutorization(const std::string& user) override; + void registerResourceProvider(const JsonApiResourceProvider *); + void unregisterResourceProvider(const JsonApiResourceProvider *); + bool hasResourceProvider(const JsonApiResourceProvider *); + // private API. These methods may be moved to RsJsonAPI so as to be visible in http mode, if needed. /** @@ -123,7 +143,6 @@ public: protected: /// @see RsSingleJobThread virtual void run(); - virtual std::vector > getResources() const; private: @@ -141,7 +160,6 @@ private: uint16_t mPort; std::string mBindAddress; - rb::Service mService; /// Called when new JSON API auth token is requested to be authorized /// The callback supplies the password to be used to make the token @@ -167,10 +185,10 @@ private: RsGenericSerializer::SerializeContext& ctx, const std::shared_ptr session ) { - return checkRsServicePtrReady( - serviceInstance.get(), serviceName, ctx, session ); + return checkRsServicePtrReady( serviceInstance.get(), serviceName, ctx, session ); } std::vector > _resources; + std::set _resource_providers; }; diff --git a/libretroshare/src/jsonapi/restbedservice.cc b/libretroshare/src/jsonapi/restbedservice.cc index 7e609a297..7d313d970 100644 --- a/libretroshare/src/jsonapi/restbedservice.cc +++ b/libretroshare/src/jsonapi/restbedservice.cc @@ -24,127 +24,63 @@ #include "util/rsdebug.h" #include "restbedservice.h" -class RestbedThread: public RsThread -{ -public: - RestbedThread() - { - _service = std::make_shared(); // this is a place holder, in case we request some internal values. - _listening_port = 1984; - _binding_address = "127.0.0.1"; - } - - void runloop() override - { - if(_resources.empty()) - { - RsErr() << "(EE) please call RestbedService::setResources() before launching the service!" << std::endl; - return; - } - auto settings = std::make_shared< restbed::Settings >( ); - settings->set_port( _listening_port ); - settings->set_bind_address( _binding_address ); - settings->set_default_header( "Connection", "close" ); - - if(_service->is_up()) - { - std::cerr << "(II) WebUI is already running. Killing it." << std::endl; - _service->stop(); - } - - _service = std::make_shared(); - - for(auto& r:_resources) - _service->publish( r ); - - try - { - std::cerr << "(II) Starting restbed service on port " << std::dec << _listening_port << " and binding address \"" << _binding_address << "\"" << std::endl; - _service->start( settings ); - } - catch(std::exception& e) - { - RsErr() << "Could not start web interface: " << e.what() << std::endl; - return; - } - - std::cerr << "(II) restbed service stopped." << std::endl; - } - void stop() - { - _service->stop(); - - RsThread::ask_for_stop(); - - while(isRunning()) - { - std::cerr << "(II) shutting down restbed service." << std::endl; - rstime::rs_usleep(1000*1000); - } - } - - void setListeningPort(uint16_t p) { _listening_port = p ; } - void setBindAddress(const std::string& bindAddress) { _binding_address = bindAddress ; } - void setResources(const std::vector >& r) { _resources = r ; } - uint16_t listeningPort() const { return _listening_port;} - -private: - std::shared_ptr _service; - std::vector > _resources; - - uint16_t _listening_port; - std::string _binding_address; -}; - RestbedService::RestbedService() { - _restbed_thread = new RestbedThread(); + mService = std::make_shared(); // this is a place holder, in case we request some internal values. + mListeningPort = 9092; + mBindingAddress = "127.0.0.1"; } -RestbedService::~RestbedService() + +void RestbedService::stop() { - while(_restbed_thread->isRunning()) - { - stop(); - std::cerr << "Deleting webUI object while webUI thread is still running. Trying shutdown...." << std::endl; + mService->stop(); + + RsThread::ask_for_stop(); + + while(isRunning()) + { + std::cerr << "(II) shutting down restbed service." << std::endl; rstime::rs_usleep(1000*1000); - } - delete _restbed_thread; + } } -bool RestbedService::restart() +void RestbedService::setListeningPort(uint16_t p) { mListeningPort = p ; } +void RestbedService::setBindAddress(const std::string& bindAddress) { mBindingAddress = bindAddress ; } +uint16_t RestbedService::listeningPort() const { return mListeningPort;} + +void RestbedService::runloop() override { - RsDbg() << "Restarting restbed service listening on port " << _restbed_thread->listeningPort() << std::endl; + if(_resources.empty()) + { + RsErr() << "(EE) please call RestbedService::setResources() before launching the service!" << std::endl; + return; + } + auto settings = std::make_shared< restbed::Settings >( ); + settings->set_port( mListeningPort ); + settings->set_bind_address( mBindingAddress ); + settings->set_default_header( "Connection", "close" ); - if(_restbed_thread->isRunning()) - _restbed_thread->stop(); + if(mService->is_up()) + { + std::cerr << "(II) WebUI is already running. Killing it." << std::endl; + mService->stop(); + } - _restbed_thread->setResources(getResources()); - _restbed_thread->start(); - return true; + mService = std::make_shared(); // re-allocating mService is important because it deletes the existing service and therefore leaves the listening port open + + for(auto& r:getResources()) + mService->publish(r); + + try + { + std::cerr << "(II) Starting restbed service on port " << std::dec << mListeningPort << " and binding address \"" << mBindingAddress << "\"" << std::endl; + mService->start( settings ); + } + catch(std::exception& e) + { + RsErr() << "Could not start web interface: " << e.what() << std::endl; + return; + } + + std::cerr << "(II) restbed service stopped." << std::endl; } - -bool RestbedService::stop() -{ - _restbed_thread->stop(); - return true; -} -bool RestbedService::isRunning() const -{ - return _restbed_thread->isRunning(); -} -void RestbedService::setListeningPort(uint16_t port) -{ - _restbed_thread->setListeningPort(port); - - if(_restbed_thread->isRunning()) - restart(); -} - -void RestbedService::setBindAddress(const std::string& bind_address) -{ - _restbed_thread->setBindAddress(bind_address); - - if(_restbed_thread->isRunning()) - restart(); -} - diff --git a/libretroshare/src/jsonapi/restbedservice.h b/libretroshare/src/jsonapi/restbedservice.h index 79efd9660..93b2c805b 100644 --- a/libretroshare/src/jsonapi/restbedservice.h +++ b/libretroshare/src/jsonapi/restbedservice.h @@ -23,26 +23,34 @@ #pragma once #include +#include "util/rsthreads.h" class RestbedThread; -class RestbedService +class RestbedService: public RsThread { public: RestbedService() ; virtual ~RestbedService(); - bool isRunning() const ; + bool restart(); + bool stop(); + bool isRunning(); - virtual bool restart(); - virtual bool stop(); + void setListeningPort(uint16_t port) ; + void setBindAddress(const std::string& bind_address); - virtual void setListeningPort(uint16_t port) ; - virtual void setBindAddress(const std::string& bind_address); + // should be overloaded by sub-class in order to provide resources to the restbed Service. - virtual std::vector > getResources()const =0; + virtual std::vector > getResources() const = 0; + +protected: + void runloop() override; private: - RestbedThread *_restbed_thread; + std::shared_ptr mService; // managed by RestbedService because it needs to be properly deleted when restarted. + + uint16_t mListeningPort; + std::string mBindingAddress; }; diff --git a/libretroshare/src/retroshare/rsjsonapi.h b/libretroshare/src/retroshare/rsjsonapi.h index 9b82b63f2..2ed67aeca 100644 --- a/libretroshare/src/retroshare/rsjsonapi.h +++ b/libretroshare/src/retroshare/rsjsonapi.h @@ -23,6 +23,7 @@ #include class p3ConfigMgr; +class JsonApiResourceProvider; class RsJsonAPI { @@ -44,6 +45,10 @@ public: virtual void connectToConfigManager(p3ConfigMgr *cfgmgr)=0; + virtual void registerResourceProvider(const JsonApiResourceProvider *)=0; + virtual void unregisterResourceProvider(const JsonApiResourceProvider *)=0; + virtual bool hasResourceProvider(const JsonApiResourceProvider *)=0; + /** * @brief Get status of the json api server * @jsonapi{development} diff --git a/libretroshare/src/rsserver/p3webui.cc b/libretroshare/src/rsserver/p3webui.cc index 688bcdd7b..68bdbf93d 100644 --- a/libretroshare/src/rsserver/p3webui.cc +++ b/libretroshare/src/rsserver/p3webui.cc @@ -136,7 +136,7 @@ void p3WebUI::setHtmlFilesDirectory(const std::string& html_dir) int p3WebUI::status() const { - if(isRunning()) + if(rsJsonAPI->status()==RsJsonAPI::JSONAPI_STATUS_RUNNING && rsJsonAPI->hasResourceProvider(this)) return WEBUI_STATUS_RUNNING; else return WEBUI_STATUS_NOT_RUNNING; @@ -153,3 +153,22 @@ void p3WebUI::setUserPassword(const std::string& passwd) std::cerr << "(EE) JsonAPI is not available in this buildof Retroshare! Cannot register a user password for the WebUI" << std::endl; #endif } + +bool p3WebUI::restart() +{ + rsJsonAPI->registerResourceProvider(this); + + return rsJsonAPI->restart(); +} + +bool p3WebUI::stop() +{ + rsJsonAPI->unregisterResourceProvider(this); + + if(rsJsonAPI->status()==RsJsonAPI::JSONAPI_STATUS_RUNNING) + return rsJsonAPI->restart(); + else + return true; +} + + diff --git a/libretroshare/src/rsserver/p3webui.h b/libretroshare/src/rsserver/p3webui.h index aaeb7bb7c..d6ccbe778 100644 --- a/libretroshare/src/rsserver/p3webui.h +++ b/libretroshare/src/rsserver/p3webui.h @@ -24,23 +24,26 @@ #include #include #include "retroshare/rswebui.h" -#include "jsonapi/restbedservice.h" +#include "jsonapi/jsonapi.h" -class p3WebUI: public RsWebUI, public RestbedService +class p3WebUI: public RsWebUI, public JsonApiResourceProvider { public: p3WebUI(){} virtual ~p3WebUI(){} - virtual void setHtmlFilesDirectory(const std::string& html_dir) override; + // implements RsWebUI - virtual bool restart() override { return RestbedService::restart();} - virtual bool stop() override { return RestbedService::stop();} - virtual void setListeningPort(uint16_t port) override { RestbedService::setListeningPort(port) ;} - virtual void setBindingAddress(const std::string& address) override { RestbedService::setBindAddress(address) ;} + virtual void setHtmlFilesDirectory(const std::string& html_dir) override; virtual void setUserPassword(const std::string& passwd) override; - virtual int status() const override; + virtual bool restart() override ; + virtual bool stop() override ; + virtual int status() const override; + + // implements JsonApiResourceProvider + + virtual std::string getName() const override { return "Web Interface" ;} virtual std::vector > getResources() const override; }; diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index 13f15d3c2..5d529c816 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -398,9 +398,9 @@ int RsInit::InitRetroShare(const RsConfigOptions& conf) RsInfo() << "Allocating jsonAPI server (not launched yet) " << std::endl; JsonApiServer *jas = new JsonApiServer(); jas->setListeningPort(conf.jsonApiPort); - jas->setBindingAddress(conf.jsonApiBindAddress); + jas->setBindAddress(conf.jsonApiBindAddress); - if(conf.jsonApiPort != NULL) + if(conf.jsonApiPort != 0) { RsInfo() << "Launching jsonAPI server on port " << conf.jsonApiPort << std::endl; jas->restart();