diff --git a/.gitignore b/.gitignore index 296f0ee..c3dcaf9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,11 @@ *.userosscache *.sln.docstates +# Tubio files +config.json +log.txt +log.json + # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs diff --git a/Tubio/FileSystem.cpp b/Tubio/FileSystem.cpp new file mode 100644 index 0000000..df12e11 --- /dev/null +++ b/Tubio/FileSystem.cpp @@ -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(ifs), + std::istreambuf_iterator(), + std::ostreambuf_iterator(ofs)); + + return true; +} + +bool FileSystem::Delete(std::string filename) +{ + if (!Exists(filename)) return false; + remove(filename.c_str()); + return true; +} diff --git a/Tubio/FileSystem.h b/Tubio/FileSystem.h new file mode 100644 index 0000000..9ef2e48 --- /dev/null +++ b/Tubio/FileSystem.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include +#include +#include + +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: + +}; + diff --git a/Tubio/Framework.cpp b/Tubio/Framework.cpp index 6a45e58..0cb742f 100644 --- a/Tubio/Framework.cpp +++ b/Tubio/Framework.cpp @@ -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; } diff --git a/Tubio/Framework.h b/Tubio/Framework.h index f8da4db..49751b8 100644 --- a/Tubio/Framework.h +++ b/Tubio/Framework.h @@ -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; diff --git a/Tubio/RestInterface.cpp b/Tubio/HttpServer.cpp similarity index 66% rename from Tubio/RestInterface.cpp rename to Tubio/HttpServer.cpp index 2ff88f6..bfaf0c6 100644 --- a/Tubio/RestInterface.cpp +++ b/Tubio/HttpServer.cpp @@ -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; diff --git a/Tubio/RestInterface.h b/Tubio/HttpServer.h similarity index 82% rename from Tubio/RestInterface.h rename to Tubio/HttpServer.h index 2276f0d..1456478 100644 --- a/Tubio/RestInterface.h +++ b/Tubio/HttpServer.h @@ -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(); diff --git a/Tubio/JasonPP.cpp b/Tubio/JasonPP.cpp index d224362..31697fa 100644 --- a/Tubio/JasonPP.cpp +++ b/Tubio/JasonPP.cpp @@ -1,25 +1,25 @@ /* -MIT License - -JasonPP, Copyright (c) 2020, Leon Etienne - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -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 -SOFTWARE. +MIT License + +JasonPP, Copyright (c) 2020, Leon Etienne + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +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 +SOFTWARE. */ #include "JasonPP.hpp" @@ -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 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(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(*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(*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(); } diff --git a/Tubio/JasonPP.hpp b/Tubio/JasonPP.hpp index 5c3fcdd..c5746cd 100644 --- a/Tubio/JasonPP.hpp +++ b/Tubio/JasonPP.hpp @@ -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 -#define Ele JasonPP::JsonElement +#define Arr std::vector<::JasonPP::JsonData> +#define Ele ::JasonPP::JsonElement #endif diff --git a/Tubio/LogHistory.cpp b/Tubio/LogHistory.cpp index 2083f45..3c3c1e7 100644 --- a/Tubio/LogHistory.cpp +++ b/Tubio/LogHistory.cpp @@ -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* 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), + }); +} diff --git a/Tubio/LogHistory.h b/Tubio/LogHistory.h index 66bc7d8..ca2c166 100644 --- a/Tubio/LogHistory.h +++ b/Tubio/LogHistory.h @@ -2,7 +2,11 @@ #include #include #include +#include +#include #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* GetLogHistory() { return history; } private: diff --git a/Tubio/LogTypes.h b/Tubio/LogTypes.h index a3f6dd4..f1ac5cc 100644 --- a/Tubio/LogTypes.h +++ b/Tubio/LogTypes.h @@ -2,7 +2,7 @@ namespace Logging { - enum class LOG_TYPE + enum LOG_TYPE { LOG, WARN, diff --git a/Tubio/Logger.cpp b/Tubio/Logger.cpp index 97a3de3..357b323 100644 --- a/Tubio/Logger.cpp +++ b/Tubio/Logger.cpp @@ -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; diff --git a/Tubio/Logger.h b/Tubio/Logger.h index 7d88b3f..7f578ea 100644 --- a/Tubio/Logger.h +++ b/Tubio/Logger.h @@ -3,7 +3,6 @@ #include #include #include "LogTypes.h" -#include "LogHistory.h" namespace Logging { diff --git a/Tubio/RestQueryHandler.cpp b/Tubio/RestQueryHandler.cpp index 6a69baf..28e9f7f 100644 --- a/Tubio/RestQueryHandler.cpp +++ b/Tubio/RestQueryHandler.cpp @@ -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; } diff --git a/Tubio/RestQueryHandler.h b/Tubio/RestQueryHandler.h index 01ef0a0..8984c13 100644 --- a/Tubio/RestQueryHandler.h +++ b/Tubio/RestQueryHandler.h @@ -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; }; diff --git a/Tubio/Tubio.vcxproj b/Tubio/Tubio.vcxproj index 5a7fda0..5ad5a1c 100644 --- a/Tubio/Tubio.vcxproj +++ b/Tubio/Tubio.vcxproj @@ -86,7 +86,7 @@ Level3 true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + JASONPP_RENDER_SORTED;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -139,6 +139,7 @@ + @@ -147,10 +148,12 @@ - + + + @@ -159,7 +162,8 @@ - + + diff --git a/Tubio/Tubio.vcxproj.filters b/Tubio/Tubio.vcxproj.filters index b84e1dc..b01d533 100644 --- a/Tubio/Tubio.vcxproj.filters +++ b/Tubio/Tubio.vcxproj.filters @@ -36,9 +36,6 @@ Quelldateien - - Quelldateien - Quelldateien @@ -48,6 +45,15 @@ Quelldateien + + Quelldateien + + + Quelldateien + + + Quelldateien + @@ -68,9 +74,6 @@ Headerdateien - - Headerdateien - Headerdateien @@ -80,5 +83,14 @@ Headerdateien + + Headerdateien + + + Headerdateien + + + Headerdateien + \ No newline at end of file diff --git a/Tubio/XGConfig.cpp b/Tubio/XGConfig.cpp new file mode 100644 index 0000000..86b7c4d --- /dev/null +++ b/Tubio/XGConfig.cpp @@ -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; diff --git a/Tubio/XGConfig.h b/Tubio/XGConfig.h new file mode 100644 index 0000000..8a6c44d --- /dev/null +++ b/Tubio/XGConfig.h @@ -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(); +}; + diff --git a/Tubio/frontend/index.html b/Tubio/frontend/index.html index 7ea7ce8..6e63e9e 100644 --- a/Tubio/frontend/index.html +++ b/Tubio/frontend/index.html @@ -1,17 +1,32 @@ - - - - Hello, World! - - + + + + Hello, World! + + + + -
-

- HELLO, WORLD :3 -

-
- - + + +

Hello, World!

+ +
+
+

+ Foo! +

+
+
+

+ Kill server +

+
+
+ + + + diff --git a/Tubio/frontend/script.js b/Tubio/frontend/script.js new file mode 100644 index 0000000..a016338 --- /dev/null +++ b/Tubio/frontend/script.js @@ -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"); + } + }); +}); diff --git a/Tubio/frontend/style.css b/Tubio/frontend/style.css new file mode 100644 index 0000000..06668af --- /dev/null +++ b/Tubio/frontend/style.css @@ -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; +}