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
*.sln.docstates
# Tubio files
config.json
log.txt
log.json
# User-specific files (MonoDevelop/Xamarin Studio)
*.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->Flush();
restInterface = new RestInterface();
httpServer = new HttpServer();
PostInit();
@ -23,10 +23,10 @@ Framework::Framework()
Framework::~Framework()
{
delete restInterface;
delete httpServer;
delete log;
restInterface = nullptr;
httpServer = nullptr;
log = nullptr;
return;
@ -36,7 +36,7 @@ void Framework::Run()
{
while (XGControl::keepServerRunning)
{
restInterface->Update();
httpServer->Update();
}
OnExit();
@ -50,6 +50,7 @@ void Framework::Run()
void Framework::PreInit()
{
LogHistory::PreInit();
XGConfig::PreInit();
RestQueryHandler::PreInit();
return;
@ -58,22 +59,23 @@ void Framework::PreInit()
void Framework::PostInit()
{
restInterface->PostInit();
httpServer->PostInit();
return;
}
void Framework::OnExit()
{
restInterface->OnExit();
httpServer->OnExit();
return;
}
void Framework::PostExit()
{
LogHistory::PostExit();
XGConfig::PostExit();
RestQueryHandler::PostExit();
LogHistory::PostExit();
return;
}

View File

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

View File

@ -1,10 +1,10 @@
#include "RestInterface.h"
#include "HttpServer.h"
using namespace Logging;
using namespace Rest;
using namespace JasonPP;
RestInterface::RestInterface()
HttpServer::HttpServer()
{
pMgr = new mg_mgr();
pNc = nullptr;
@ -13,7 +13,7 @@ RestInterface::RestInterface()
return;
}
RestInterface::~RestInterface()
HttpServer::~HttpServer()
{
delete pMgr;
delete log;
@ -24,31 +24,31 @@ RestInterface::~RestInterface()
return;
}
void RestInterface::PostInit()
void HttpServer::PostInit()
{
isBootedSuccessfully = InitWebServer();
return;
}
bool RestInterface::InitWebServer()
bool HttpServer::InitWebServer()
{
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();
pNc = mg_bind(pMgr, WEBAPI_SERVER_PORT, this->EventHandler);
pNc = mg_bind(pMgr, XGConfig::httpServer.port.c_str(), this->EventHandler);
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();
return false;
}
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";
log->cout << "Started web server successfully!";
@ -58,14 +58,14 @@ bool RestInterface::InitWebServer()
return true;
}
void RestInterface::Update()
void HttpServer::Update()
{
mg_mgr_poll(pMgr, WEBAPI_SERVER_POLLRATE);
mg_mgr_poll(pMgr, XGConfig::httpServer.pollingRate);
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_printf(c, str.c_str());
@ -73,7 +73,7 @@ void RestInterface::ServeStringToConnection(struct mg_connection* c, std::string
return;
}
void RestInterface::EventHandler(mg_connection* pNc, int ev, void* p)
void HttpServer::EventHandler(mg_connection* pNc, int ev, void* p)
{
switch (ev)
{
@ -98,7 +98,7 @@ void RestInterface::EventHandler(mg_connection* pNc, int ev, void* p)
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
http_message* hpm = (http_message*)p;
@ -131,7 +131,7 @@ void RestInterface::ProcessAPIRequest(mg_connection* pNc, int ev, void* p)
return;
}
void RestInterface::OnExit()
void HttpServer::OnExit()
{
log->cout << "Shutting down rest api server...";
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;
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();
}
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 "RestResponseTemplates.h"
#include "RestQueryHandler.h"
#define WEBAPI_SERVER_POLLRATE 100
#define WEBAPI_SERVER_PORT "6969"
#include "XGConfig.h"
namespace Rest
{
class RestInterface
class HttpServer
{
public:
RestInterface();
~RestInterface();
HttpServer();
~HttpServer();
void PostInit();
void Update();

View File

@ -262,7 +262,7 @@ std::size_t JsonArray::RemoveSimilar(const JsonData reference)
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;
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;
}
std::size_t JsonArray::RemoveAllExceptType(const JSON_DATA_TYPE type)
std::size_t JsonArray::RemoveAllExceptType(const JDType type)
{
std::size_t counter = 0;
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);
// 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
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
// This is the "shallow"-sort
if (!(((a.GetDataType() == JSON_DATA_TYPE::JSON) || (a.GetDataType() == JSON_DATA_TYPE::ARRAY)) &&
((b.GetDataType() == JSON_DATA_TYPE::JSON) || (b.GetDataType() == JSON_DATA_TYPE::ARRAY))))
if (!(((a.GetDataType() == JDType::JSON) || (a.GetDataType() == JDType::ARRAY)) &&
((b.GetDataType() == JDType::JSON) || (b.GetDataType() == JDType::ARRAY))))
{
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"
// This way numerics can still be sorted alphabetically
// Also allows for sorting after bools
if (a.GetDataType() == JSON_DATA_TYPE::STRING) aStr = a.GetStringData();
else if ((a.GetDataType() != JSON_DATA_TYPE::JSON) && (a.GetDataType() != JSON_DATA_TYPE::ARRAY)) aStr = a.Render();
if (a.GetDataType() == JDType::STRING) aStr = a.GetStringData();
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.
if (b.GetDataType() == JSON_DATA_TYPE::STRING) bStr = b.GetStringData();
else if ((b.GetDataType() != JSON_DATA_TYPE::JSON) && (b.GetDataType() != JSON_DATA_TYPE::ARRAY)) bStr = b.Render();
if (b.GetDataType() == JDType::STRING) bStr = b.GetStringData();
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.
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"
// This way numerics can still be sorted alphabetically
// Also allows for sorting after bools
if (a.GetDataType() == JSON_DATA_TYPE::STRING) aStr = a.GetStringData();
else if ((a.GetDataType() != JSON_DATA_TYPE::JSON) && (a.GetDataType() != JSON_DATA_TYPE::ARRAY)) aStr = a.Render();
if (a.GetDataType() == JDType::STRING) aStr = a.GetStringData();
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.
if (b.GetDataType() == JSON_DATA_TYPE::STRING) bStr = b.GetStringData();
else if ((b.GetDataType() != JSON_DATA_TYPE::JSON) && (b.GetDataType() != JSON_DATA_TYPE::ARRAY)) bStr = b.Render();
if (b.GetDataType() == JDType::STRING) bStr = b.GetStringData();
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.
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())
{
case JSON_DATA_TYPE::INT:
case JDType::INT:
dataA = (long double)a.GetIntData();
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
dataA = a.GetFloatData();
break;
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
dataA = a.GetBoolData() ? 1.0 : 0.0;
break;
default:
@ -645,13 +645,13 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
}
switch (b.GetDataType())
{
case JSON_DATA_TYPE::INT:
case JDType::INT:
dataB = (long double)b.GetIntData();
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
dataB = b.GetFloatData();
break;
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
dataB = b.GetBoolData() ? 1.0 : 0.0;
break;
default:
@ -669,13 +669,13 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
switch (a.GetDataType())
{
case JSON_DATA_TYPE::INT:
case JDType::INT:
dataA = (long double)a.GetIntData();
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
dataA = a.GetFloatData();
break;
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
dataA = a.GetBoolData() ? 1.0 : 0.0;
break;
default:
@ -683,13 +683,13 @@ bool JsonArray::Sort__Compare(const JsonData& a, const JsonData& b, const JSON_A
}
switch (b.GetDataType())
{
case JSON_DATA_TYPE::INT:
case JDType::INT:
dataB = (long double)b.GetIntData();
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
dataB = b.GetFloatData();
break;
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
dataB = b.GetBoolData() ? 1.0 : 0.0;
break;
default:
@ -753,7 +753,7 @@ JsonArray& JsonArray::operator-=(const JsonData& data)
return *this;
}
JsonArray& JsonArray::operator-=(const JSON_DATA_TYPE type)
JsonArray& JsonArray::operator-=(const JDType type)
{
RemoveAllOfType(type);
return *this;
@ -1031,29 +1031,29 @@ bool JasonPP::IsJsonValid(const std::string code)
return true;
}
std::string JasonPP::JsonDataType2String(const JSON_DATA_TYPE type)
std::string JasonPP::JsonDataType2String(const JDType type)
{
switch (type)
{
case JSON_DATA_TYPE::__NULL__:
case JDType::__NULL__:
return std::string("NULL");
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
return std::string("BOOL");
case JSON_DATA_TYPE::INT:
case JDType::INT:
return std::string("INT");
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
return std::string("FLOAT");
case JSON_DATA_TYPE::STRING:
case JDType::STRING:
return std::string("STRING");
case JSON_DATA_TYPE::JSON:
case JDType::JSON:
return std::string("JSON");
case JSON_DATA_TYPE::ARRAY:
case JDType::ARRAY:
return std::string("ARRAY");
}
@ -1457,37 +1457,37 @@ JsonData::JsonData()
}
// Set default data per type
JsonData::JsonData(const JSON_DATA_TYPE type)
JsonData::JsonData(const JDType type)
{
Init();
switch (type)
{
case JSON_DATA_TYPE::__NULL__:
case JDType::__NULL__:
// Default value is already NULL
break;
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
SetBoolData(false);
break;
case JSON_DATA_TYPE::INT:
case JDType::INT:
SetIntData(0);
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
SetFloatData(0);
break;
case JSON_DATA_TYPE::STRING:
case JDType::STRING:
SetStringData("");
break;
case JSON_DATA_TYPE::JSON:
case JDType::JSON:
SetJsonDataAsPointer(new JsonBlock());
break;
case JSON_DATA_TYPE::ARRAY:
case JDType::ARRAY:
SetArrayDataAsPointer(new JsonArray());
break;
}
@ -1602,7 +1602,7 @@ void JsonData::SetFloatPrecision(const double precision)
JsonArray& JsonData::SetArrayDataAsPointer(JsonArray* p)
{
dataType = JSON_DATA_TYPE::ARRAY;
dataType = JDType::ARRAY;
if (arrayData != nullptr)
{
@ -1617,7 +1617,7 @@ JsonArray& JsonData::SetArrayDataAsPointer(JsonArray* p)
JsonBlock& JsonData::SetJsonDataAsPointer(JsonBlock* p)
{
dataType = JSON_DATA_TYPE::JSON;
dataType = JDType::JSON;
if (jsonData != nullptr)
{
@ -1631,7 +1631,7 @@ JsonBlock& JsonData::SetJsonDataAsPointer(JsonBlock* p)
void JsonData::Init()
{
dataType = JSON_DATA_TYPE::__NULL__;
dataType = JDType::__NULL__;
intData = 0l;
floatData = 0.0f;
stringData = std::string();
@ -1686,12 +1686,12 @@ double JsonData::GetFloatPrecision() 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
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::BOOL;
JDType typeToGet = JDType::BOOL;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
@ -1700,11 +1700,11 @@ bool JsonData::GetBoolData() const
long long int JsonData::GetIntData() const
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::INT;
JDType typeToGet = JDType::INT;
if (dataType != typeToGet)
{
if (dataType == JSON_DATA_TYPE::FLOAT)
if (dataType == JDType::FLOAT)
{
return (long long int)floatData;
}
@ -1719,11 +1719,11 @@ long long int JsonData::GetIntData() const
long double JsonData::GetFloatData() const
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::FLOAT;
JDType typeToGet = JDType::FLOAT;
if (dataType != typeToGet)
{
if (dataType == JSON_DATA_TYPE::INT)
if (dataType == JDType::INT)
{
return (float)intData;
}
@ -1738,7 +1738,7 @@ long double JsonData::GetFloatData() const
std::string JsonData::GetStringData() const
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::STRING;
JDType typeToGet = JDType::STRING;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
@ -1747,35 +1747,35 @@ std::string JsonData::GetStringData() const
JsonBlock& JsonData::GetJsonData()
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::JSON;
JDType typeToGet = JDType::JSON;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *jsonData;
}
const JsonBlock& JsonData::GetJsonData() const
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::JSON;
JDType typeToGet = JDType::JSON;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *jsonData;
}
JsonArray& JsonData::GetArrayData()
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::ARRAY;
JDType typeToGet = JDType::ARRAY;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *arrayData;
}
const JsonArray& JsonData::GetArrayData() const
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::ARRAY;
JDType typeToGet = JDType::ARRAY;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
return *arrayData;
}
short JsonData::GetNullData()
{
JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::__NULL__;
JDType typeToGet = JDType::__NULL__;
if (dataType != typeToGet) ThrowDataTypeException(typeToGet);
@ -1803,7 +1803,7 @@ bool JsonData::HasParent() const
void JsonData::SetBoolData(const bool data)
{
dataType = JSON_DATA_TYPE::BOOL;
dataType = JDType::BOOL;
intData = (int)data;
return;
@ -1811,7 +1811,7 @@ void JsonData::SetBoolData(const bool data)
void JsonData::SetIntData(const long long int data)
{
dataType = JSON_DATA_TYPE::INT;
dataType = JDType::INT;
intData = data;
return;
@ -1819,7 +1819,7 @@ void JsonData::SetIntData(const long long int data)
void JsonData::SetIntData(const int data)
{
dataType = JSON_DATA_TYPE::INT;
dataType = JDType::INT;
intData = data;
return;
@ -1827,7 +1827,7 @@ void JsonData::SetIntData(const int data)
void JsonData::SetFloatData(const long double data)
{
dataType = JSON_DATA_TYPE::FLOAT;
dataType = JDType::FLOAT;
floatData = data;
return;
@ -1835,7 +1835,7 @@ void JsonData::SetFloatData(const long double data)
void JsonData::SetStringData(const std::string data)
{
dataType = JSON_DATA_TYPE::STRING;
dataType = JDType::STRING;
stringData = data;
return;
@ -1848,7 +1848,7 @@ JsonBlock& JsonData::SetJsonData(const JsonBlock data)
JsonArray& JsonData::SetArrayData(const std::vector<JsonData> data)
{
dataType = JSON_DATA_TYPE::ARRAY;
dataType = JDType::ARRAY;
JsonArray* newArr = new JsonArray;
newArr->CopyJsonDataFromVector_Pointer(&data); // Slightly more performant than constructor
return SetArrayDataAsPointer(newArr);
@ -1861,14 +1861,14 @@ JsonArray& JsonData::SetArrayData(const JsonArray data)
void JsonData::SetNull()
{
dataType = JSON_DATA_TYPE::__NULL__;
dataType = JDType::__NULL__;
return;
}
/* MISC */
void JsonData::ThrowDataTypeException(const JSON_DATA_TYPE toFetch) const
void JsonData::ThrowDataTypeException(const JDType toFetch) const
{
throw JsonWrongDataTypeException(
JsonDataType2String(toFetch),
@ -1890,32 +1890,32 @@ std::string JsonData::Render(unsigned int num_tabs, const bool minify) const
switch (dataType)
{
case JSON_DATA_TYPE::__NULL__:
case JDType::__NULL__:
ss << "null";
break;
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
ss << ((intData != 0) ? "true" : "false");
break;
case JSON_DATA_TYPE::INT:
case JDType::INT:
ss << intData;
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
ss.precision((std::streamsize)((-log10(GetFloatPrecision())) + 1));
ss << floatData;
break;
case JSON_DATA_TYPE::STRING:
case JDType::STRING:
ss << "\"" << StringHelpers::Escape(stringData) << "\"";
break;
case JSON_DATA_TYPE::JSON:
case JDType::JSON:
ss << jsonData->Render(num_tabs, minify);
break;
case JSON_DATA_TYPE::ARRAY:
case JDType::ARRAY:
ss << arrayData->Render(num_tabs, minify);
break;
}
@ -2007,31 +2007,31 @@ void JsonData::CloneFrom(const JsonData& other)
switch (other.dataType)
{
case JSON_DATA_TYPE::__NULL__:
case JDType::__NULL__:
// Default value is already NULL
break;
case JSON_DATA_TYPE::BOOL:
case JDType::BOOL:
SetBoolData(other.intData != 0);
break;
case JSON_DATA_TYPE::INT:
case JDType::INT:
SetIntData(other.intData);
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
SetFloatData(other.floatData);
break;
case JSON_DATA_TYPE::STRING:
case JDType::STRING:
SetStringData(other.stringData);
break;
case JSON_DATA_TYPE::ARRAY:
case JDType::ARRAY:
SetArrayData(*other.arrayData);
break;
case JSON_DATA_TYPE::JSON:
case JDType::JSON:
SetJsonData(*other.jsonData);
break;
}
@ -2042,8 +2042,8 @@ void JsonData::CloneFrom(const JsonData& other)
bool JsonData::IsIdentical(const JsonData& other) const
{
// Special case for int/float implicit conversion
if (((dataType == JSON_DATA_TYPE::INT) && (other.dataType == JSON_DATA_TYPE::FLOAT)) ||
((other.dataType == JSON_DATA_TYPE::INT) && (dataType == JSON_DATA_TYPE::FLOAT)))
if (((dataType == JDType::INT) && (other.dataType == JDType::FLOAT)) ||
((other.dataType == JDType::INT) && (dataType == JDType::FLOAT)))
{
// Here we have to get the float value via the getter because of implicit conversion
// Use the more precise precision of the two...
@ -2055,32 +2055,32 @@ bool JsonData::IsIdentical(const JsonData& other) const
switch (dataType)
{
case JSON_DATA_TYPE::__NULL__:
case JDType::__NULL__:
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
return intData == other.intData;
break;
case JSON_DATA_TYPE::INT:
case JDType::INT:
return intData == other.intData;
break;
case JSON_DATA_TYPE::FLOAT:
case JDType::FLOAT:
// Use the more precise precision of the two...
return Helpers::AreSame(floatData, other.floatData, Helpers::Min<double>(GetFloatPrecision(), other.GetFloatPrecision()));
break;
case JSON_DATA_TYPE::STRING:
case JDType::STRING:
return stringData == other.stringData;
break;
case JSON_DATA_TYPE::ARRAY:
case JDType::ARRAY:
return arrayData->IsIdentical(*other.arrayData);
break;
case JSON_DATA_TYPE::JSON:
case JDType::JSON:
return jsonData->IsIdentical(*other.jsonData);
break;
}
@ -2140,11 +2140,11 @@ bool JsonData::operator!=(const JsonData& other) const
JsonData& JsonData::operator+=(const JsonElement ele)
{
if (dataType == JSON_DATA_TYPE::JSON)
if (dataType == JDType::JSON)
{
return jsonData->Add(ele);
}
ThrowDataTypeException(JSON_DATA_TYPE::JSON);
ThrowDataTypeException(JDType::JSON);
std::terminate();
}
@ -2257,7 +2257,7 @@ JsonData::operator long double() 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);
}
@ -2266,7 +2266,7 @@ namespace JasonPP
{
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);
}
}
@ -2690,10 +2690,10 @@ bool JsonBlock::DoesShorthandExist(const std::string shorthand, const std::strin
const JsonBlock* jb = &const_cast<const JsonBlock&>(*this);
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 (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
@ -2718,10 +2718,10 @@ const JsonData& JsonBlock::ShorthandGet(const std::string shorthand, const std::
const JsonBlock* jb = &const_cast<const JsonBlock&>(*this);
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 (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
@ -2757,7 +2757,7 @@ JsonData& JsonBlock::ShorthandAdd(const std::string shorthand, const std::string
}
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();
}
}
@ -2804,7 +2804,7 @@ void JsonBlock::ShorthandRemove(const std::string shorthand, const std::string d
JsonData* dt = &ShorthandGet(shorthandParent, delimiter);
// 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();
}

View File

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

View File

@ -11,7 +11,10 @@ void LogHistory::PreInit()
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);
history->at(i) = nullptr;
@ -23,6 +26,29 @@ void LogHistory::PostExit()
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)
{
history->push_back(newEntry);
@ -31,3 +57,14 @@ void LogHistory::AddLogToHistory(LogEntry* newEntry)
}
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 <vector>
#include <ctime>
#include <sstream>
#include <fstream>
#include "LogTypes.h"
#include "XGConfig.h"
#include "JasonPP.hpp"
namespace Logging
{
@ -11,10 +15,13 @@ namespace Logging
class LogEntry
{
public:
std::string compiledMessage;
std::string message;
std::string identifier;
LOG_TYPE type;
std::time_t timestamp;
JasonPP::JsonBlock GetAsJson();
};
class LogHistory
@ -23,6 +30,8 @@ namespace Logging
static void PreInit();
static void PostExit();
static void Save();
static std::vector<LogEntry*>* GetLogHistory() { return history; }
private:

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@ bool RestQueryHandler::ProcessQuery(const std::string clientAdress, const Json&
{
log->SetAdditionalInformation(std::string("@") + clientAdress);
if (!ValidateField("request", JSON_DATA_TYPE::STRING, request, responseBody))
if (!ValidateField("request", JDType::STRING, request, responseBody))
{
responseCode = BAD_REQUEST;
return false;
@ -23,7 +23,10 @@ bool RestQueryHandler::ProcessQuery(const std::string clientAdress, const Json&
JsonBlock requestBody = request.AsJson;
std::string requestName = requestBody.Get("request").AsString;
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;
}
void Rest::RestQueryHandler::PostExit()
void RestQueryHandler::PostExit()
{
delete log;
log = nullptr;
@ -40,6 +43,15 @@ void Rest::RestQueryHandler::PostExit()
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)
{
XGControl::keepServerRunning = false;
@ -53,9 +65,9 @@ bool RestQueryHandler::KillYourself(const JsonBlock& request, JsonBlock& respons
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...");
return false;
@ -68,8 +80,8 @@ bool RestQueryHandler::ValidateField(const std::string name, const JasonPP::JSON
const JsonData& cached = cachedJson.ShorthandGet(name);
if ((cached.GetDataType() == type) ||
((cached.IsOfNumericType()) && (type == JSON_DATA_TYPE::INT)) ||
((cached.IsOfNumericType()) && (type == JSON_DATA_TYPE::FLOAT)))
((cached.IsOfNumericType()) && (type == JDType::INT)) ||
((cached.IsOfNumericType()) && (type == JDType::FLOAT)))
{
return true;
}

View File

@ -16,9 +16,10 @@ namespace Rest
static void PostExit();
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 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;
};

View File

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

View File

@ -36,9 +36,6 @@
<ClCompile Include="Framework.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="RestInterface.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="RestResponseTemplates.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
@ -48,6 +45,15 @@
<ClCompile Include="XGControl.cpp">
<Filter>Quelldateien</Filter>
</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>
<ClInclude Include="JasonPP.hpp">
@ -68,9 +74,6 @@
<ClInclude Include="Framework.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="RestInterface.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="RestResponseTemplates.h">
<Filter>Headerdateien</Filter>
</ClInclude>
@ -80,5 +83,14 @@
<ClInclude Include="XGControl.h">
<Filter>Headerdateien</Filter>
</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>
</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>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello, World!</title>
</head>
<body style="position: relative;">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello, World!</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<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;">
<p>
HELLO, WORLD :3
</p>
</div>
<body>
</body>
<h1 id="headline">Hello, World!</h1>
<div class="button-wrapper">
<div class="button" id="btn_foo">
<p>
Foo!
</p>
</div>
<div class="button" id="btn_killserver">
<p>
Kill server
</p>
</div>
</div>
<script src="/script.js"></script>
</body>
</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;
}