diff --git a/Tubio/DownloadManager.h b/Tubio/DownloadManager.h index 8660ca9..7f0ce05 100644 --- a/Tubio/DownloadManager.h +++ b/Tubio/DownloadManager.h @@ -7,6 +7,7 @@ #include "FileSystem.h" #include "XGConfig.h" #include "Logger.h" +#include "LogHistory.h" namespace Downloader { diff --git a/Tubio/JasonPP.cpp b/Tubio/JasonPP.cpp index 3893d85..6b649c4 100644 --- a/Tubio/JasonPP.cpp +++ b/Tubio/JasonPP.cpp @@ -455,6 +455,35 @@ void JsonArray::Add(const std::vector data) return; } +void JsonArray::Merge(const JsonArray& other) +{ + // If merging into itself, we have to cache a copy of itself in the beginning state + if (this == &other) + { + JsonArray clonedOther; + clonedOther.CloneFrom(other); + + for (std::size_t i = 0; i < clonedOther.Size(); i++) + { + JsonData jd; + jd.CloneFrom(clonedOther.At(i)); + Add(jd); + } + } + else + { + // All ok, merging from a different array + for (std::size_t i = 0; i < other.Size(); i++) + { + JsonData jd; + jd.CloneFrom(other.At(i)); + Add(jd); + } + } + + return; +} + void JsonArray::InsertExistingtJsonData(const std::vector data) { for (std::size_t i = 0; i < data.size(); i++) diff --git a/Tubio/JasonPP.hpp b/Tubio/JasonPP.hpp index a9cf535..4d60869 100644 --- a/Tubio/JasonPP.hpp +++ b/Tubio/JasonPP.hpp @@ -629,6 +629,12 @@ namespace JasonPP /// To be added void Add(const std::vector data); + /// + /// Will merge JsonArray other into this, deep-copying all values. + /// + /// Array to merge-copy from + void Merge(const JsonArray& other); + /// /// Will append the object given /// @@ -2142,7 +2148,7 @@ namespace JasonPP }; } -#define JASONPP_VERSION (1.0215) +#define JASONPP_VERSION (1.0216) namespace JasonPP { diff --git a/Tubio/LogHistory.cpp b/Tubio/LogHistory.cpp index a16efba..5a1b1f4 100644 --- a/Tubio/LogHistory.cpp +++ b/Tubio/LogHistory.cpp @@ -42,12 +42,12 @@ void LogHistory::Update() void LogHistory::Save() { std::stringstream textfile; - JasonPP::Json jsonFile = JasonPP::JsonArray(); + JasonPP::Json newJsonLogs = 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(); + newJsonLogs.AsArray += history->at(i)->GetAsJson(); } std::ofstream ofs; @@ -55,9 +55,41 @@ void LogHistory::Save() ofs << textfile.str(); ofs.close(); - ofs.open(XGConfig::logging.logfile_json, std::ios::app); - ofs << jsonFile.Render(); - ofs.close(); + // You can't just append to a json array file... + // You have to first parse it, append to it, and then rewrite the complete file + { + JasonPP::Json allLogs; + + if (FileSystem::Exists(XGConfig::logging.logfile_json)) + { + std::string fileContent = FileSystem::ReadFile(XGConfig::logging.logfile_json); + if (JasonPP::IsJsonValid(fileContent)) + { + allLogs.Parse(fileContent); + if (allLogs.GetDataType() != JasonPP::JDType::ARRAY) + { + // Json file is fucked (wrong format). Reset to empty array + allLogs.SetArrayData(JasonPP::JsonArray()); + } + } + else + { + // Json file is fucked (wrong syntax). Reset to empty array + allLogs.SetArrayData(JasonPP::JsonArray()); + } + } + else + { + // Json file is fucked (doesn't exist). Reset to empty array + allLogs.SetArrayData(JasonPP::JsonArray()); + } + + allLogs.AsArray.Merge(newJsonLogs.AsArray); + ofs.open(XGConfig::logging.logfile_json); + ofs << allLogs.Render(); + ofs.close(); + + } lastSave = time(0); didHistoryChangeSinceLastSave = false; @@ -65,6 +97,57 @@ void LogHistory::Save() return; } +JasonPP::JsonArray LogHistory::GetCompleteLogHistoryAsJson() +{ + Save(); + + // Logfile does not exist, just return an empty array + if (!FileSystem::Exists(XGConfig::logging.logfile_json)) + { + std::cout << "no log file" << std::endl; + return JasonPP::JsonArray(); + } + else + { + // Logfile exists + std::string file_contents = FileSystem::ReadFile(XGConfig::logging.logfile_json); + if (JasonPP::IsJsonValid(file_contents)) + { + JasonPP::Json logs; + logs.Parse(file_contents); + + if (logs.GetDataType() == JasonPP::JDType::ARRAY) + { + logs.AsArray.Sort("timestamp", JasonPP::JSON_ARRAY_SORT_MODE::NUM_DESC); + return logs.AsArray; + } + else + { + std::cout << "invalid format log file" << std::endl; + ClearLogHistory(); // The json logfile is fucked + return JasonPP::JsonArray(); + } + } + else + { + std::cout << "invalid syntax log file" << std::endl; + std::cout << file_contents << std::endl; + ClearLogHistory(); // The json logfile is fucked + return JasonPP::JsonArray(); + } + } +} + +bool LogHistory::ClearLogHistory() +{ + FileSystem::Delete(XGConfig::logging.logfile_json); + FileSystem::Delete(XGConfig::logging.logfile_text); + + Save(); + + return true; +} + void LogHistory::AddLogToHistory(LogEntry* newEntry) { history->push_back(newEntry); @@ -80,9 +163,10 @@ bool LogHistory::didHistoryChangeSinceLastSave; JasonPP::JsonBlock LogEntry::GetAsJson() { return JasonPP::JsonBlock({ - Ele("compiledMessage", message), - Ele("message", compiledMessage), + Ele("compiledMessage", compiledMessage), + Ele("message", message), Ele("identifier", identifier), + Ele("additional_information", additional_information), Ele("type", (int)type), Ele("timestamp", (long long int)timestamp), }); diff --git a/Tubio/LogHistory.h b/Tubio/LogHistory.h index cd4b000..9cb277c 100644 --- a/Tubio/LogHistory.h +++ b/Tubio/LogHistory.h @@ -18,6 +18,7 @@ namespace Logging std::string compiledMessage; std::string message; std::string identifier; + std::string additional_information; LOG_TYPE type; std::time_t timestamp; @@ -33,7 +34,13 @@ namespace Logging static void Save(); - static std::vector* GetLogHistory() { return history; } + static std::vector* GetSessionLogHistory() { return history; } + static JasonPP::JsonArray GetCompleteLogHistoryAsJson(); + + /// + /// Will clear the log history + /// + static bool ClearLogHistory(); private: static void AddLogToHistory(LogEntry* newEntry); diff --git a/Tubio/Logger.cpp b/Tubio/Logger.cpp index 357b323..90767b5 100644 --- a/Tubio/Logger.cpp +++ b/Tubio/Logger.cpp @@ -46,12 +46,13 @@ std::string Logger::Flush() strftime(timeBuf, 100, "%d.%m.%Y - %T", &currTm); std::stringstream bufOut; - bufOut << "<" << timeBuf << "> [" << identifier << "]" << TypeToPrefix(type) << ((additionalInfo.length() > 0) ? " " : "") << additionalInfo << ": " << cout.str(); + bufOut << "<" << timeBuf << "> [" << identifier << "]" << TypeToPrefix(type) << ((additional_information.length() > 0) ? " " : "") << additional_information << ": " << cout.str(); LogEntry* newEntry = new LogEntry; newEntry->message = cout.str(); newEntry->compiledMessage = bufOut.str(); newEntry->identifier = identifier; + newEntry->additional_information = additional_information; newEntry->timestamp = currTime; newEntry->type = type; LogHistory::AddLogToHistory(newEntry); diff --git a/Tubio/Logger.h b/Tubio/Logger.h index 7f578ea..b5b947e 100644 --- a/Tubio/Logger.h +++ b/Tubio/Logger.h @@ -21,7 +21,7 @@ namespace Logging void Set(std::string str); //Sets additional information to be appended after the identifier - void SetAdditionalInformation(std::string str) { additionalInfo = str; }; + void SetAdditionalInformation(std::string str) { additional_information = str; }; //Prints the buffered string to the console and clears it std::string Flush(); @@ -44,7 +44,7 @@ namespace Logging bool IsInitializedSanityCheck(); std::string identifier; - std::string additionalInfo = ""; + std::string additional_information = ""; LOG_TYPE type = LOG_TYPE::LOG; bool isInitialized = false; diff --git a/Tubio/RestQueryHandler.cpp b/Tubio/RestQueryHandler.cpp index 41d654c..77ebea3 100644 --- a/Tubio/RestQueryHandler.cpp +++ b/Tubio/RestQueryHandler.cpp @@ -34,6 +34,7 @@ bool RestQueryHandler::ProcessQuery(const std::string clientAdress, const Json& else if (requestName == "show_console") return ShowConsole(requestBody, responseBody, responseCode); else if (requestName == "hide_console") return HideConsole(requestBody, responseBody, responseCode); else if (requestName == "get_os_name") return GetOSName(requestBody, responseBody, responseCode); + else if (requestName == "fetch_logs") return FetchLogs(requestBody, responseBody, responseCode); @@ -208,7 +209,16 @@ bool RestQueryHandler::GetOSName(const JsonBlock& request, JsonBlock& responseBo return true; } +bool RestQueryHandler::FetchLogs(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +{ + log->cout << "Fetching logs..."; + log->Flush(); + responseCode = OK; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); + responseBody.Set("logs") = LogHistory::GetCompleteLogHistoryAsJson(); + return true; +} diff --git a/Tubio/RestQueryHandler.h b/Tubio/RestQueryHandler.h index 86717b0..5202cd1 100644 --- a/Tubio/RestQueryHandler.h +++ b/Tubio/RestQueryHandler.h @@ -26,6 +26,7 @@ namespace Rest static bool HideConsole(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); static bool ShowConsole(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); static bool GetOSName(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); + static bool FetchLogs(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); static bool ValidateField(const std::string name, const JasonPP::JDType type, const JasonPP::Json& checkThat, JasonPP::JsonBlock& putErrorResponseHere);