Added a prettier web interface placeholder

This commit is contained in:
Leon Etienne (ubuntu wsl) 2020-09-24 18:54:34 +02:00
parent 99c429872b
commit 4f68951725
23 changed files with 716 additions and 187 deletions

5
.gitignore vendored
View File

@ -10,6 +10,11 @@
*.userosscache *.userosscache
*.sln.docstates *.sln.docstates
# Tubio files
config.json
log.txt
log.json
# User-specific files (MonoDevelop/Xamarin Studio) # User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs *.userprefs

62
Tubio/FileSystem.cpp Normal file
View File

@ -0,0 +1,62 @@
#include "Filesystem.h"
std::string FileSystem::ReadFile(std::string filename)
{
std::ifstream ifs;
ifs.open(filename, std::ios::in);
if (!ifs.good())
{
throw std::exception("no such file");
std::terminate();
}
std::string buf;
std::stringstream content;
while (std::getline(ifs, buf))
{
content << buf;
}
return content.str();
}
bool FileSystem::WriteFile(std::string filename, std::string content)
{
std::ofstream ofs;
if (!ofs.good()) return false;
ofs.open(filename, std::ios::out);
ofs << content;
ofs.close();
return true;
}
bool FileSystem::Exists(std::string filename)
{
std::ifstream ifs;
ifs.open(filename, std::ios::in);
if (!ifs.good()) return false;
ifs.close();
return true;
}
bool FileSystem::Copy(std::string from, std::string to)
{
std::ifstream ifs;
if (!ifs.good()) return false;
ifs.open(from, std::ios::in | std::ios::binary);
std::ofstream ofs;
if (!ofs.good()) return false;
ofs.open(to, std::ios::out | std::ios::binary);
std::copy(std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(ofs));
return true;
}
bool FileSystem::Delete(std::string filename)
{
if (!Exists(filename)) return false;
remove(filename.c_str());
return true;
}

20
Tubio/FileSystem.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <string>
#include <fstream>
#include <sstream>
#include <stdio.h>
class FileSystem
{
public:
static std::string ReadFile(std::string filename);
static bool WriteFile(std::string filename, std::string content);
static bool Exists(std::string filename);
static bool Copy(std::string from, std::string to);
static bool Delete(std::string filename);
private:
};

View File

