From 595e04bc328b4d812230e6a263032490e2b62891 Mon Sep 17 00:00:00 2001 From: "Leon Etienne (ubuntu wsl)" Date: Thu, 24 Sep 2020 14:31:30 +0200 Subject: [PATCH] Added basic rest framework --- Tubio/Framework.cpp | 7 +- Tubio/Framework.h | 8 +- Tubio/JasonPP.cpp | 56 +++++++-- Tubio/JasonPP.hpp | 10 +- Tubio/LogHistory.cpp | 4 +- Tubio/LogHistory.h | 2 +- Tubio/Logger.cpp | 30 ++--- Tubio/Logger.h | 18 +-- Tubio/RestInterface.cpp | 64 ++++++---- Tubio/RestInterface.h | 41 ++++--- Tubio/RestQueryHandler.cpp | 92 ++++++++++++++ Tubio/RestQueryHandler.h | 25 ++++ Tubio/RestResponseTemplates.cpp | 89 ++++++++++++++ Tubio/RestResponseTemplates.h | 33 +++++ Tubio/Tubio.vcxproj | 6 + Tubio/Tubio.vcxproj.filters | 18 +++ Tubio/XGControl.cpp | 3 + Tubio/XGControl.h | 11 ++ .../RestInterface.cpp | 116 ------------------ .../RestInterface.cpp | 114 ----------------- 20 files changed, 429 insertions(+), 318 deletions(-) create mode 100644 Tubio/RestQueryHandler.cpp create mode 100644 Tubio/RestQueryHandler.h create mode 100644 Tubio/RestResponseTemplates.cpp create mode 100644 Tubio/RestResponseTemplates.h create mode 100644 Tubio/XGControl.cpp create mode 100644 Tubio/XGControl.h delete mode 100644 enc_temp_folder/279148d2e95bb05a299ee9c83973619a/RestInterface.cpp delete mode 100644 enc_temp_folder/c03316ad742a6c4782beb0cc156430/RestInterface.cpp diff --git a/Tubio/Framework.cpp b/Tubio/Framework.cpp index 9657f11..c0914a3 100644 --- a/Tubio/Framework.cpp +++ b/Tubio/Framework.cpp @@ -1,6 +1,7 @@ #include "Framework.h" using namespace Logging; +using namespace Rest; Framework::Framework() { @@ -13,7 +14,7 @@ Framework::Framework() PostInit(); - isRunning = true; + XGControl::keepServerRunning = true; Run(); return; @@ -32,7 +33,7 @@ Framework::~Framework() void Framework::Run() { - while (isRunning) + while (XGControl::keepServerRunning) { restInterface->Update(); } @@ -48,6 +49,7 @@ void Framework::Run() void Framework::PreInit() { LogHistory::PreInit(); + RestQueryHandler::PreInit(); return; } @@ -70,6 +72,7 @@ void Framework::OnExit() void Framework::PostExit() { LogHistory::PostExit(); + RestQueryHandler::PostExit(); return; } diff --git a/Tubio/Framework.h b/Tubio/Framework.h index a61a584..f8da4db 100644 --- a/Tubio/Framework.h +++ b/Tubio/Framework.h @@ -2,6 +2,7 @@ #include "Logger.h" #include "LogHistory.h" #include "RestInterface.h" +#include "XGControl.h" class Framework { @@ -9,18 +10,17 @@ public: Framework(); ~Framework(); - void Run(); - private: + void Run(); void PostInit(); void OnExit(); void PreInit(); void PostExit(); - RestInterface* restInterface; + Rest::RestInterface* restInterface; - Log* log; + Logging::Logger* log; bool isRunning = true; }; diff --git a/Tubio/JasonPP.cpp b/Tubio/JasonPP.cpp index 12d435c..d224362 100644 --- a/Tubio/JasonPP.cpp +++ b/Tubio/JasonPP.cpp @@ -948,6 +948,7 @@ void JsonArray::Parse(const std::string jsonCode) bool areWeInString = false; bool areWeInCode = false; bool isCharEscaped = false; + bool areWeBetweenCommaAndValue = false; // Has the parser found a comma, but is still looking for the next value? for (std::size_t i = 0; i < minifiedCode.length(); i++) { @@ -957,13 +958,25 @@ void JsonArray::Parse(const std::string jsonCode) { start = i; areWeInCode = true; + areWeBetweenCommaAndValue = true; } else if ((!areWeInString) && (areWeInCode) && (arrayBracketLevel == 1) && (curlyBracketLevel == 0) && ((c == ',') || (i == minifiedCode.length() - 1))) { + if (c != ',') areWeBetweenCommaAndValue = false; end = i; areWeInCode = false; - dataJsonSnippets.push_back(minifiedCode.substr(start, end - start)); + + std::string codeSnippet = minifiedCode.substr(start, end - start); + if (codeSnippet.length() > 0) // A json data snippet can't be of size 0! + { + dataJsonSnippets.push_back(codeSnippet); + } + else + { + // JsonElement too short to be valid. + throw JsonParsingGeneralException(std::string("Fucked up a comma around position ") + Jstring((long long int)start)); + } } if ((!areWeInString) && (c == ']') && (arrayBracketLevel == 1) && (i != minifiedCode.length() - 1)) throw JsonParsingExpectedEOFException(minifiedCode.substr(i, minifiedCode.length() - i)); @@ -984,6 +997,7 @@ void JsonArray::Parse(const std::string jsonCode) // Someone fucked up his json code if (arrayBracketLevel != 0) throw JsonParsingMissingBracketsException(); if (curlyBracketLevel != 0) throw JsonParsingMissingBracketsException(); + if (areWeBetweenCommaAndValue) throw JsonParsingGeneralException("Unexpected EOF. Don't put a comma after the last value of a json array!"); if (areWeInString) throw JsonParsingMissingQuotesException(); } @@ -1090,7 +1104,7 @@ std::string StringHelpers::Replace(const std::string str, const std::string find return ss.str(); } -std::string StringHelpers::Escape(std::string str) +std::string StringHelpers::Escape(const std::string str) { std::stringstream ss; @@ -1120,7 +1134,6 @@ std::string StringHelpers::Escape(std::string str) ss << "\\\\"; break; default: - if (str[i] < 0) ss << EscapeUTF8(str[i]); else ss << str[i]; } @@ -1671,6 +1684,11 @@ double JsonData::GetFloatPrecision() const return customFloatPrecision; } +bool JsonData::IsOfNumericType() const +{ + return (dataType == JSON_DATA_TYPE::INT) || (dataType == JSON_DATA_TYPE::FLOAT); +} + bool JsonData::GetBoolData() const { JSON_DATA_TYPE typeToGet = JSON_DATA_TYPE::BOOL; @@ -2963,22 +2981,43 @@ void JsonBlock::Parse(const std::string jsonCode) bool areWeInString = false; bool areWeInCode = false; bool isCharEscaped = false; + bool areWeBetweenCommaAndLabel = false; // Has the parser found a comma, but is still looking for the next label? for (std::size_t i = 0; i < minifiedCode.length(); i++) { const char c = minifiedCode[i]; - if ((!areWeInString) && (c == '\"') && (arrayBracketLevel == 0) && (curlyBracketLevel == 1) && (!areWeInCode)) + if ((!areWeInString) && (arrayBracketLevel == 0) && (curlyBracketLevel == 1) && (!areWeInCode)) { - start = i; - areWeInCode = true; + if (c == '\"') + { + start = i; + areWeInCode = true; + areWeBetweenCommaAndLabel = false; + } + else if (c == ',') + { + // Did not find a label between two commas! + throw JsonParsingGeneralException(std::string("Fucked up a comma around position ") + Jstring((long long int)i)); + } } else if ((areWeInCode) && (arrayBracketLevel == 0) && (curlyBracketLevel == 1) && (!areWeInString) && ((c == ',') || (c == '}'))) { end = i; areWeInCode = false; - elementCodeSnippets.push_back(minifiedCode.substr(start, end - start)); + if (c == ',') areWeBetweenCommaAndLabel = true; + + std::string codeSnippet = minifiedCode.substr(start, end - start); + if (codeSnippet.length() >= 4) // Minimum length for valid JsonElement code. "":0 + { + elementCodeSnippets.push_back(codeSnippet); + } + else + { + // JsonElement too short to be valid. + throw JsonParsingGeneralException(std::string("Fucked up a comma around position ") + Jstring((long long int)start)); + } } // Our } at level 1 is not the last char? It should be! EXPECTED_END_OF_FILE_EXCEPTION :) @@ -2987,7 +3026,7 @@ void JsonBlock::Parse(const std::string jsonCode) if ((c == '\"') && (!areWeInString)) areWeInString = true; else if ((c == '\"') && (!isCharEscaped) && (areWeInString)) areWeInString = false; - // No need to check for char escaping since we are already checking if we are in a string or not. Chars are ever escaped outside of strings + // No need to check for char escaping since we are already checking if we are in a string or not. Chars are never escaped outside of strings if ((c == '[') && (!areWeInString)) arrayBracketLevel++; else if ((c == ']') && (!areWeInString)) arrayBracketLevel--; else if ((c == '{') && (!areWeInString)) curlyBracketLevel++; @@ -3001,6 +3040,7 @@ void JsonBlock::Parse(const std::string jsonCode) if (arrayBracketLevel != 0) throw JsonParsingMissingBracketsException(); if (curlyBracketLevel != 0) throw JsonParsingMissingBracketsException(); if (areWeInString) throw JsonParsingMissingQuotesException(); + if (areWeBetweenCommaAndLabel) throw JsonParsingGeneralException("Unexpected EOF. Don't put a comma after the last value of a json block!"); if ((elementCodeSnippets.size() == 0) && (minifiedCode.length() > 2)) throw JsonParsingGeneralException("Found no members in json block, but code is too long for no members"); } diff --git a/Tubio/JasonPP.hpp b/Tubio/JasonPP.hpp index 9d3c5b6..5c3fcdd 100644 --- a/Tubio/JasonPP.hpp +++ b/Tubio/JasonPP.hpp @@ -1053,7 +1053,7 @@ namespace JasonPP /// /// The original string to work in /// The string with escaped characters - static std::string Escape(std::string str); + static std::string Escape(const std::string str); /// /// Will unescape json strings @@ -1241,6 +1241,12 @@ namespace JasonPP /// The json data type of this object JSON_DATA_TYPE GetDataType() const { return dataType; }; + /// + /// Returns whether or not this JsonData is either of type FLOAT or INT + /// + /// Whether or not this JsonData is either of type FLOAT or INT + bool IsOfNumericType() const; + /// /// Returns the bool value of this element, exception if of wrong type /// @@ -2136,7 +2142,7 @@ namespace JasonPP }; } -#define JASONPP_VERSION (1.01) +#define JASONPP_VERSION (1.02) namespace JasonPP { diff --git a/Tubio/LogHistory.cpp b/Tubio/LogHistory.cpp index c8ef1d9..2083f45 100644 --- a/Tubio/LogHistory.cpp +++ b/Tubio/LogHistory.cpp @@ -23,9 +23,9 @@ void LogHistory::PostExit() return; } -void LogHistory::AddLogToHistory(LogEntry* _newEntry) +void LogHistory::AddLogToHistory(LogEntry* newEntry) { - history->push_back(_newEntry); + history->push_back(newEntry); return; } diff --git a/Tubio/LogHistory.h b/Tubio/LogHistory.h index 33ac04c..66bc7d8 100644 --- a/Tubio/LogHistory.h +++ b/Tubio/LogHistory.h @@ -26,7 +26,7 @@ namespace Logging static std::vector* GetLogHistory() { return history; } private: - static void AddLogToHistory(LogEntry* _newEntry); + static void AddLogToHistory(LogEntry* newEntry); static std::vector* history; diff --git a/Tubio/Logger.cpp b/Tubio/Logger.cpp index 943e58d..5713018 100644 --- a/Tubio/Logger.cpp +++ b/Tubio/Logger.cpp @@ -2,15 +2,15 @@ using namespace Logging; -Logger::Logger(std::string _identifier) +Logger::Logger(std::string identifier) { isInitialized = true; std::stringstream ss; - rawIdentifier = _identifier; + rawIdentifier = identifier; ss << "[" << rawIdentifier << "]"; - identifier = ss.str(); + this->identifier = ss.str(); return; } @@ -25,12 +25,12 @@ void Logger::Clear() return; } -void Logger::Set(std::string _str) +void Logger::Set(std::string str) { if (!IsInitializedSanityCheck()) return; Clear(); - cout << _str; + cout << str; return; } @@ -44,7 +44,7 @@ std::string Logger::Flush() tm currTm; localtime_s(&currTm, &currTime); char timeBuf[256]; - strftime(timeBuf, 100, "%d.%m.%Y - %T", currTm); + strftime(timeBuf, 100, "%d.%m.%Y - %T", &currTm); std::stringstream bufOut; bufOut << "<" << timeBuf << "> " << identifier << TypeToPrefix(type) << ": " << cout.str(); @@ -56,25 +56,25 @@ std::string Logger::Flush() newEntry->type = type; LogHistory::AddLogToHistory(newEntry); - std::cout << TypeToColor(type) << bufOut.str() << "\033[0m" << std::endl; + std::cout << bufOut.str() << std::endl; Clear(); return ""; } -std::string Logger::Type(LOG_TYPE _type) +std::string Logger::Type(LOG_TYPE type) { if (!IsInitializedSanityCheck()) return ""; - type = _type; + this->type = type; return ""; } -std::string Logger::TypeToPrefix(LOG_TYPE _type) +std::string Logger::TypeToPrefix(LOG_TYPE type) { - switch (_type) + switch (type) { case LOG_TYPE::LOG: return ""; @@ -94,7 +94,7 @@ std::string Logger::TypeToPrefix(LOG_TYPE _type) std::string Logger::TypeToColor(LOG_TYPE _type) { - switch (_type) + /*switch (_type) { case LOG_TYPE::LOG: return "\033[0m"; @@ -109,7 +109,8 @@ std::string Logger::TypeToColor(LOG_TYPE _type) return "\033[0m"; } - return "\033[0m"; + return "\033[0m";*/ + return ""; } bool Logger::IsInitializedSanityCheck() @@ -117,7 +118,8 @@ bool Logger::IsInitializedSanityCheck() if (!isInitialized) { Logger log("Logger"); //A Log object cannot always have a Log-member because of its recursive nature. Only create them when needed! - log.cout << log.Err() << "Attempted to use logger object without being initialized!" << log.Flush(); + log.cout << log.Err() << "Attempted to use logger object without being initialized!"; + log.Flush(); return false; } diff --git a/Tubio/Logger.h b/Tubio/Logger.h index e851e33..47794df 100644 --- a/Tubio/Logger.h +++ b/Tubio/Logger.h @@ -7,43 +7,43 @@ namespace Logging { - class Log + class Logger { public: public: //Creates a Logger object. Pass an identifier such as MySQL - Log(std::string _identifier); + Logger(std::string identifier); //Clears the buffered string and resets the log type to default void Clear(); //Sets the buffered string - void Set(std::string _str); + void Set(std::string str); //Prints the buffered string to the console and clears it std::string Flush(); //Sets a custom log type - std::string Type(LOG_TYPE _type); + std::string Type(LOG_TYPE type); //Sets the log type to warning - std::string Warn() { return Type(WARN); } + std::string Warn() { return Type(LOG_TYPE::WARN); } //Sets the log type to error - std::string Err() { return Type(ERR); } + std::string Err() { return Type(LOG_TYPE::ERR); } std::stringstream cout; private: - std::string TypeToPrefix(LOG_TYPE _type); - std::string TypeToColor(LOG_TYPE _type); + std::string TypeToPrefix(LOG_TYPE type); + std::string TypeToColor(LOG_TYPE type); bool IsInitializedSanityCheck(); std::string identifier; std::string rawIdentifier; - LOG_TYPE type = LOG; + LOG_TYPE type = LOG_TYPE::LOG; bool isInitialized = false; }; diff --git a/Tubio/RestInterface.cpp b/Tubio/RestInterface.cpp index 0b30f2b..dbfad08 100644 --- a/Tubio/RestInterface.cpp +++ b/Tubio/RestInterface.cpp @@ -1,6 +1,8 @@ #include "RestInterface.h" using namespace Logging; +using namespace Rest; +using namespace JasonPP; RestInterface::RestInterface() { @@ -28,7 +30,6 @@ void RestInterface::PostInit() { isBootedSuccessfully = InitWebServer(); - return; } @@ -64,45 +65,42 @@ void RestInterface::Update() return; } -void RestInterface::ServeStringToConnection(struct mg_connection* _c, std::string _str) +void RestInterface::ServeStringToConnection(struct mg_connection* c, std::string str, int httpStatusCode) { - mg_send_head(_c, 200, _str.length(), "content-type: application/json\nAccess-Control-Allow-Origin: *"); - mg_printf(_c, _str.c_str()); + mg_send_head(c, httpStatusCode, str.length(), "content-type: application/json\nAccess-Control-Allow-Origin: *"); + mg_printf(c, str.c_str()); return; } - -void RestInterface::EventHandler(mg_connection* _pNc, int _ev, void* _p) +void RestInterface::EventHandler(mg_connection* pNc, int ev, void* p) { - switch (_ev) + switch (ev) { case MG_EV_HTTP_REQUEST: - /* - StringParser sp(_pNc->recv_mbuf.buf); + http_message* hpm = (http_message*)p; + std::string requestBodyRaw = FixUnterminatedString(hpm->body.p, hpm->body.len); - sp.Skip("GET /"); - std::string rawRequest = sp.ExtSeek(" HTTP/"); - std::string jsonQuery = StringTools::UrlDecode(rawRequest); + if (IsJsonValid(requestBodyRaw)) + { + Json requestBody; + requestBody.Parse(requestBodyRaw); + + JsonBlock responseBody; + HTTP_STATUS_CODE returnCode; + RestQueryHandler::ProcessQuery(requestBody, responseBody, returnCode); - std::string queryResult = RestAPIQueryHandler::ProcessQuery(jsonQuery); + Json response(responseBody); + ServeStringToConnection(pNc, response.Render(), returnCode); + } + else + { + Json errorJson = RestResponseTemplates::GetByCode(HTTP_STATUS_CODE::BAD_REQUEST, "Received json is fucked up"); + ServeStringToConnection(pNc, errorJson.Render(), HTTP_STATUS_CODE::BAD_REQUEST); + } - - ServeStringToConnection(_pNc, queryResult); - */ - - //std::cout << _pNc->recv_mbuf.buf << std::endl; - - http_message* hpm = (http_message*)_p; - - char buf[500]; - mg_get_http_var(&hpm->body, "data", buf, 500); - std::cout << buf << std::endl; - - ServeStringToConnection(_pNc, _pNc->recv_mbuf.buf); - break; } @@ -115,3 +113,15 @@ void RestInterface::OnExit() return; } + + +std::string RestInterface::FixUnterminatedString(const char* cstr, const std::size_t len) +{ + std::stringstream ss; + for (std::size_t i = 0; i < len; i++) + { + ss << *(cstr + i); + } + + return ss.str(); +} diff --git a/Tubio/RestInterface.h b/Tubio/RestInterface.h index ed4f489..6da03f8 100644 --- a/Tubio/RestInterface.h +++ b/Tubio/RestInterface.h @@ -4,34 +4,37 @@ #include #include "mongoose.h" #include "Logger.h" +#include "RestResponseTemplates.h" +#include "RestQueryHandler.h" #define WEBAPI_SERVER_POLLRATE 100 #define WEBAPI_SERVER_PORT "6969" -class RestInterface +namespace Rest { -public: - RestInterface(); - ~RestInterface(); + class RestInterface + { + public: + RestInterface(); + ~RestInterface(); - void PostInit(); - void Update(); - void OnExit(); + void PostInit(); + void Update(); + void OnExit(); -private: - bool InitWebServer(); + private: + bool InitWebServer(); - static void EventHandler(struct mg_connection* _pNc, int _ev, void* _p); - - static void ServeStringToConnection(struct mg_connection* _c, std::string _str); + static void EventHandler(struct mg_connection* pNc, int ev, void* p); + static void ServeStringToConnection(struct mg_connection* c, std::string str, int httpStatusCode = 200); + static std::string FixUnterminatedString(const char* cstr, const std::size_t len); - struct mg_mgr* pMgr; - struct mg_connection* pNc; - static mg_serve_http_opts pServeOpts; + struct mg_mgr* pMgr; + struct mg_connection* pNc; - Logging::Logger* log; - - bool isBootedSuccessfully; -}; + Logging::Logger* log; + bool isBootedSuccessfully; + }; +} diff --git a/Tubio/RestQueryHandler.cpp b/Tubio/RestQueryHandler.cpp new file mode 100644 index 0000000..e4fe605 --- /dev/null +++ b/Tubio/RestQueryHandler.cpp @@ -0,0 +1,92 @@ +#include "RestQueryHandler.h" + +using namespace Rest; +using namespace Logging; +using namespace JasonPP; + +void RestQueryHandler::PreInit() +{ + log = new Logger("RestQueryHandler"); + + return; +} + +bool RestQueryHandler::ProcessQuery(const Json& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +{ + if (!ValidateField("request", JSON_DATA_TYPE::STRING, request, responseBody)) + { + responseCode = BAD_REQUEST; + return false; + } + JsonBlock requestBody = request.AsJson; + std::string requestName = requestBody.Get("request").AsString; + + if (requestName == "kill_yourself") return KillYourself(requestBody, responseBody, responseCode); + + + + responseBody.CloneFrom(RestResponseTemplates::GetByCode(NOT_FOUND, "The requested request was not found.")); + responseCode = NOT_FOUND; + return false; +} + +void Rest::RestQueryHandler::PostExit() +{ + delete log; + log = nullptr; + + return; +} + +bool RestQueryHandler::KillYourself(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +{ + XGControl::keepServerRunning = false; + + log->cout << "Shutting down server upon rest request..."; + log->Flush(); + + responseCode = OK; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); + responseBody.Set("message") = "Goodbye! :3"; + return true; +} + +bool RestQueryHandler::ValidateField(const std::string name, const JasonPP::JSON_DATA_TYPE type, const JasonPP::Json& checkThat, JasonPP::JsonBlock& putErrorResponseHere) +{ + if (checkThat.GetDataType() != JSON_DATA_TYPE::JSON) + { + putErrorResponseHere = RestResponseTemplates::GetByCode(BAD_REQUEST, "The request body must be a json struct! No json array or similar..."); + return false; + } + + const JsonBlock& cachedJson = checkThat.AsJson; + + if (cachedJson.DoesShorthandExist(name)) + { + const JsonData& cached = cachedJson.ShorthandGet(name); + + if ((cached.GetDataType() == type) || + ((cached.IsOfNumericType()) && (type == JSON_DATA_TYPE::INT)) || + ((cached.IsOfNumericType()) && (type == JSON_DATA_TYPE::FLOAT))) + { + return true; + } + else + { + std::stringstream ss; + ss << "Mandatory value \"" << name << "\" is of wrong type (" << JsonDataType2String(cached.GetDataType()) << ")" << std::endl; + ss << "Should be of type " << JsonDataType2String(type) << "! (Integers can be casted to floats)"; + + putErrorResponseHere.CloneFrom(RestResponseTemplates::GetByCode(BAD_REQUEST, ss.str())); + } + } + else + { + putErrorResponseHere.CloneFrom(RestResponseTemplates::GetByCode(BAD_REQUEST, std::string("Missing mandatory value '" + name + "'"))); + return false; + } + + return false; +} + +Logger* RestQueryHandler::log; \ No newline at end of file diff --git a/Tubio/RestQueryHandler.h b/Tubio/RestQueryHandler.h new file mode 100644 index 0000000..8291555 --- /dev/null +++ b/Tubio/RestQueryHandler.h @@ -0,0 +1,25 @@ +#pragma once +#include "JasonPP.hpp" +#include "RestResponseTemplates.h" +#include "XGControl.h" +#include "Logger.h" + +namespace Rest +{ + class RestQueryHandler + { + public: + static void PreInit(); + + static bool ProcessQuery(const JasonPP::Json& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); + + static void PostExit(); + + private: + 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 Logging::Logger* log; + }; +} diff --git a/Tubio/RestResponseTemplates.cpp b/Tubio/RestResponseTemplates.cpp new file mode 100644 index 0000000..6d84ed1 --- /dev/null +++ b/Tubio/RestResponseTemplates.cpp @@ -0,0 +1,89 @@ +#include "RestResponseTemplates.h" + +using namespace JasonPP; + +/* +Every query MUST have a value for "status" +Every query with status = "ERROR" MUST have a value for "description" and "message"! +*/ + +JsonBlock Rest::RestResponseTemplates::GetByCode(HTTP_STATUS_CODE code, std::string message) +{ + switch (code) + { + case HTTP_STATUS_CODE::OK: + return OK(); + case HTTP_STATUS_CODE::BAD_REQUEST: + return BadRequest(message); + case HTTP_STATUS_CODE::FORBIDDEN: + return Forbidden((message.length() > 0) ? message : "Could be disabled in the config file!"); + case HTTP_STATUS_CODE::NOT_FOUND: + return NotFound((message.length() > 0) ? message : "not found"); + case HTTP_STATUS_CODE::INTERNAL_SERVER_ERROR: + return InternalServerError((message.length() > 0) ? message : "Well, that's not good."); + case HTTP_STATUS_CODE::NOT_IMPLEMENTED: + return NotImplemented(message); + } + return InternalServerError("No template found for this http-status-code"); +} + +JsonBlock Rest::RestResponseTemplates::OK() +{ + return JsonBlock({ + Ele("status", "OK"), + }); +} + +JsonBlock Rest::RestResponseTemplates::BadRequest(std::string message) +{ + return JsonBlock({ + Ele("status", "ERROR"), + Ele("description", "Bad request"), + Ele("message", message) + }); +} + +JsonBlock Rest::RestResponseTemplates::Unauthorized(std::string message) +{ + return JsonBlock({ + Ele("status", "ERROR"), + Ele("description", "Unauthorized"), + Ele("message", message) + }); +} + +JsonBlock Rest::RestResponseTemplates::Forbidden(std::string message) +{ + return JsonBlock({ + Ele("status", "ERROR"), + Ele("description", "Forbidden"), + Ele("message", message) + }); +} + +JsonBlock Rest::RestResponseTemplates::NotFound(std::string message) +{ + return JsonBlock({ + Ele("status", "ERROR"), + Ele("description", "Not found"), + Ele("message", message) + }); +} + +JsonBlock Rest::RestResponseTemplates::InternalServerError(std::string message) +{ + return JsonBlock({ + Ele("status", "ERROR"), + Ele("description", "Internal server error"), + Ele("message", message) + }); +} + +JsonBlock Rest::RestResponseTemplates::NotImplemented(std::string message) +{ + return JsonBlock({ + Ele("status", "ERROR"), + Ele("description", "Not implemented"), + Ele("message", message) + }); +} diff --git a/Tubio/RestResponseTemplates.h b/Tubio/RestResponseTemplates.h new file mode 100644 index 0000000..56473fa --- /dev/null +++ b/Tubio/RestResponseTemplates.h @@ -0,0 +1,33 @@ +#pragma once +#include "JasonPP.hpp" + +namespace Rest +{ + enum HTTP_STATUS_CODE { + OK = 200, + BAD_REQUEST = 400, + UNAUTHORIZED = 401, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + INTERNAL_SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501 + }; + + class RestResponseTemplates + { + public: + static JasonPP::JsonBlock GetByCode(HTTP_STATUS_CODE code, std::string message = ""); + + private: + static JasonPP::JsonBlock OK(); + static JasonPP::JsonBlock BadRequest(std::string message); + static JasonPP::JsonBlock Unauthorized(std::string message); + static JasonPP::JsonBlock Forbidden(std::string message); + static JasonPP::JsonBlock NotFound(std::string message); + static JasonPP::JsonBlock MethodNotAllowed(std::string message); + + static JasonPP::JsonBlock InternalServerError(std::string message); + static JasonPP::JsonBlock NotImplemented(std::string message); + }; +} diff --git a/Tubio/Tubio.vcxproj b/Tubio/Tubio.vcxproj index d263da1..5a7fda0 100644 --- a/Tubio/Tubio.vcxproj +++ b/Tubio/Tubio.vcxproj @@ -145,7 +145,10 @@ + + + @@ -154,7 +157,10 @@ + + + diff --git a/Tubio/Tubio.vcxproj.filters b/Tubio/Tubio.vcxproj.filters index 16dc41a..b84e1dc 100644 --- a/Tubio/Tubio.vcxproj.filters +++ b/Tubio/Tubio.vcxproj.filters @@ -39,6 +39,15 @@ Quelldateien + + Quelldateien + + + Quelldateien + + + Quelldateien + @@ -62,5 +71,14 @@ Headerdateien + + Headerdateien + + + Headerdateien + + + Headerdateien + \ No newline at end of file diff --git a/Tubio/XGControl.cpp b/Tubio/XGControl.cpp new file mode 100644 index 0000000..9ddc0d2 --- /dev/null +++ b/Tubio/XGControl.cpp @@ -0,0 +1,3 @@ +#include "XGControl.h" + +bool XGControl::keepServerRunning = false; diff --git a/Tubio/XGControl.h b/Tubio/XGControl.h new file mode 100644 index 0000000..d12aa6e --- /dev/null +++ b/Tubio/XGControl.h @@ -0,0 +1,11 @@ +#pragma once + +/// +/// Class to house control variables +/// +class XGControl +{ +public: + static bool keepServerRunning; +}; + diff --git a/enc_temp_folder/279148d2e95bb05a299ee9c83973619a/RestInterface.cpp b/enc_temp_folder/279148d2e95bb05a299ee9c83973619a/RestInterface.cpp deleted file mode 100644 index a59e3b4..0000000 --- a/enc_temp_folder/279148d2e95bb05a299ee9c83973619a/RestInterface.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "RestInterface.h" - -using namespace Logging; - -RestInterface::RestInterface() -{ - pMgr = new mg_mgr(); - pNc = nullptr; - log = new Logger("WebServer"); - - isBootedSuccessfully = false; - - return; -} - -RestInterface::~RestInterface() -{ - delete pMgr; - delete log; - - log = nullptr; - pMgr = nullptr; - - return; -} - -void RestInterface::PostInit() -{ - isBootedSuccessfully = InitWebServer(); - - - return; -} - -bool RestInterface::InitWebServer() -{ - mg_mgr_init(pMgr, NULL); - - log->cout << "Starting web server on port " << WEBAPI_SERVER_PORT << "..."; - log->Flush(); - - pNc = mg_bind(pMgr, WEBAPI_SERVER_PORT, this->EventHandler); - - if (pNc == NULL) - { - log->cout << log->Err() << "Failed to boot the web server! - Unable to bind listener!"; - log->Flush(); - return false; - } - - mg_set_protocol_http_websocket(pNc); - - log->cout << "Started web server successfully!"; - log->Flush(); - isBootedSuccessfully = true; - - return true; -} - -void RestInterface::Update() -{ - mg_mgr_poll(pMgr, WEBAPI_SERVER_POLLRATE); - - return; -} - -void RestInterface::ServeStringToConnection(struct mg_connection* _c, std::string _str) -{ - mg_send_head(_c, 200, _str.length(), "content-type: application/json\nAccess-Control-Allow-Origin: *"); - mg_printf(_c, _str.c_str()); - - return; -} - - -void RestInterface::EventHandler(mg_connection* _pNc, int _ev, void* _p) -{ - switch (_ev) - { - case MG_EV_HTTP_REQUEST: - - /* - StringParser sp(_pNc->recv_mbuf.buf); - - sp.Skip("GET /"); - std::string rawRequest = sp.ExtSeek(" HTTP/"); - std::string jsonQuery = StringTools::UrlDecode(rawRequest); - - std::string queryResult = RestAPIQueryHandler::ProcessQuery(jsonQuery); - - - - ServeStringToConnection(_pNc, queryResult); - */ - - //std::cout << _pNc->recv_mbuf.buf << std::endl; - - http_message* hpm = (http_message*)_p; - - char buf[500]; - mg_get_http_var(&hpm->body, "data", buf, 500); - - ServeStringToConnection(_pNc, _pNc->recv_mbuf.buf); - - break; - } - - return; -} - -void RestInterface::OnExit() -{ - mg_mgr_free(pMgr); - - return; -} diff --git a/enc_temp_folder/c03316ad742a6c4782beb0cc156430/RestInterface.cpp b/enc_temp_folder/c03316ad742a6c4782beb0cc156430/RestInterface.cpp deleted file mode 100644 index 535cac5..0000000 --- a/enc_temp_folder/c03316ad742a6c4782beb0cc156430/RestInterface.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "RestInterface.h" - -using namespace Logging; - -RestInterface::RestInterface() -{ - pMgr = new mg_mgr(); - pNc = nullptr; - log = new Logger("WebServer"); - - isBootedSuccessfully = false; - - return; -} - -RestInterface::~RestInterface() -{ - delete pMgr; - delete log; - - log = nullptr; - pMgr = nullptr; - - return; -} - -void RestInterface::PostInit() -{ - isBootedSuccessfully = InitWebServer(); - - - return; -} - -bool RestInterface::InitWebServer() -{ - mg_mgr_init(pMgr, NULL); - - log->cout << "Starting web server on port " << WEBAPI_SERVER_PORT << "..."; - log->Flush(); - - pNc = mg_bind(pMgr, WEBAPI_SERVER_PORT, this->EventHandler); - - if (pNc == NULL) - { - log->cout << log->Err() << "Failed to boot the web server! - Unable to bind listener!"; - log->Flush(); - return false; - } - - mg_set_protocol_http_websocket(pNc); - - log->cout << "Started web server successfully!"; - log->Flush(); - isBootedSuccessfully = true; - - return true; -} - -void RestInterface::Update() -{ - mg_mgr_poll(pMgr, WEBAPI_SERVER_POLLRATE); - - return; -} - -void RestInterface::ServeStringToConnection(struct mg_connection* _c, std::string _str) -{ - mg_send_head(_c, 200, _str.length(), "content-type: application/json\nAccess-Control-Allow-Origin: *"); - mg_printf(_c, _str.c_str()); - - return; -} - - -void RestInterface::EventHandler(mg_connection* _pNc, int _ev, void* _p) -{ - switch (_ev) - { - case MG_EV_HTTP_REQUEST: - - /* - StringParser sp(_pNc->recv_mbuf.buf); - - sp.Skip("GET /"); - std::string rawRequest = sp.ExtSeek(" HTTP/"); - std::string jsonQuery = StringTools::UrlDecode(rawRequest); - - std::string queryResult = RestAPIQueryHandler::ProcessQuery(jsonQuery); - - - - ServeStringToConnection(_pNc, queryResult); - */ - - std::cout << _pNc->recv_mbuf.buf << std::endl; - - http_message* hpm = (http_message*)_p; - - std::cout << hpm << std::endl; - ServeStringToConnection(_pNc, _pNc->recv_mbuf.buf); - - break; - } - - return; -} - -void RestInterface::OnExit() -{ - mg_mgr_free(pMgr); - - return; -}