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

@ -1,25 +1,25 @@
/* /*
MIT License MIT License
JasonPP, Copyright (c) 2020, Leon Etienne JasonPP, Copyright (c) 2020, Leon Etienne
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#include "JasonPP.hpp" #include "JasonPP.hpp"
@ -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>
<p>
HELLO, WORLD :3 <h1 id="headline">Hello, World!</h1>
</p>
</div> <div class="button-wrapper">
<div class="button" id="btn_foo">
</body> <p>
Foo!
</p>
</div>
<div class="button" id="btn_killserver">
<p>
Kill server
</p>
</div>
</div>
<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;
}