Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions App/Server/OpenAPIGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ using namespace DBM;

QJsonObject OpenAPIGenerator::CachedJson;

QJsonObject initializeObject()
QJsonObject initializeObject(const QString &_host = "127.0.0.1", const quint16 _port = 80)
{

if(ServerConfigs::BaseOpenAPIObjectFile.value().size()){
if (ServerConfigs::BaseOpenAPIObjectFile.value().size())
{
QFile File(ServerConfigs::BaseOpenAPIObjectFile.value());
File.open(QIODevice::ReadOnly);
if (File.isReadable() == false)
Expand All @@ -43,7 +44,9 @@ QJsonObject initializeObject()
if(JsonDoc.isNull() || JsonDoc.isObject() == false)
throw exTargomanAPI("Invalid json reading from: <" + ServerConfigs::BaseOpenAPIObjectFile.value() + ">");
return JsonDoc.object();
}else{
}
else
{
return QJsonObject({
{ "swagger","2.0" },
{ "info",QJsonObject({
Expand All @@ -52,7 +55,7 @@ QJsonObject initializeObject()
{ "description", "" },
{ "contact", QJsonObject({{"email", "sample@example.com"}}) }
}) },
{ "host", QString("127.0.0.1:%1").arg(ServerConfigs::ListenPort.value()) },
{ "host", QString("%1:%2").arg(_host).arg(_port) },
{ "securityDefinitions", QJsonObject({
{ "Bearer", QJsonObject({
{ "type", "apiKey" },
Expand All @@ -74,14 +77,20 @@ QJsonObject initializeObject()
}
}

QJsonObject OpenAPIGenerator::retrieveJson()
QJsonObject OpenAPIGenerator::retrieveJson(const QString &_host, const quint16 _port)
{
if (OpenAPIGenerator::CachedJson.isEmpty() == false)
return OpenAPIGenerator::CachedJson;
/**/
OpenAPIGenerator::CachedJson = initializeObject();
{
QJsonObject Return = OpenAPIGenerator::CachedJson;

Return["host"] = QString("%1:%2").arg(_host).arg(_port);

return Return;
}

OpenAPIGenerator::CachedJson = initializeObject(_host, _port);

if(OpenAPIGenerator::CachedJson.value("info").isObject() == false)
if (OpenAPIGenerator::CachedJson.value("info").isObject() == false)
throw exHTTPInternalServerError("Invalid OpenAPI base json");

QJsonObject PathsObject;
Expand Down
13 changes: 5 additions & 8 deletions App/Server/OpenAPIGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,25 @@
******************************************************************************/
/**
* @author S.Mehran M.Ziabary <ziabary@targoman.com>
* @author Kambiz Zandi <kambizzandi@gmail.com>
*/


#ifndef TARGOMAN_API_SERVER_OPENAPIGENERATOR_H
#define TARGOMAN_API_SERVER_OPENAPIGENERATOR_H

#include "RESTAPIRegistry.h"

namespace Targoman {
namespace API {
namespace Server {
namespace Targoman::API::Server {

class OpenAPIGenerator
{
public:
static QJsonObject retrieveJson();
static QJsonObject retrieveJson(const QString& _host = "127.0.0.1", const quint16 _port = 80);

private:
static QJsonObject CachedJson;
};

}
}
}
} //namespace Targoman::API::Server

#endif // TARGOMAN_API_SERVER_OPENAPIGENERATOR_H
68 changes: 40 additions & 28 deletions App/Server/RESTServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
#include "APICache.hpp"

namespace Targoman::API {

namespace Server {

using namespace Targoman::Common;
Expand All @@ -51,68 +50,74 @@ static WebSocketServer gWSServer;
#endif
static clsUpdateAndPruneThread *gStatUpdateThread;

void RESTServer::start(fnIsInBlackList_t _fnIPInBlackList) {
if(this->IsStarted)
throw exTargomanInitialization("QRESTServer can be started one time only");
void RESTServer::start(fnIsInBlackList_t _fnIPInBlackList)
{
if (this->IsStarted)
throw exTargomanInitialization("RESTServer can be run single instance only");

this->fnIPInBlackList = _fnIPInBlackList;

QString BasePath = ServerConfigs::BasePath.value();

if(BasePath.endsWith('/') == false)
BasePath+='/';
if (BasePath.endsWith('/') == false)
BasePath += '/';

if(BasePath.startsWith('/') == false)
BasePath='/'+BasePath;
if (BasePath.startsWith('/') == false)
BasePath = '/' + BasePath;

if(ServerConfigs::CacheConnector.value().size() && QUrl::fromUserInput(ServerConfigs::CacheConnector.value()).isValid() == false)
if (ServerConfigs::CacheConnector.value().size() && QUrl::fromUserInput(ServerConfigs::CacheConnector.value()).isValid() == false)
throw exRESTRegistry("Invalid connector url specified for central cache");

#ifdef TARGOMAN_API_REDIS_PROTOCOL
if(ServerConfigs::CacheConnector.value().startsWith(TARGOMAN_M2STR(QHTTP_REDIS_PROTOCOL)))
if (ServerConfigs::CacheConnector.value().startsWith(TARGOMAN_M2STR(QHTTP_REDIS_PROTOCOL)))
CentralCache::setup(new clsRedisConnector(ServerConfigs::CacheConnector.value()));
#endif

if(ServerConfigs::CacheConnector.value().size() && CentralCache::isValid() == false)
if (ServerConfigs::CacheConnector.value().size() && CentralCache::isValid() == false)
throw exRESTRegistry("Unsupported cache connector protocol.");

ServerConfigs::BasePathWithVersion = BasePath + ServerConfigs::Version.value();
if(ServerConfigs::BasePathWithVersion.endsWith('/') == false)
if (ServerConfigs::BasePathWithVersion.endsWith('/') == false)
ServerConfigs::BasePathWithVersion += '/';

this->IsStarted = true;

if(ServerConfigs::StatisticsInterval.value()){
if (ServerConfigs::StatisticsInterval.value())
{
gStatUpdateThread = new clsUpdateAndPruneThread();
connect(gStatUpdateThread, &clsUpdateAndPruneThread::finished, gStatUpdateThread, &QObject::deleteLater);
gStatUpdateThread->start();
}


QObject::connect(&gHTTPServer, &QHttpServer::newConnection, [this](QHttpConnection* _con){
QObject::connect(&gHTTPServer, &QHttpServer::newConnection, [this](QHttpConnection* _con)
{
if (!this->validateConnection(_con->tcpSocket()->peerAddress(), _con->tcpSocket()->peerPort()))
_con->killConnection();
});

QHostAddress ListenAddress = ServerConfigs::JustLocal.value() ? QHostAddress::LocalHost : QHostAddress::Any;

gHTTPServer.listen(ListenAddress, ServerConfigs::ListenPort.value(), [&, BasePath](QHttpRequest* _req, QHttpResponse* _res){
gHTTPServer.listen(ListenAddress, ServerConfigs::ListenPort.value(), [&, BasePath](QHttpRequest* _req, QHttpResponse* _res)
{
clsRequestHandler* RequestHandler = new clsRequestHandler(_req, _res);
try{
try
{
QString Path = _req->url().adjusted(QUrl::NormalizePathSegments |
QUrl::RemoveAuthority
).path(QUrl::PrettyDecoded);
if(Path != _req->url().path())
if (Path != _req->url().path())
return RequestHandler->redirect(Path, false);

if(ServerConfigs::PublicPath.value().size() && QFile::exists(ServerConfigs::PublicPath.value() + Path))
if (ServerConfigs::PublicPath.value().size() && QFile::exists(ServerConfigs::PublicPath.value() + Path))
return RequestHandler->sendFile(ServerConfigs::PublicPath.value(), Path);

if(Path.startsWith(BasePath) == false)
if (Path.startsWith(BasePath) == false)
return RequestHandler->sendError(qhttp::ESTATUS_NOT_FOUND, "Path not found: '" + Path + "'", true);
if(Path.startsWith(ServerConfigs::BasePathWithVersion) == false)

if (Path.startsWith(ServerConfigs::BasePathWithVersion) == false)
return RequestHandler->sendError(qhttp::ESTATUS_NOT_ACCEPTABLE, "Invalid Version or version not specified", true);
if(Path == ServerConfigs::BasePathWithVersion )

if (Path == ServerConfigs::BasePathWithVersion )
return RequestHandler->sendError(qhttp::ESTATUS_NOT_ACCEPTABLE, "No API call provided", true);

TargomanLogInfo(7,
Expand All @@ -127,14 +132,19 @@ void RESTServer::start(fnIsInBlackList_t _fnIPInBlackList) {
"?"<<
_req->url().query());
RequestHandler->process(Path.mid(ServerConfigs::BasePathWithVersion.size() - 1));
}catch(exTargomanBase& ex){
}
catch(exTargomanBase& ex)
{
RequestHandler->sendError(static_cast<qhttp::TStatusCode>(ex.httpCode()), ex.what(), ex.httpCode() >= 500);
}
});

if(gHTTPServer.isListening()){
if (gHTTPServer.isListening())
{
TargomanLogInfo(1, "REST Server is listening on "<<ListenAddress.toString()<<":"<<ServerConfigs::ListenPort.value()<<ServerConfigs::BasePathWithVersion);
}else{
}
else
{
TargomanLogError("Unable to start server to listen on "<<ListenAddress.toString()<<":"<<ServerConfigs::ListenPort.value());
QCoreApplication::exit(-1);
}
Expand All @@ -159,7 +169,7 @@ void RESTServer::stop()
#endif

this->IsStarted = false;
if(gStatUpdateThread)
if (gStatUpdateThread)
gStatUpdateThread->quit();
}

Expand All @@ -186,12 +196,14 @@ bool RESTServer::validateConnection(const QHostAddress& _peerAddress, quint16 _p
{
enuIPBlackListStatus::Type IPBlackListStatus = enuIPBlackListStatus::Unknown;

if(this->fnIPInBlackList &&
(IPBlackListStatus = this->fnIPInBlackList(_peerAddress)) != enuIPBlackListStatus::Ok){
if (this->fnIPInBlackList &&
(IPBlackListStatus = this->fnIPInBlackList(_peerAddress)) != enuIPBlackListStatus::Ok)
{
TargomanLogWarn(1,"Connection from " + _peerAddress.toString() + " was closed by security provider due to: "+enuIPBlackListStatus::toStr(IPBlackListStatus));
gServerStats.Blocked.inc();
return false;
}

gServerStats.Connections.inc();

TargomanLogInfo(7, "New connection accepted from: "<<_peerAddress.toString()<<":"<<_peerPort);
Expand Down
23 changes: 14 additions & 9 deletions App/Server/appTargomanAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,19 @@ appTargomanAPI::appTargomanAPI(QObject *parent) : QObject(parent)

void appTargomanAPI::slotExecute()
{
try {
try
{
// Load modules
QMap<QString, intfPureModule::stuDBInfo> RequiredDBs;

auto LoadedModules = Configuration::ConfigManager::instance().loadedPlugins();
if (LoadedModules.isEmpty())
throw exTargomanAPI("No module was loaded. Maybe you forgot to specify --plugins");

foreach (auto Plugin, LoadedModules) {
foreach (auto Plugin, LoadedModules)
{
intfPureModule* Module = qobject_cast<intfPureModule*>(Plugin.Instance);

if (!Module)
throw exInvalidAPIModule(QString("Seems that this an incorrect module: %1").arg(Plugin.File));

Expand All @@ -73,6 +76,7 @@ void appTargomanAPI::slotExecute()
RESTAPIRegistry::registerRESTAPI(ModuleMethod.Module, ModuleMethod.Method);

auto DBInfo = Module->requiredDB();

if (DBInfo.Schema.size())
RequiredDBs.insert(Module->moduleBaseName(), DBInfo);

Expand All @@ -91,12 +95,12 @@ void appTargomanAPI::slotExecute()
&& ServerConfigs::MasterDB::Schema.value().size())
{
intfPureModule::stuDBInfo MasterDBInfo = {
ServerConfigs::MasterDB::Schema.value(),
ServerConfigs::MasterDB::Port.value(),
ServerConfigs::MasterDB::Host.value(),
ServerConfigs::MasterDB::User.value(),
ServerConfigs::MasterDB::Pass.value()
};
ServerConfigs::MasterDB::Schema.value(),
ServerConfigs::MasterDB::Port.value(),
ServerConfigs::MasterDB::Host.value(),
ServerConfigs::MasterDB::User.value(),
ServerConfigs::MasterDB::Pass.value()
};

ConnectionStrings.insert(MasterDBInfo.toConnStr(/*true*/));
DBManager::clsDAC::setConnectionString(MasterDBInfo.toConnStr());
Expand Down Expand Up @@ -130,7 +134,8 @@ void appTargomanAPI::slotExecute()

TargomanInfo(5, "\n" + RESTAPIRegistry::registeredAPIs("", true, true).join("\n"));
}
catch(Targoman::Common::exTargomanBase& e) {
catch(Targoman::Common::exTargomanBase& e)
{
TargomanLogError(e.what());
QCoreApplication::exit(-1);
}
Expand Down
13 changes: 6 additions & 7 deletions App/Server/appTargomanAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,27 @@
******************************************************************************/
/**
* @author S. Mehran M. Ziabary <ziabary@targoman.com>
* @author Kambiz Zandi <kambizzandi@gmail.com>
*/

#ifndef TARGOMAN_API_SERVER_APPTARGOMANAPI_H
#define TARGOMAN_API_SERVER_APPTARGOMANAPI_H

#include <QObject>

namespace Targoman {
namespace API {
namespace Server {
namespace Targoman::API::Server {

class appTargomanAPI : public QObject
{
Q_OBJECT

public:
explicit appTargomanAPI(QObject *parent = nullptr);

public slots:
void slotExecute();

};

}
}
}
} //namespace Targoman::API::Server

#endif // TARGOMAN_API_SERVER_APPTARGOMANAPI_H
Loading