@ -11,7 +11,7 @@ Framework::Framework()
log->cout << "Starting Tubio server..."; log->cout << "Starting Tubio server...";
log->Flush(); log->Flush();
restInterface = new RestInterface(); httpServer = new HttpServer();
PostInit(); PostInit();
@ -23,10 +23,10 @@ Framework::Framework()
Framework::~Framework() Framework::~Framework()
{ {
delete restInterface; delete httpServer;
delete log; delete log;
restInterface = nullptr; httpServer = nullptr;
log = nullptr; log = nullptr;
return; return;
@ -36,7 +36,7 @@ void Framework::Run()
{ {
while (XGControl::keepServerRunning) while (XGControl::keepServerRunning)
{ {
restInterface->Update(); httpServer->Update();
} }
OnExit(); OnExit();
@ -50,6 +50,7 @@ void Framework::Run()
void Framework::PreInit() void Framework::PreInit()
{ {
LogHistory::PreInit(); LogHistory::PreInit();
XGConfig::PreInit();
RestQueryHandler::PreInit(); RestQueryHandler::PreInit();
return; return;
@ -58,22 +59,23 @@ void Framework::PreInit()
void Framework::PostInit() void Framework::PostInit()
{ {
restInterface->PostInit(); httpServer->PostInit();
return; return;
} }
void Framework::OnExit() void Framework::OnExit()
{ {
restInterface->OnExit(); httpServer->OnExit();
return; return;
} }
void Framework::PostExit() void Framework::PostExit()
{ {
LogHistory::PostExit(); XGConfig::PostExit();
RestQueryHandler::PostExit(); RestQueryHandler::PostExit();
LogHistory::PostExit();
return; return;
} }

View File

@ -1,8 +1,9 @@
#pragma once #pragma once
#include "Logger.h" #include "Logger.h"
#include "LogHistory.h" #include "LogHistory.h"
#include "RestInterface.h" #include "HttpServer.h"
#include "XGControl.h" #include "XGControl.h"
#include "XGConfig.h"
class Framework class Framework
{ {
@ -18,7 +19,7 @@ private:
void PreInit(); void PreInit();
void PostExit(); void PostExit();
Rest::RestInterface* restInterface; Rest::HttpServer* httpServer;
Logging::Logger* log; Logging::Logger* log;

View File

@ -1,10 +1,10 @@
#include "RestInterface.h" #include "HttpServer.h"
using namespace Logging; using namespace Logging;
using namespace Rest; using namespace Rest;
using namespace JasonPP; using namespace JasonPP;
RestInterface::RestInterface() HttpServer::HttpServer()
{ {
pMgr = new mg_mgr(); pMgr = new mg_mgr();
pNc = nullptr; pNc = nullptr;
@ -13,7 +13,7 @@ RestInterface::RestInterface()
return; return;
} }
RestInterface::~RestInterface() HttpServer::~HttpServer()
{ {
delete pMgr; delete pMgr;
delete log; delete log;
@ -24,31 +24,31 @@ RestInterface::~RestInterface()
return; return;
} }
void RestInterface::PostInit() void HttpServer::PostInit()
{ {
isBootedSuccessfully = InitWebServer(); isBootedSuccessfully = InitWebServer();
return; return;
} }
bool RestInterface::InitWebServer() bool HttpServer::InitWebServer()
{ {
mg_mgr_init(pMgr, NULL); mg_mgr_init(pMgr, NULL);
log->cout << "Starting rest api server on port " << WEBAPI_SERVER_PORT << "..."; log->cout << "Starting rest api server on port " << XGConfig::httpServer.port << "...";
log->Flush(); log->Flush();
pNc = mg_bind(pMgr, WEBAPI_SERVER_PORT, this->EventHandler); pNc = mg_bind(pMgr, XGConfig::httpServer.port.c_str(), this->EventHandler);
if (pNc == NULL) if (pNc == NULL)
{ {
log->cout << log->Err() << "Failed to boot rest api web server! - Unable to bind listener! (port: " << WEBAPI_SERVER_PORT << ")"; log->cout << log->Err() << "Failed to boot the http server! - Unable to bind listener! (port: " << XGConfig::httpServer.port << ")";
log->Flush(); log->Flush();
return false; return false;
} }
mg_set_protocol_http_websocket(pNc); mg_set_protocol_http_websocket(pNc);
frontend_serve_opts.document_root = "frontend"; frontend_serve_opts.document_root = XGConfig::httpServer.rootdir.c_str();
frontend_serve_opts.enable_directory_listing = "no"; frontend_serve_opts.enable_directory_listing = "no";
log->cout << "Started web server successfully!"; log->cout << "Started web server successfully!";
@ -58,14 +58,14 @@ bool RestInterface::InitWebServer()
return true; return true;
} }
void RestInterface::Update() void HttpServer::Update()
{ {
mg_mgr_poll(pMgr, WEBAPI_SERVER_POLLRATE); mg_mgr_poll(pMgr, XGConfig::httpServer.pollingRate);
return; return;
} }
void RestInterface::ServeStringToConnection(struct mg_connection* c, std::string str, int httpStatusCode) void HttpServer::ServeStringToConnection(struct mg_connection* c, std::string str, int httpStatusCode)
{ {
mg_send_head(c, httpStatusCode, str.length(), "content-type: application/json\nAccess-Control-Allow-Origin: *"); mg_send_head(c, httpStatusCode, str.length(), "content-type: application/json\nAccess-Control-Allow-Origin: *");
mg_printf(c, str.c_str()); mg_printf(c, str.c_str());
@ -73,7 +73,7 @@ void RestInterface::ServeStringToConnection(struct mg_connection* c, std::string
return; return;
} }
void RestInterface::EventHandler(mg_connection* pNc, int ev, void* p) void HttpServer::EventHandler(mg_connection* pNc, int ev, void* p)
{ {
switch (ev) switch (ev)
{ {
@ -98,7 +98,7 @@ void RestInterface::EventHandler(mg_connection* pNc, int ev, void* p)
return; return;
} }
void RestInterface::ProcessAPIRequest(mg_connection* pNc, int ev, void* p) void HttpServer::ProcessAPIRequest(mg_connection* pNc, int ev, void* p)
{ {
// Get struct with http message informations // Get struct with http message informations
http_message* hpm = (http_message*)p; http_message* hpm = (http_message*)p;
@ -131,7 +131,7 @@ void RestInterface::ProcessAPIRequest(mg_connection* pNc, int ev, void* p)
return; return;
} }
void RestInterface::OnExit() void HttpServer::OnExit()
{ {
log->cout << "Shutting down rest api server..."; log->cout << "Shutting down rest api server...";
log->Flush(); log->Flush();
@ -142,7 +142,7 @@ void RestInterface::OnExit()
} }
std::string RestInterface::FixUnterminatedString(const char* cstr, const std::size_t len) std::string HttpServer::FixUnterminatedString(const char* cstr, const std::size_t len)
{ {
std::stringstream ss; std::stringstream ss;
for (std::size_t i = 0; i < len; i++) for (std::size_t i = 0; i < len; i++)
@ -153,4 +153,4 @@ std::string RestInterface::FixUnterminatedString(const char* cstr, const std::si
return ss.str(); return ss.str();
} }
mg_serve_http_opts RestInterface::frontend_serve_opts; mg_serve_http_opts HttpServer::frontend_serve_opts;

View File

@ -6,17 +6,15 @@
#include "Logger.h" #include "Logger.h"
#include "RestResponseTemplates.h" #include "RestResponseTemplates.h"
#include "RestQueryHandler.h" #include "RestQueryHandler.h"
#include "XGConfig.h"
#define WEBAPI_SERVER_POLLRATE 100
#define WEBAPI_SERVER_PORT "6969"
namespace Rest namespace Rest
{ {
class RestInterface class HttpServer
{ {
public: public:
RestInterface(); HttpServer();
~RestInterface(); ~HttpServer();
void PostInit(); void PostInit();
void Update(); void Update();

View File

@ -262,7 +262,7 @@ std::size_t JsonArray::RemoveSimilar(const JsonData reference)
return counter; return counter;
} }
std::size_t JsonArray::RemoveAllOfType(const JSON_DATA_TYPE type) std::size_t JsonArray::RemoveAllOfType(const JDType type)
{ {
std::size_t counter = 0; std::size_t counter = 0;
for (long long int i = content->size() - 1; i >= 0; i--) for (long long int i = content->size() - 1; i >= 0; i--)
@ -277,7 +277,7 @@ std::size_t JsonArray::RemoveAllOfType(const JSON_DATA_TYPE type)
return counter; return counter;
} }
std::size_t JsonArray::RemoveAllExceptType(const JSON_DATA_TYPE type) std::size_t JsonArray::RemoveAllExceptType(const JDType type)
{ {
std::size_t counter = 0; std::size_t counter = 0;
for (long long int i = content->size() - 1; i >= 0; i--) for (long long int i = content->size() - 1; i >= 0; i--)
@ -524,7 +524,7 @@ void JsonArray::Sort(const std::string shorthandKey, const JSON_ARRAY_SORT_MODE
const JsonData* b = &At(j + 1); const JsonData* b = &At(j + 1);
// Check if they are of type json (this is the json sorter) (deep sort) // Check if they are of type json (this is the json sorter) (deep sort)
if ((a->GetDataType() == JSON_DATA_TYPE::JSON) && (b->GetDataType() == JSON_DATA_TYPE::JSON)) if ((a->GetDataType() == JDType::JSON) && (b->GetDataType() == JDType::JSON))
{ {
// Check if the requested key even exists // Check if the requested key even exists
if ((a->GetJsonData().DoesShorthandExist(shorthandKey, shorthandDelimiter)) && if ((a->GetJsonData().DoesShorthandExist(shorthandKey, shorthandDelimiter)) &&
@ -560,8 +560,8 @@ void JsonArray::Sort(const JSON_ARRAY_SORT_MODE mode)
// Only if neither a or b's are neither of type json or array // Only if neither a or b's are neither of type json or array
// This is the "shallow"-sort // This is the "shallow"-sort
if (!(((a.GetDataType() == JSON_DATA_TYPE::JSON) || (a.GetDataType() == JSON_DATA_TYPE::ARRAY)) && if (!(((a.GetDataType() == JDType::JSON) || (a.GetDataType() == JDType::ARRAY)) &&
((b.GetDataType() == JSON_DATA_TYPE::JSON) || (b.GetDataType() == JSON_DATA_TYPE::ARRAY)))) ((b.GetDataType() == JDType::JSON) || (b.GetDataType() == JDType::ARRAY))))
{ {
if (Sort__Compare(a, b, mode)) if (Sort__Compare(a, b, mode))
{ {
@ -590,11 +590,11 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
// If it's BOOL, INT or FLOAT, just get it's value as string. Eg "53", "53.2" or "false" // If it's BOOL, INT or FLOAT, just get it's value as string. Eg "53", "53.2" or "false"
// This way numerics can still be sorted alphabetically // This way numerics can still be sorted alphabetically
// Also allows for sorting after bools // Also allows for sorting after bools
if (a.GetDataType() == JSON_DATA_TYPE::STRING) aStr = a.GetStringData(); if (a.GetDataType() == JDType::STRING) aStr = a.GetStringData();
else if ((a.GetDataType() != JSON_DATA_TYPE::JSON) && (a.GetDataType() != JSON_DATA_TYPE::ARRAY)) aStr = a.Render(); else if ((a.GetDataType() != JDType::JSON) && (a.GetDataType() != JDType::ARRAY)) aStr = a.Render();
else return true; // Datatype invalid. Swap, to keep the others in order. else return true; // Datatype invalid. Swap, to keep the others in order.
if (b.GetDataType() == JSON_DATA_TYPE::STRING) bStr = b.GetStringData(); if (b.GetDataType() == JDType::STRING) bStr = b.GetStringData();
else if ((b.GetDataType() != JSON_DATA_TYPE::JSON) && (b.GetDataType() != JSON_DATA_TYPE::ARRAY)) bStr = b.Render(); else if ((b.GetDataType() != JDType::JSON) && (b.GetDataType() != JDType::ARRAY)) bStr = b.Render();
else return true; // Datatype invalid. Swap, to keep the others in order. else return true; // Datatype invalid. Swap, to keep the others in order.
return StringHelpers::SortDescriminator_Alphabetically(aStr, bStr); return StringHelpers::SortDescriminator_Alphabetically(aStr, bStr);
@ -612,11 +612,11 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
// If it's BOOL, INT or FLOAT, just get it's value as string. Eg "53", "53.2" or "false" // If it's BOOL, INT or FLOAT, just get it's value as string. Eg "53", "53.2" or "false"
// This way numerics can still be sorted alphabetically // This way numerics can still be sorted alphabetically
// Also allows for sorting after bools // Also allows for sorting after bools
if (a.GetDataType() == JSON_DATA_TYPE::STRING) aStr = a.GetStringData(); if (a.GetDataType() == JDType::STRING) aStr = a.GetStringData();
else if ((a.GetDataType() != JSON_DATA_TYPE::JSON) && (a.GetDataType() != JSON_DATA_TYPE::ARRAY)) aStr = a.Render(); else if ((a.GetDataType() != JDType::JSON) && (a.GetDataType() != JDType::ARRAY)) aStr = a.Render();
else return true; // Datatype invalid. Swap, to keep the others in order. else return true; // Datatype invalid. Swap, to keep the others in order.
if (b.GetDataType() == JSON_DATA_TYPE::STRING) bStr = b.GetStringData(); if (b.GetDataType() == JDType::STRING) bStr = b.GetStringData();
else if ((b.GetDataType() != JSON_DATA_TYPE::JSON) && (b.GetDataType() != JSON_DATA_TYPE::ARRAY)) bStr = b.Render(); else if ((b.GetDataType() != JDType::JSON) && (b.GetDataType() != JDType::ARRAY)) bStr = b.Render();
else return true; // Datatype invalid. Swap, to keep the others in order. else return true; // Datatype invalid. Swap, to keep the others in order.
return StringHelpers::SortDescriminator_Alphabetically(bStr, aStr); return StringHelpers::SortDescriminator_Alphabetically(bStr, aStr);
@ -631,13 +631,13 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
switch (a.GetDataType()) switch (a.GetDataType())
{ {
case JSON_DATA_TYPE::INT: case JDType::INT:
dataA = (long double)a.GetIntData(); dataA = (long double)a.GetIntData();
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
dataA = a.GetFloatData(); dataA = a.GetFloatData();
break; break;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
dataA = a.GetBoolData() ? 1.0 : 0.0; dataA = a.GetBoolData() ? 1.0 : 0.0;
break; break;
default: default:
@ -645,13 +645,13 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
} }
switch (b.GetDataType()) switch (b.GetDataType())
{ {
case JSON_DATA_TYPE::INT: case JDType::INT:
dataB = (long double)b.GetIntData(); dataB = (long double)b.GetIntData();
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
dataB = b.GetFloatData(); dataB = b.GetFloatData();
break; break;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
dataB = b.GetBoolData() ? 1.0 : 0.0; dataB = b.GetBoolData() ? 1.0 : 0.0;
break; break;
default: default:
@ -669,13 +669,13 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
switch (a.GetDataType()) switch (a.GetDataType())
{ {
case JSON_DATA_TYPE::INT: case JDType::INT:
dataA = (long double)a.GetIntData(); dataA = (long double)a.GetIntData();
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
dataA = a.GetFloatData(); dataA = a.GetFloatData();
break; break;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
dataA = a.GetBoolData() ? 1.0 : 0.0; dataA = a.GetBoolData() ? 1.0 : 0.0;
break; break;
default: default:
@ -683,13 +683,13 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
} }
switch (b.GetDataType()) switch (b.GetDataType())
{ {
case JSON_DATA_TYPE::INT: case JDType::INT:
dataB = (long double)b.GetIntData(); dataB = (long double)b.GetIntData();
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
dataB = b.GetFloatData(); dataB = b.GetFloatData();
break; break;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
dataB = b.GetBoolData() ? 1.0 : 0.0; dataB = b.GetBoolData() ? 1.0 : 0.0;
break; break;
default: default:
@ -753,7 +753,7 @@ JsonArray& JsonArray::operator-=(const JsonData& data)
return *this; return *this;
} }
JsonArray& JsonArray::operator-=(const JSON_DATA_TYPE type) JsonArray& JsonArray::operator-=(const JDType type)
{ {
RemoveAllOfType(type); RemoveAllOfType(type);
return *this; return *this;
@ -1031,29 +1031,29 @@ bool JasonPP::IsJsonValid(const std::string code)
return true; return true;
} }
std::string JasonPP::JsonDataType2String(const JSON_DATA_TYPE type) std::string JasonPP::JsonDataType2String(const JDType type)
{ {
switch (type) switch (type)
{ {
case JSON_DATA_TYPE::__NULL__: case JDType::__NULL__:
return std::string("NULL"); return std::string("NULL");
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
return std::string("BOOL"); return std::string("BOOL");
case JSON_DATA_TYPE::INT: case JDType::INT:
return std::string("INT"); return std::string("INT");
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
return std::string("FLOAT"); return std::string("FLOAT");
case JSON_DATA_TYPE::STRING: case JDType::STRING:
return std::string("STRING"); return std::string("STRING");
case JSON_DATA_TYPE::JSON: case JDType::JSON:
return std::string("JSON"); return std::string("JSON");
case JSON_DATA_TYPE::ARRAY: case JDType::ARRAY:
return std::string("ARRAY"); return std::string("ARRAY");
} }
@ -1457,37 +1457,37 @@ JsonData::JsonData()
} }
// Set default data per type // Set default data per type
JsonData::JsonData(const JSON_DATA_TYPE type) JsonData::JsonData(const JDType type)
{ {
Init(); Init();
switch (type) switch (type)
{ {
case JSON_DATA_TYPE::__NULL__: case JDType::__NULL__:
// Default value is already NULL // Default value is already NULL
break; break;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
SetBoolData(false); SetBoolData(false);
break; break;
case JSON_DATA_TYPE::INT: case JDType::INT:
SetIntData(0); SetIntData(0);
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
SetFloatData(0); SetFloatData(0);
break; break;
case JSON_DATA_TYPE::STRING: case JDType::STRING:
SetStringData(""); SetStringData("");
break; break;
case JSON_DATA_TYPE::JSON: case JDType::JSON:
SetJsonDataAsPointer(new JsonBlock()); SetJsonDataAsPointer(new JsonBlock());
break; break;
case JSON_DATA_TYPE::ARRAY: case JDType::ARRAY:
SetArrayDataAsPointer(new JsonArray()); SetArrayDataAsPointer(new JsonArray());
break; break;
} }
@ -1602,7 +1602,7 @@ void JsonData::SetFloatPrecision(const double precision)
JsonArray& JsonData::SetArrayDataAsPointer(JsonArray* p) JsonArray& JsonData::SetArrayDataAsPointer(JsonArray* p)
{ {
dataType = JSON_DATA_TYPE::ARRAY; dataType = JDType::ARRAY;
if (arrayData != nullptr) if (arrayData != nullptr)
{ {
@ -1617,7 +1617,7 @@ JsonArray& JsonData::SetArrayDataAsPointer(JsonArray* p)
JsonBlock& JsonData::SetJsonDataAsPointer(JsonBlock* p) JsonBlock& JsonData::SetJsonDataAsPointer(JsonBlock* p)
{ {
dataType = JSON_DATA_TYPE::JSON; dataType = JDType::JSON;
if (jsonData != nullptr) if (jsonData != nullptr)
{ {
@ -1631,7 +1631,7 @@ JsonBlock& JsonData::SetJsonDataAsPointer(JsonBlock* p)
void JsonData::Init() void JsonData::Init()
{ {
dataType = JSON_DATA_TYPE::__NULL__; dataType = JDType::__NULL__;
intData = 0l; intData = 0l;
floatData = 0.0f; floatData = 0.0f;
stringData = std::string(); stringData = std::string();
@ -1686,12 +1686,12 @@ double JsonData::GetFloatPrecision() const
bool JsonData::IsOfNumericType() const bool JsonData::IsOfNumericType() const
{ {
return (dataType == JSON_DATA_TYPE::INT) || (dataType == JSON_DATA_TYPE::FLOAT); return (dataType == JDType::INT) || (dataType == JDType::FLOAT);
} }
bool JsonData::GetBoolData() const bool JsonData::GetBoolData() const
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::BOOL; JDType typeToGet = JDType::BOOL;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet); if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
@ -1700,11 +1700,11 @@ bool JsonData::GetBoolData() const
long long int JsonData::GetIntData() const long long int JsonData::GetIntData() const
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::INT; JDType typeToGet = JDType::INT;
if (dataType != typeToGet) if (dataType != typeToGet)
{ {
if (dataType == JSON_DATA_TYPE::FLOAT) if (dataType == JDType::FLOAT)
{ {
return (long long int)floatData; return (long long int)floatData;
} }
@ -1719,11 +1719,11 @@ long long int JsonData::GetIntData() const
long double JsonData::GetFloatData() const long double JsonData::GetFloatData() const
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::FLOAT; JDType typeToGet = JDType::FLOAT;
if (dataType != typeToGet) if (dataType != typeToGet)
{ {
if (dataType == JSON_DATA_TYPE::INT) if (dataType == JDType::INT)
{ {
return (float)intData; return (float)intData;
} }
@ -1738,7 +1738,7 @@ long double JsonData::GetFloatData() const
std::string JsonData::GetStringData() const std::string JsonData::GetStringData() const
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::STRING; JDType typeToGet = JDType::STRING;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet); if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
@ -1747,35 +1747,35 @@ std::string JsonData::GetStringData() const
JsonBlock& JsonData::GetJsonData() JsonBlock& JsonData::GetJsonData()
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::JSON; JDType typeToGet = JDType::JSON;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet); if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *jsonData; return *jsonData;
} }
const JsonBlock& JsonData::GetJsonData() const const JsonBlock& JsonData::GetJsonData() const
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::JSON; JDType typeToGet = JDType::JSON;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet); if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *jsonData; return *jsonData;
} }
JsonArray& JsonData::GetArrayData() JsonArray& JsonData::GetArrayData()
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::ARRAY; JDType typeToGet = JDType::ARRAY;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet); if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *arrayData; return *arrayData;
} }
const JsonArray& JsonData::GetArrayData() const const JsonArray& JsonData::GetArrayData() const
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::ARRAY; JDType typeToGet = JDType::ARRAY;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet); if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *arrayData; return *arrayData;
} }
short JsonData::GetNullData() short JsonData::GetNullData()
{ {
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::__NULL__; JDType typeToGet = JDType::__NULL__;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet); if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
@ -1803,7 +1803,7 @@ bool JsonData::HasParent() const
void JsonData::SetBoolData(const bool data) void JsonData::SetBoolData(const bool data)
{ {
dataType = JSON_DATA_TYPE::BOOL; dataType = JDType::BOOL;
intData = (int)data; intData = (int)data;
return; return;
@ -1811,7 +1811,7 @@ void JsonData::SetBoolData(const bool data)
void JsonData::SetIntData(const long long int data) void JsonData::SetIntData(const long long int data)
{ {
dataType = JSON_DATA_TYPE::INT; dataType = JDType::INT;
intData = data; intData = data;
return; return;
@ -1819,7 +1819,7 @@ void JsonData::SetIntData(const long long int data)
void JsonData::SetIntData(const int data) void JsonData::SetIntData(const int data)
{ {
dataType = JSON_DATA_TYPE::INT; dataType = JDType::INT;
intData = data; intData = data;
return; return;
@ -1827,7 +1827,7 @@ void JsonData::SetIntData(const int data)
void JsonData::SetFloatData(const long double data) void JsonData::SetFloatData(const long double data)
{ {
dataType = JSON_DATA_TYPE::FLOAT; dataType = JDType::FLOAT;
floatData = data; floatData = data;
return; return;
@ -1835,7 +1835,7 @@ void JsonData::SetFloatData(const long double data)
void JsonData::SetStringData(const std::string data) void JsonData::SetStringData(const std::string data)
{ {
dataType = JSON_DATA_TYPE::STRING; dataType = JDType::STRING;
stringData = data; stringData = data;
return; return;
@ -1848,7 +1848,7 @@ JsonBlock& JsonData::SetJsonData(const JsonBlock data)
JsonArray& JsonData::SetArrayData(const std::vector<JsonData> data) JsonArray& JsonData::SetArrayData(const std::vector<JsonData> data)
{ {
dataType = JSON_DATA_TYPE::ARRAY; dataType = JDType::ARRAY;
JsonArray* newArr = new JsonArray; JsonArray* newArr = new JsonArray;
newArr->CopyJsonDataFromVector_Pointer(&data); // Slightly more performant than constructor newArr->CopyJsonDataFromVector_Pointer(&data); // Slightly more performant than constructor
return SetArrayDataAsPointer(newArr); return SetArrayDataAsPointer(newArr);
@ -1861,14 +1861,14 @@ JsonArray& JsonData::SetArrayData(const JsonArray data)
void JsonData::SetNull() void JsonData::SetNull()
{ {
dataType = JSON_DATA_TYPE::__NULL__; dataType = JDType::__NULL__;
return; return;
} }
/* MISC */ /* MISC */
void JsonData::ThrowDataTypeException(const JSON_DATA_TYPE toFetch) const void JsonData::ThrowDataTypeException(const JDType toFetch) const
{ {
throw JsonWrongDataTypeException( throw JsonWrongDataTypeException(
JsonDataType2String(toFetch), JsonDataType2String(toFetch),
@ -1890,32 +1890,32 @@ std::string JsonData::Render(unsigned int num_tabs, const bool minify) const
switch (dataType) switch (dataType)
{ {
case JSON_DATA_TYPE::__NULL__: case JDType::__NULL__:
ss << "null"; ss << "null";
break; break;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
ss << ((intData != 0) ? "true" : "false"); ss << ((intData != 0) ? "true" : "false");
break; break;
case JSON_DATA_TYPE::INT: case JDType::INT:
ss << intData; ss << intData;
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
ss.precision((std::streamsize)((-log10(GetFloatPrecision())) + 1)); ss.precision((std::streamsize)((-log10(GetFloatPrecision())) + 1));
ss << floatData; ss << floatData;
break; break;
case JSON_DATA_TYPE::STRING: case JDType::STRING:
ss << "\"" << StringHelpers::Escape(stringData) << "\""; ss << "\"" << StringHelpers::Escape(stringData) << "\"";
break; break;
case JSON_DATA_TYPE::JSON: case JDType::JSON:
ss << jsonData->Render(num_tabs, minify); ss << jsonData->Render(num_tabs, minify);
break; break;
case JSON_DATA_TYPE::ARRAY: case JDType::ARRAY:
ss << arrayData->Render(num_tabs, minify); ss << arrayData->Render(num_tabs, minify);
break; break;
} }
@ -2007,31 +2007,31 @@ void JsonData::CloneFrom(const JsonData& other)
switch (other.dataType) switch (other.dataType)
{ {
case JSON_DATA_TYPE::__NULL__: case JDType::__NULL__:
// Default value is already NULL // Default value is already NULL
break; break;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
SetBoolData(other.intData != 0); SetBoolData(other.intData != 0);
break; break;
case JSON_DATA_TYPE::INT: case JDType::INT:
SetIntData(other.intData); SetIntData(other.intData);
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
SetFloatData(other.floatData); SetFloatData(other.floatData);
break; break;
case JSON_DATA_TYPE::STRING: case JDType::STRING:
SetStringData(other.stringData); SetStringData(other.stringData);
break; break;
case JSON_DATA_TYPE::ARRAY: case JDType::ARRAY:
SetArrayData(*other.arrayData); SetArrayData(*other.arrayData);
break; break;
case JSON_DATA_TYPE::JSON: case JDType::JSON:
SetJsonData(*other.jsonData); SetJsonData(*other.jsonData);
break; break;
} }
@ -2042,8 +2042,8 @@ void JsonData::CloneFrom(const JsonData& other)
bool JsonData::IsIdentical(const JsonData& other) const bool JsonData::IsIdentical(const JsonData& other) const
{ {
// Special case for int/float implicit conversion // Special case for int/float implicit conversion
if (((dataType == JSON_DATA_TYPE::INT) && (other.dataType == JSON_DATA_TYPE::FLOAT)) || if (((dataType == JDType::INT) && (other.dataType == JDType::FLOAT)) ||
((other.dataType == JSON_DATA_TYPE::INT) && (dataType == JSON_DATA_TYPE::FLOAT))) ((other.dataType == JDType::INT) && (dataType == JDType::FLOAT)))
{ {
// Here we have to get the float value via the getter because of implicit conversion // Here we have to get the float value via the getter because of implicit conversion
// Use the more precise precision of the two... // Use the more precise precision of the two...
@ -2055,32 +2055,32 @@ bool JsonData::IsIdentical(const JsonData& other) const
switch (dataType) switch (dataType)
{ {
case JSON_DATA_TYPE::__NULL__: case JDType::__NULL__:
return true; return true;
case JSON_DATA_TYPE::BOOL: case JDType::BOOL:
// Values can't be of different type because of the check at the beginning of the function // Values can't be of different type because of the check at the beginning of the function
return intData == other.intData; return intData == other.intData;
break; break;
case JSON_DATA_TYPE::INT: case JDType::INT:
return intData == other.intData; return intData == other.intData;
break; break;
case JSON_DATA_TYPE::FLOAT: case JDType::FLOAT:
// Use the more precise precision of the two... // Use the more precise precision of the two...
return Helpers::AreSame(floatData, other.floatData, Helpers::Min<double>(GetFloatPrecision(), other.GetFloatPrecision())); return Helpers::AreSame(floatData, other.floatData, Helpers::Min<double>(GetFloatPrecision(), other.GetFloatPrecision()));
break; break;
case JSON_DATA_TYPE::STRING: case JDType::STRING:
return stringData == other.stringData; return stringData == other.stringData;
break; break;
case JSON_DATA_TYPE::ARRAY: case JDType::ARRAY:
return arrayData->IsIdentical(*other.arrayData); return arrayData->IsIdentical(*other.arrayData);
break; break;
case JSON_DATA_TYPE::JSON: case JDType::JSON:
return jsonData->IsIdentical(*other.jsonData); return jsonData->IsIdentical(*other.jsonData);
break; break;
} }
@ -2140,11 +2140,11 @@ bool JsonData::operator!=(const JsonData& other) const
JsonData& JsonData::operator+=(const JsonElement ele) JsonData& JsonData::operator+=(const JsonElement ele)
{ {
if (dataType == JSON_DATA_TYPE::JSON) if (dataType == JDType::JSON)
{ {
return jsonData->Add(ele); return jsonData->Add(ele);
} }
ThrowDataTypeException(JSON_DATA_TYPE::JSON); ThrowDataTypeException(JDType::JSON);
std::terminate(); std::terminate();
} }
@ -2257,7 +2257,7 @@ JsonData::operator long double() const
JsonData::operator std::string() const JsonData::operator std::string() const
{ {
if (dataType == JSON_DATA_TYPE::STRING) return GetStringData(); if (dataType == JDType::STRING) return GetStringData();
else return Render(JASONPP_STRINGCONV_MINIFY); else return Render(JASONPP_STRINGCONV_MINIFY);
} }
@ -2266,7 +2266,7 @@ namespace JasonPP
{ {
std::ostream& operator<<(std::ostream& os, const JsonData& jd) std::ostream& operator<<(std::ostream& os, const JsonData& jd)
{ {
if (jd.dataType == JSON_DATA_TYPE::STRING) return os << jd.GetStringData(); if (jd.dataType == JDType::STRING) return os << jd.GetStringData();
else return os << jd.Render(JASONPP_STRINGCONV_MINIFY); else return os << jd.Render(JASONPP_STRINGCONV_MINIFY);
} }
} }
@ -2690,10 +2690,10 @@ bool JsonBlock::DoesShorthandExist(const std::string shorthand, const std::strin
const JsonBlock* jb = &const_cast<const JsonBlock&>(*this); const JsonBlock* jb = &const_cast<const JsonBlock&>(*this);
for (std::size_t i = 0; i < segments.size(); i++) for (std::size_t i = 0; i < segments.size(); i++)
{ {
if ((jb->DoesExist(segments[i])) && ((jb->Get(segments[i]).GetDataType() == JSON_DATA_TYPE::JSON) || (i == segments.size() - 1))) if ((jb->DoesExist(segments[i])) && ((jb->Get(segments[i]).GetDataType() == JDType::JSON) || (i == segments.size() - 1)))
{ {
if (i == segments.size() - 1) return true; // We are at the end. Let's just return it if (i == segments.size() - 1) return true; // We are at the end. Let's just return it
if (jb->Get(segments[i]).GetDataType() == JSON_DATA_TYPE::JSON) jb = &jb->Get(segments[i]).GetJsonData(); if (jb->Get(segments[i]).GetDataType() == JDType::JSON) jb = &jb->Get(segments[i]).GetJsonData();
else return false; else return false;
} }
else else
@ -2718,10 +2718,10 @@ const JsonData& JsonBlock::ShorthandGet(const std::string shorthand, const std::
const JsonBlock* jb = &const_cast<const JsonBlock&>(*this); const JsonBlock* jb = &const_cast<const JsonBlock&>(*this);
for (std::size_t i = 0; i < segments.size(); i++) for (std::size_t i = 0; i < segments.size(); i++)
{ {
if ((jb->DoesExist(segments[i])) && ((jb->Get(segments[i]).GetDataType() == JSON_DATA_TYPE::JSON) || (i == segments.size() - 1))) if ((jb->DoesExist(segments[i])) && ((jb->Get(segments[i]).GetDataType() == JDType::JSON) || (i == segments.size() - 1)))
{ {
if (i == segments.size() - 1) return jb->Get(segments[i]); // We are at the end. Let's just return it if (i == segments.size() - 1) return jb->Get(segments[i]); // We are at the end. Let's just return it
if (jb->Get(segments[i]).GetDataType() == JSON_DATA_TYPE::JSON) jb = &jb->Get(segments[i]).GetJsonData(); if (jb->Get(segments[i]).GetDataType() == JDType::JSON) jb = &jb->Get(segments[i]).GetJsonData();
else throw JsonShorthandInvalidException(shorthand); else throw JsonShorthandInvalidException(shorthand);
} }
else else
@ -2757,7 +2757,7 @@ JsonData& JsonBlock::ShorthandAdd(const std::string shorthand, const std::string
} }
else else
{ {
if (jb->Get(segments[i]).GetDataType() != JSON_DATA_TYPE::JSON) throw JsonShorthandInvalidException(shorthand, "A path segment already exists and is not of type json!"); if (jb->Get(segments[i]).GetDataType() != JDType::JSON) throw JsonShorthandInvalidException(shorthand, "A path segment already exists and is not of type json!");
jb = &jb->Get(segments[i]).GetJsonData(); jb = &jb->Get(segments[i]).GetJsonData();
} }
} }
@ -2804,7 +2804,7 @@ void JsonBlock::ShorthandRemove(const std::string shorthand, const std::string d
JsonData* dt = &ShorthandGet(shorthandParent, delimiter); JsonData* dt = &ShorthandGet(shorthandParent, delimiter);
// Is the parent object of the object to be deleted even of type json? // Is the parent object of the object to be deleted even of type json?
if (dt->GetDataType() != JSON_DATA_TYPE::JSON) throw JsonShorthandInvalidException(shorthand, "The parent of the object to be deleted is not of type json!"); if (dt->GetDataType() != JDType::JSON) throw JsonShorthandInvalidException(shorthand, "The parent of the object to be deleted is not of type json!");
parentJson = &dt->GetJsonData(); parentJson = &dt->GetJsonData();
} }

View File

@ -2142,13 +2142,18 @@ namespace JasonPP
}; };
} }
#define JASONPP_VERSION (1.02) #define JASONPP_VERSION (1.021)
namespace JasonPP namespace JasonPP
{ {
typedef JsonData Json; typedef JsonData Json;
} }
namespace JasonPP
{
typedef JSON_DATA_TYPE JDType;
}
namespace JasonPP namespace JasonPP
{ {
@ -2198,8 +2203,8 @@ namespace JasonPP
#define AsJson GetJsonData() #define AsJson GetJsonData()
#define AsArray GetArrayData() #define AsArray GetArrayData()
#define Arr std::vector<JasonPP::JsonData> #define Arr std::vector<::JasonPP::JsonData>
#define Ele JasonPP::JsonElement #define Ele ::JasonPP::JsonElement
#endif #endif

View File

@ -11,7 +11,10 @@ void LogHistory::PreInit()
void LogHistory::PostExit() void LogHistory::PostExit()
{ {
for (unsigned int i = 0; i < history->size(); i++) Save();
for (std::size_t i = 0; i < history->size(); i++)
{ {
delete history->at(i); delete history->at(i);
history->at(i) = nullptr; history->at(i) = nullptr;
@ -23,6 +26,29 @@ void LogHistory::PostExit()
return; return;
} }
void LogHistory::Save()
{
std::stringstream textfile;
JasonPP::Json jsonFile = JasonPP::JsonArray();
for (std::size_t i = 0; i < history->size(); i++)
{
textfile << history->at(i)->compiledMessage << std::endl;
jsonFile.AsArray += history->at(i)->GetAsJson();
}
std::ofstream ofs;
ofs.open(XGConfig::logging.logfile_text, std::ios::app);
ofs << textfile.str();
ofs.close();
ofs.open(XGConfig::logging.logfile_json, std::ios::app);
ofs << jsonFile.Render();
ofs.close();
return;
}
void LogHistory::AddLogToHistory(LogEntry* newEntry) void LogHistory::AddLogToHistory(LogEntry* newEntry)
{ {
history->push_back(newEntry); history->push_back(newEntry);
@ -31,3 +57,14 @@ void LogHistory::AddLogToHistory(LogEntry* newEntry)
} }
std::vector<LogEntry*>* LogHistory::history; std::vector<LogEntry*>* LogHistory::history;
JasonPP::JsonBlock LogEntry::GetAsJson()
{
return JasonPP::JsonBlock({
Ele("compiledMessage", message),
Ele("message", compiledMessage),
Ele("identifier", identifier),
Ele("type", (int)type),
Ele("timestamp", (long long int)timestamp),
});
}

View File

@ -2,7 +2,11 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <ctime> #include <ctime>
#include <sstream>
#include <fstream>
#include "LogTypes.h" #include "LogTypes.h"
#include "XGConfig.h"
#include "JasonPP.hpp"
namespace Logging namespace Logging
{ {
@ -11,10 +15,13 @@ namespace Logging
class LogEntry class LogEntry
{ {
public: public:
std::string compiledMessage;
std::string message; std::string message;
std::string identifier; std::string identifier;
LOG_TYPE type; LOG_TYPE type;
std::time_t timestamp; std::time_t timestamp;
JasonPP::JsonBlock GetAsJson();
}; };
class LogHistory class LogHistory
@ -23,6 +30,8 @@ namespace Logging
static void PreInit(); static void PreInit();
static void PostExit(); static void PostExit();
static void Save();
static std::vector<LogEntry*>* GetLogHistory() { return history; } static std::vector<LogEntry*>* GetLogHistory() { return history; }
private: private:

View File

@ -2,7 +2,7 @@
namespace Logging namespace Logging
{ {
enum class LOG_TYPE enum LOG_TYPE
{ {
LOG, LOG,
WARN, WARN,

View File

@ -1,4 +1,5 @@
#include "Logger.h" #include "Logger.h"
#include "LogHistory.h"
using namespace Logging; using namespace Logging;
@ -48,7 +49,8 @@ std::string Logger::Flush()
bufOut << "<" << timeBuf << "> [" << identifier << "]" << TypeToPrefix(type) << ((additionalInfo.length() > 0) ? " " : "") << additionalInfo << ": " << cout.str(); bufOut << "<" << timeBuf << "> [" << identifier << "]" << TypeToPrefix(type) << ((additionalInfo.length() > 0) ? " " : "") << additionalInfo << ": " << cout.str();
LogEntry* newEntry = new LogEntry; LogEntry* newEntry = new LogEntry;
newEntry->message = bufOut.str(); newEntry->message = cout.str();
newEntry->compiledMessage = bufOut.str();
newEntry->identifier = identifier; newEntry->identifier = identifier;
newEntry->timestamp = currTime; newEntry->timestamp = currTime;
newEntry->type = type; newEntry->type = type;

View File

@ -3,7 +3,6 @@
#include <string> #include <string>
#include <sstream> #include <sstream>
#include "LogTypes.h" #include "LogTypes.h"
#include "LogHistory.h"
namespace Logging namespace Logging
{ {

View File

@ -15,7 +15,7 @@ bool RestQueryHandler::ProcessQuery(const std::string clientAdress, const Json&
{ {
log->SetAdditionalInformation(std::string("@") + clientAdress); log->SetAdditionalInformation(std::string("@") + clientAdress);
if (!ValidateField("request", JSON_DATA_TYPE::STRING, request, responseBody)) if (!ValidateField("request", JDType::STRING, request, responseBody))
{ {
responseCode = BAD_REQUEST; responseCode = BAD_REQUEST;
return false; return false;
@ -23,7 +23,10 @@ bool RestQueryHandler::ProcessQuery(const std::string clientAdress, const Json&
JsonBlock requestBody = request.AsJson; JsonBlock requestBody = request.AsJson;
std::string requestName = requestBody.Get("request").AsString; std::string requestName = requestBody.Get("request").AsString;
if (requestName == "kill_yourself") return KillYourself(requestBody, responseBody, responseCode); if (requestName == "kill_yourself") return KillYourself(requestBody, responseBody, responseCode);
else if (requestName == "foo") return Example_Foo(requestBody, responseBody, responseCode);
@ -32,7 +35,7 @@ bool RestQueryHandler::ProcessQuery(const std::string clientAdress, const Json&
return false; return false;
} }
void Rest::RestQueryHandler::PostExit() void RestQueryHandler::PostExit()
{ {
delete log; delete log;
log = nullptr; log = nullptr;
@ -40,6 +43,15 @@ void Rest::RestQueryHandler::PostExit()
return; return;
} }
bool RestQueryHandler::Example_Foo(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode)
{
responseCode = OK;
responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK));
responseBody.Set("message") = "Bar!";
std::cout << "Bar!" << std::endl;
return true;
}
bool RestQueryHandler::KillYourself(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) bool RestQueryHandler::KillYourself(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode)
{ {
XGControl::keepServerRunning = false; XGControl::keepServerRunning = false;
@ -53,9 +65,9 @@ bool RestQueryHandler::KillYourself(const JsonBlock& request, JsonBlock& respons
return true; return true;
} }
bool RestQueryHandler::ValidateField(const std::string name, const JasonPP::JSON_DATA_TYPE type, const JasonPP::Json& checkThat, JasonPP::JsonBlock& putErrorResponseHere) bool RestQueryHandler::ValidateField(const std::string name, const JasonPP::JDType type, const JasonPP::Json& checkThat, JasonPP::JsonBlock& putErrorResponseHere)
{ {
if (checkThat.GetDataType() != JSON_DATA_TYPE::JSON) if (checkThat.GetDataType() != JDType::JSON)
{ {
putErrorResponseHere = RestResponseTemplates::GetByCode(BAD_REQUEST, "The request body must be a json struct! No json array or similar..."); putErrorResponseHere = RestResponseTemplates::GetByCode(BAD_REQUEST, "The request body must be a json struct! No json array or similar...");
return false; return false;
@ -68,8 +80,8 @@ bool RestQueryHandler::ValidateField(const std::string name, const JasonPP::JSON
const JsonData& cached = cachedJson.ShorthandGet(name); const JsonData& cached = cachedJson.ShorthandGet(name);
if ((cached.GetDataType() == type) || if ((cached.GetDataType() == type) ||
((cached.IsOfNumericType()) && (type == JSON_DATA_TYPE::INT)) || ((cached.IsOfNumericType()) && (type == JDType::INT)) ||
((cached.IsOfNumericType()) && (type == JSON_DATA_TYPE::FLOAT))) ((cached.IsOfNumericType()) && (type == JDType::FLOAT)))
{ {
return true; return true;
} }

View File

@ -16,9 +16,10 @@ namespace Rest
static void PostExit(); static void PostExit();
private: private:
static bool Example_Foo(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode);
static bool KillYourself(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); static bool KillYourself(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode);
static bool ValidateField(const std::string name, const JasonPP::JSON_DATA_TYPE type, const JasonPP::Json& checkThat, JasonPP::JsonBlock& putErrorResponseHere); static bool ValidateField(const std::string name, const JasonPP::JDType type, const JasonPP::Json& checkThat, JasonPP::JsonBlock& putErrorResponseHere);
static Logging::Logger* log; static Logging::Logger* log;
}; };

View File

@ -86,7 +86,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>JASONPP_RENDER_SORTED;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
</ClCompile> </ClCompile>
<Link> <Link>
@ -139,6 +139,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="FileSystem.cpp" />
<ClCompile Include="Framework.cpp" /> <ClCompile Include="Framework.cpp" />
<ClCompile Include="JasonPP.cpp" /> <ClCompile Include="JasonPP.cpp" />
<ClCompile Include="Logger.cpp" /> <ClCompile Include="Logger.cpp" />
@ -147,10 +148,12 @@
<ClCompile Include="mongoose.c" /> <ClCompile Include="mongoose.c" />
<ClCompile Include="RestQueryHandler.cpp" /> <ClCompile Include="RestQueryHandler.cpp" />
<ClCompile Include="RestResponseTemplates.cpp" /> <ClCompile Include="RestResponseTemplates.cpp" />
<ClCompile Include="RestInterface.cpp" /> <ClCompile Include="HttpServer.cpp" />
<ClCompile Include="XGConfig.cpp" />
<ClCompile Include="XGControl.cpp" /> <ClCompile Include="XGControl.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="FileSystem.h" />
<ClInclude Include="Framework.h" /> <ClInclude Include="Framework.h" />
<ClInclude Include="JasonPP.hpp" /> <ClInclude Include="JasonPP.hpp" />
<ClInclude Include="Logger.h" /> <ClInclude Include="Logger.h" />
@ -159,7 +162,8 @@
<ClInclude Include="mongoose.h" /> <ClInclude Include="mongoose.h" />
<ClInclude Include="RestQueryHandler.h" /> <ClInclude Include="RestQueryHandler.h" />
<ClInclude Include="RestResponseTemplates.h" /> <ClInclude Include="RestResponseTemplates.h" />
<ClInclude Include="RestInterface.h" /> <ClInclude Include="HttpServer.h" />
<ClInclude Include="XGConfig.h" />
<ClInclude Include="XGControl.h" /> <ClInclude Include="XGControl.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -36,9 +36,6 @@
<ClCompile Include="Framework.cpp"> <ClCompile Include="Framework.cpp">
<Filter>Quelldateien</Filter> <Filter>Quelldateien</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="RestInterface.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="RestResponseTemplates.cpp"> <ClCompile Include="RestResponseTemplates.cpp">
<Filter>Quelldateien</Filter> <Filter>Quelldateien</Filter>
</ClCompile> </ClCompile>
@ -48,6 +45,15 @@
<ClCompile Include="XGControl.cpp"> <ClCompile Include="XGControl.cpp">
<Filter>Quelldateien</Filter> <Filter>Quelldateien</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="XGConfig.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="FileSystem.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="HttpServer.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="JasonPP.hpp"> <ClInclude Include="JasonPP.hpp">
@ -68,9 +74,6 @@
<ClInclude Include="Framework.h"> <ClInclude Include="Framework.h">
<Filter>Headerdateien</Filter> <Filter>Headerdateien</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="RestInterface.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="RestResponseTemplates.h"> <ClInclude Include="RestResponseTemplates.h">
<Filter>Headerdateien</Filter> <Filter>Headerdateien</Filter>
</ClInclude> </ClInclude>
@ -80,5 +83,14 @@
<ClInclude Include="XGControl.h"> <ClInclude Include="XGControl.h">
<Filter>Headerdateien</Filter> <Filter>Headerdateien</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="XGConfig.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="FileSystem.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="HttpServer.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

200
Tubio/XGConfig.cpp Normal file
View File

@ -0,0 +1,200 @@
#include "XGConfig.h"
using namespace JasonPP;
void XGConfig::PreInit()
{
log = new ::Logging::Logger("Config");
InitializeDefaultValues();
if (FileSystem::Exists(XGCONFIG_FILE))
{
Load();
log->cout << "Loaded config file";
log->Flush();
}
else
{
// Save default config values, and thus, create a default config file
Save();
log->cout << log->Warn() << "Config file not found. Created default one.";
log->Flush();
}
return;
}
bool XGConfig::IsJsonFieldValid(const JsonBlock& json, const std::string key, const JDType type)
{
return ((json.DoesShorthandExist(key)) && (json.ShorthandGet(key).GetDataType() == type));
}
void XGConfig::InitializeDefaultValues()
{
httpServer.port = "6969";
httpServer.pollingRate = 100;
httpServer.rootdir = "frontend";
logging.logfile_text = "log.txt";
logging.logfile_json = "log.json";
return;
}
void XGConfig::LoadFromJson(const JasonPP::JsonBlock& json)
{
if (IsJsonFieldValid(json, "logging.logfile_json", JDType::STRING))
{
logging.logfile_json = json.ShorthandGet("logging.logfile_json").AsString;
}
if (IsJsonFieldValid(json, "logging.logfile_text", JDType::STRING))
{
logging.logfile_text = json.ShorthandGet("logging.logfile_text").AsString;
}
if (IsJsonFieldValid(json, "httpServer.port", JDType::STRING))
{
httpServer.port = json.ShorthandGet("httpServer.port").AsString;
}
if (IsJsonFieldValid(json, "httpServer.pollingRate", JDType::INT))
{
httpServer.pollingRate = json.ShorthandGet("httpServer.pollingRate").AsInt;
}
if (IsJsonFieldValid(json, "httpServer.rootdir", JDType::STRING))
{
httpServer.rootdir = json.ShorthandGet("httpServer.rootdir").AsString;
}
return;
}
JsonBlock XGConfig::CreateJson()
{
return JsonBlock({
Ele("httpServer", JsonBlock({
Ele("port", httpServer.port),
Ele("pollingRate", httpServer.pollingRate),
Ele("rootdir", httpServer.rootdir)
})),
Ele("logging", JsonBlock({
Ele("logfile_text", logging.logfile_text),
Ele("logfile_json", logging.logfile_json)
}))
});
}
void XGConfig::PostExit()
{
Save();
delete log;
log = nullptr;
return;
}
void XGConfig::Save()
{
/*
All this shit is basically:
-- Create backup of known good config
-- Save new config
-- Is new config parsable?
-- Yes
-- Delete backup
-- No
-- Restore backup
*/
log->cout << "Saving config...";
log->Flush();
if (!FileSystem::Copy(XGCONFIG_FILE, XGCONFIG_FILE_TMPBACKUP)) // Copy known-good file
{
log->cout << log->Err() << "Unable to create backup of config file! (backup is \"" << XGCONFIG_FILE_TMPBACKUP << "\")";
log->Flush();
return;
}
if (!SaveToFile(XGCONFIG_FILE)) // Now overwrite original file
{
log->cout << log->Err() << "Unable to save config file \"" << XGCONFIG_FILE_TMPBACKUP << "\"";
log->Flush();
return;
}
std::string writtenCode = FileSystem::ReadFile(XGCONFIG_FILE);
if (IsJsonValid(writtenCode))
{
// All good, was successfully saved. Now delete the backup file.
FileSystem::Delete(std::string(XGCONFIG_FILE) + "___");
}
else
{
// Saving was not successful. Let's copy the backup back.
if (FileSystem::Copy(XGCONFIG_FILE_TMPBACKUP, XGCONFIG_FILE)) // Copy known-good file
{
log->cout << log->Err() << "Unable to restore backup of config file! (backup is \"" << XGCONFIG_FILE_TMPBACKUP << "\")";
log->Flush();
return;
}
if (FileSystem::Delete(XGCONFIG_FILE_TMPBACKUP))
{
log->cout << log->Err() << "Unable to delete backup of config file! (backup is \"" << XGCONFIG_FILE_TMPBACKUP << "\")";
log->Flush();
return;
}
log->cout << log->Warn() << "Unable to save config file to \"" << XGCONFIG_FILE << "\"!";
log->Flush();
}
return;
}
bool XGConfig::SaveToFile(std::string filename)
{
Json cfgStruct(CreateJson());
return FileSystem::WriteFile(filename, cfgStruct.Render());
}
void XGConfig::Load()
{
std::string config_code = FileSystem::ReadFile(XGCONFIG_FILE);
if (IsJsonValid(config_code))
{
Json json;
json.Parse(config_code);
if (json.GetDataType() == JDType::JSON)
{
LoadFromJson(json.AsJson);
}
else
{
log->cout << log->Warn() << "Unable to load config file because its content is not of json-type json!";
log->Flush();
}
}
else
{
log->cout << log->Warn() << "Unable to parse config file to \"" << XGCONFIG_FILE << "\" because it's json syntax is most likely fucked up!";
log->Flush();
}
return;
}
XGConfig::HttpServer XGConfig::httpServer;
XGConfig::Logging XGConfig::logging;
::Logging::Logger* XGConfig::log;

43
Tubio/XGConfig.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include "Filesystem.h"
#include "JasonPP.hpp"
#include "Logger.h"
#define XGCONFIG_FILE "config.json"
#define XGCONFIG_FILE_TMPBACKUP (std::string(XGCONFIG_FILE) + "___")
class XGConfig
{
public:
struct HttpServer
{
std::string port;
std::string rootdir;
int pollingRate;
};
struct Logging
{
std::string logfile_text;
std::string logfile_json;
};
static void PreInit();
static void Save();
static void PostExit();
static HttpServer httpServer;
static XGConfig::Logging logging;
static ::Logging::Logger* log;
private:
static bool SaveToFile(std::string filename);
static bool IsJsonFieldValid(const JasonPP::JsonBlock& json, const std::string key, const JasonPP::JDType type);
static void InitializeDefaultValues();
static JasonPP::JsonBlock CreateJson();
static void LoadFromJson(const JasonPP::JsonBlock& json);
static void Load();
};

View File

@ -1,17 +1,32 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello, World!</title> <title>Hello, World!</title>
</head> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<body style="position: relative;"> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<link rel="stylesheet" href="/style.css">
</head>
<div style="width: 100%; height: 100vh; display: flex; justify-content: center; align-items: center; text-align: center; font-size: 38pt; font-family: sans-serif;"> <body>
<h1 id="headline">Hello, World!</h1>
<div class="button-wrapper">
<div class="button" id="btn_foo">
<p> <p>
HELLO, WORLD :3 Foo!
</p> </p>
</div> </div>
<div class="button" id="btn_killserver">
<p>
Kill server
</p>
</div>
</div>
</body>
<script src="/script.js"></script>
</body>
</html> </html>

27
Tubio/frontend/script.js Normal file
View File

@ -0,0 +1,27 @@
$(".button").mousedown(function(e){
// Animations
e.target.classList.add("clicked");
setTimeout(function(){
e.target.classList.remove("clicked");
}, 100);
});
$("#btn_foo").click(function(e){
// Functionality
axios.post("/api", {
request: "foo"
}).then(function(response){
// Do something with the servers response
});
});
$("#btn_killserver").click(function(e){
// Functionality
axios.post("/api", {
request: "kill_yourself"
}).then(function(response){
if (response.data.status == "OK") {
$("#headline").html("Sever's dead");
}
});
});

75
Tubio/frontend/style.css Normal file
View File

@ -0,0 +1,75 @@
body {
background-color: #00aa77;
}
h1,
h2,
h3,
h4,
p {
font-family: sans-serif;
color: #fff;
}
h1 {
font-size: 38pt;
text-align: center;
}
.button-wrapper {
display: flex;
width: 100%;
height: 100%;
align-items: center;
flex-direction: column;
}
.button {
background-color: #ee8800;
padding: 0.5em 8em;
width: 200px;
border-radius: 1em;
cursor: pointer;
text-align: center;
user-select: none;
transition:
background-color 0.2s,
transform 0.2s;
}
@media (max-width: 600px) {
.button {
width: 80%;
padding: 0.15em 3em;
}
}
.button:first-child
{
margin-top: 5em;
}
.button:not(:first-child)
{
margin-top: 2em;
}
@media (min-width: 600px) {
.button:hover {
background-color: #ffaa00;
transform: scale(1.05);
}
}
.button.clicked {
background-color: #cc6600;
transform: scale(0.95);
}
.button p{
font-size: 24pt;
}
.button * {
pointer-events: none;
}