diff --git a/Tubio/LogHistory.cpp b/Tubio/LogHistory.cpp index 5a1b1f4..0965e91 100644 --- a/Tubio/LogHistory.cpp +++ b/Tubio/LogHistory.cpp @@ -5,8 +5,9 @@ using namespace Logging; void LogHistory::PreInit() { history = new std::vector(); - lastSave = time(0); + lastSave = time(0); // now didHistoryChangeSinceLastSave = false; + LoadSaveFileCache(); return; } @@ -58,35 +59,12 @@ void LogHistory::Save() // 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); + LoadSaveFileCache(); + JasonPP::Json savefile; + savefile.SetArrayData(saveFileCache); + savefile.AsArray.Merge(newJsonLogs.AsArray); ofs.open(XGConfig::logging.logfile_json); - ofs << allLogs.Render(); + ofs << savefile.Render(); ofs.close(); } @@ -97,45 +75,74 @@ void LogHistory::Save() return; } -JasonPP::JsonArray LogHistory::GetCompleteLogHistoryAsJson() +void LogHistory::LoadSaveFileCache() { - Save(); - - // Logfile does not exist, just return an empty array - if (!FileSystem::Exists(XGConfig::logging.logfile_json)) + JasonPP::Json allLogs; + 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)) + std::string fileContent = FileSystem::ReadFile(XGConfig::logging.logfile_json); + if (JasonPP::IsJsonValid(fileContent)) { - JasonPP::Json logs; - logs.Parse(file_contents); - - if (logs.GetDataType() == JasonPP::JDType::ARRAY) + allLogs.Parse(fileContent); + if (allLogs.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(); + // Json file is fucked (wrong format). Reset to empty array + allLogs.SetArrayData(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(); + // 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()); + } + saveFileCache.Clear(); + saveFileCache.CloneFrom(allLogs.AsArray); + return; +} + +JasonPP::JsonArray LogHistory::GetCompleteLogHistoryAsJson(time_t max_age, std::size_t max_num) +{ + JasonPP::JsonArray arr + ; + + for (std::size_t i = 0; i < history->size(); i++) + { + arr += history->at(i)->GetAsJson(); + } + arr.Merge(saveFileCache); + arr.Sort("timestamp", JasonPP::JSON_ARRAY_SORT_MODE::NUM_DESC); + + if ((max_age == -1) && (max_num == (std::size_t)-1)) return arr; + + JasonPP::JsonArray cutArr; + for (std::size_t i = 0; ((i < arr.Size()) && (i < max_num)); i++) + { + // If max_age is > 0, we have to check against the max age + if (max_age > 0) + { + if (arr[i].AsJson.DoesExist("timestamp")) + { + if (arr[i]["timestamp"].GetDataType() == JasonPP::JDType::INT) + { + if ((time(0) - arr[i]["timestamp"].AsInt) < max_age) + { + cutArr += arr[i]; + } + } + } + } + else // If not, just insert it + { + cutArr += arr[i]; + } + } + return cutArr; } bool LogHistory::ClearLogHistory() @@ -158,6 +165,7 @@ void LogHistory::AddLogToHistory(LogEntry* newEntry) std::vector* LogHistory::history; time_t LogHistory::lastSave; +JasonPP::JsonArray LogHistory::saveFileCache; bool LogHistory::didHistoryChangeSinceLastSave; JasonPP::JsonBlock LogEntry::GetAsJson() diff --git a/Tubio/LogHistory.h b/Tubio/LogHistory.h index 6730dec..670ff0a 100644 --- a/Tubio/LogHistory.h +++ b/Tubio/LogHistory.h @@ -32,10 +32,18 @@ namespace Logging static void PostExit(); static void Update(); + static void LoadSaveFileCache(); static void Save(); static std::vector* GetSessionLogHistory() { return history; } - static JasonPP::JsonArray GetCompleteLogHistoryAsJson(); + + /// + /// Will return all logs ever in json format. You can specify a max_age and a max_num + /// + /// Max age to return + /// Maximum amount to return + /// + static JasonPP::JsonArray GetCompleteLogHistoryAsJson(time_t max_age, std::size_t max_num); /// /// Will clear the log history @@ -46,6 +54,7 @@ namespace Logging static void AddLogToHistory(LogEntry* newEntry); static std::vector* history; + static JasonPP::JsonArray saveFileCache; static time_t lastSave; static bool didHistoryChangeSinceLastSave; diff --git a/Tubio/RestQueryHandler.cpp b/Tubio/RestQueryHandler.cpp index ab3b487..b8927d5 100644 --- a/Tubio/RestQueryHandler.cpp +++ b/Tubio/RestQueryHandler.cpp @@ -35,7 +35,8 @@ 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); + else if (requestName == "fetch_session_logs") return FetchSessionLogs(requestBody, responseBody, responseCode); + else if (requestName == "fetch_alltime_logs") return FetchAlltimeLogs(requestBody, responseBody, responseCode); @@ -240,18 +241,44 @@ bool RestQueryHandler::GetOSName(const JsonBlock& request, JsonBlock& responseBo return true; } -bool RestQueryHandler::FetchLogs(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +bool RestQueryHandler::FetchSessionLogs(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) { - log->cout << "Fetching logs..."; + log->cout << "Fetching session logs..."; log->Flush(); responseCode = OK; responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); - responseBody.Set("logs") = LogHistory::GetCompleteLogHistoryAsJson(); + JsonArray logs = LogHistory::GetCompleteLogHistoryAsJson(time(0) - XGControl::boot_time + 1, -1); + responseBody.Set("logs_size") = (long long int)logs.Size(); + responseBody.Set("logs") = logs; return true; } +bool RestQueryHandler::FetchAlltimeLogs(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +{ + log->cout << "Fetching logs..."; + log->Flush(); + time_t max_age = -1; + std::size_t max_num = (std::size_t) - 1; + + JsonBlock dummy; + if (ValidateField("max_age", JDType::INT, request, dummy)) + { + max_age = request["max_age"].AsInt; + } + if (ValidateField("max_num", JDType::INT, request, dummy)) + { + max_num = request["max_num"].AsInt; + } + + responseCode = OK; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); + JsonArray logs = LogHistory::GetCompleteLogHistoryAsJson(max_age, max_num); + responseBody.Set("logs_size") = (long long int)logs.Size(); + responseBody.Set("logs") = logs; + return true; +} diff --git a/Tubio/RestQueryHandler.h b/Tubio/RestQueryHandler.h index 9153ad7..25a5393 100644 --- a/Tubio/RestQueryHandler.h +++ b/Tubio/RestQueryHandler.h @@ -27,7 +27,8 @@ 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 FetchAlltimeLogs(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); + static bool FetchSessionLogs(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);