Added a prettier web interface placeholder
This commit is contained in:
parent
99c429872b
commit
4f68951725
5
.gitignore
vendored
5
.gitignore
vendored
@ -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
62
Tubio/FileSystem.cpp
Normal 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
20
Tubio/FileSystem.h
Normal 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:
|
||||
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
@ -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();
|
@ -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<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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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),
|
||||
});
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Logging
|
||||
{
|
||||
enum class LOG_TYPE
|
||||
enum LOG_TYPE
|
||||
{
|
||||
LOG,
|
||||
WARN,
|
||||
|
@ -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;
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include "LogTypes.h"
|
||||
#include "LogHistory.h"
|
||||
|
||||
namespace Logging
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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" />
|
||||
|
@ -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
200
Tubio/XGConfig.cpp
Normal 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
43
Tubio/XGConfig.h
Normal 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();
|
||||
};
|
||||
|
@ -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
27
Tubio/frontend/script.js
Normal 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
75
Tubio/frontend/style.css
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user