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

This commit is contained in:
csoler 2019-11-23 00:17:17 +01:00
parent 997501a24d
commit 009ed54ce2
No known key found for this signature in database
GPG Key ID: 7BCA522266C0804C
8 changed files with 156 additions and 170 deletions

View File

@ -376,33 +376,6 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config")
#include "jsonapi-wrappers.inl"
}
void JsonApiServer::run()
{
std::shared_ptr<rb::Settings> 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<std::shared_ptr<restbed::Resource> > JsonApiServer::getResources() const
{
return _resources;
}
void JsonApiServer::registerHandler(
const std::string& path,
const std::function<void (const std::shared_ptr<restbed::Session>)>& 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<std::shared_ptr<rb::Resource> > JsonApiServer::getResources() const
{
auto tab = _resources;
for(auto& rp: _resource_providers)
for(auto r: rp->getResources())
tab.push_back(r);
return tab;
}

View File

@ -24,6 +24,7 @@
#include <restbed>
#include <cstdint>
#include <map>
#include <set>
#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<std::shared_ptr<rb::Resource> > 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<std::shared_ptr<rb::Resource> > 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<std::shared_ptr<rb::Resource> > 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<rb::Session> session )
{
return checkRsServicePtrReady(
serviceInstance.get(), serviceName, ctx, session );
return checkRsServicePtrReady( serviceInstance.get(), serviceName, ctx, session );
}
std::vector<std::shared_ptr<rb::Resource> > _resources;
std::set<JsonApiResourceProvider *> _resource_providers;
};

View File

@ -24,127 +24,63 @@
#include "util/rsdebug.h"
#include "restbedservice.h"
class RestbedThread: public RsThread
{
public:
RestbedThread()
{
_service = std::make_shared<restbed::Service>(); // 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<restbed::Service>();
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<std::shared_ptr<restbed::Resource> >& r) { _resources = r ; }
uint16_t listeningPort() const { return _listening_port;}
private:
std::shared_ptr<restbed::Service> _service;
std::vector<std::shared_ptr<restbed::Resource> > _resources;
uint16_t _listening_port;
std::string _binding_address;
};
RestbedService::RestbedService()
{
_restbed_thread = new RestbedThread();
mService = std::make_shared<restbed::Service>(); // 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<restbed::Service>(); // 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();
}

View File

@ -23,26 +23,34 @@
#pragma once
#include <restbed>
#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<std::shared_ptr<restbed::Resource> > getResources()const =0;
virtual std::vector<std::shared_ptr<restbed::Resource> > getResources() const = 0;
protected:
void runloop() override;
private:
RestbedThread *_restbed_thread;
std::shared_ptr<restbed::Service> mService; // managed by RestbedService because it needs to be properly deleted when restarted.
uint16_t mListeningPort;
std::string mBindingAddress;
};

View File

@ -23,6 +23,7 @@
#include <string>
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}

View File

@ -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;
}

View File

@ -24,23 +24,26 @@
#include <vector>
#include <memory>
#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<std::shared_ptr<restbed::Resource> > getResources() const override;
};

View File

@ -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();