diff --git a/SpCloudMain/CMakeLists.txt b/SpCloudMain/CMakeLists.txt index 2927c1e..58b9773 100644 --- a/SpCloudMain/CMakeLists.txt +++ b/SpCloudMain/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(SpCloudMain "Service/AuthorizationService.cpp" "Service/FileProcessingService.cpp" "Service/CommandService.cpp" + "Service/Logger.cpp" ) if (CMAKE_VERSION VERSION_GREATER 3.12) diff --git a/SpCloudMain/Controllers/PublishController.cpp b/SpCloudMain/Controllers/PublishController.cpp index 3647795..46afb46 100644 --- a/SpCloudMain/Controllers/PublishController.cpp +++ b/SpCloudMain/Controllers/PublishController.cpp @@ -14,9 +14,8 @@ private: FileProcessingService file_processing; - //std::string publish_app_path = "/mnt/c/Users/Danil/SpCloudApp";//Todo change to linux path - //std::string publish_app_path = "/home/danilt2000/SpCloudMain/SpCloudApp";//Todo change to linux path - std::string publish_app_path = "/home/danilt2000/SpCloud/";//Todo change to linux path + std::string publish_app_path = "/mnt/c/Users/Danil/SpCloudApp"; + //std::string publish_app_path = "/home/danilt2000/SpCloud/"; //std::string publish_app_path = "C:/Temps/";// Todo delete if not needed public: @@ -32,67 +31,69 @@ public: //httplib::Headers test = req.headers;//Todo add processing header for authorization layer }); } - - private: - void process_publish(const httplib::Request& req, httplib::Response& res) + +private: + void process_publish(const httplib::Request& req, httplib::Response& res) + { + if (this->authorization.is_user_authorized()) { - if (this->authorization.is_user_authorized()) - { - const auto& content = req.files.begin()->second.content; - - const auto& filename = this->publish_app_path + req.files.begin()->second.filename; - - if (filename.size() >= 4 && filename.substr(filename.size() - 4) == ".rar") { - if (file_processing.save_file(filename, content)) { - - std::string random_string = generate_random_string(20);//Todo think about change - - file_processing.unzip(filename, this->publish_app_path + random_string); - - this->dotnet_publish(this->publish_app_path + random_string); - - res.set_content("File uploaded successfully: " + filename, "text/plain"); - } - else { - res.status = 500; - res.set_content("Failed to save file, please ensure you are putting rar file" - + filename, "text/plain"); - } + const auto& content = req.files.begin()->second.content; + + const auto& filename = this->publish_app_path + req.files.begin()->second.filename; + + if (filename.size() >= 4 && filename.substr(filename.size() - 4) == ".rar") { + //if (file_processing.save_file_with_retry(filename, content)) { + if (file_processing.save_file(filename, content)) { + + //Todo uncommit later + //std::string random_string = generate_random_string(20);//Todo think about change + + //file_processing.unzip(filename, this->publish_app_path + random_string); + + //this->dotnet_publish(this->publish_app_path + random_string); + + res.set_content("File uploaded successfully: " + filename, "text/plain"); } else { - res.status = 400; - res.set_content("Invalid file type. Only .rar files are allowed.", - "text/plain"); + res.status = 500; + res.set_content("Failed to save file, please ensure you are putting rar file" + + filename, "text/plain"); } } - else - { - //Todo add logging and exiting from function with bead request + else { + res.status = 400; + res.set_content("Invalid file type. Only .rar files are allowed.", + "text/plain"); } } - - void dotnet_publish(const std::string& path) + else { - std::string dll_file_name = file_processing.find_file_by_suffix(path, "dll"); - - std::string command = R"(dotnet )" + path + "/" + dll_file_name; - - std::thread commandThread(&CommandService::execute_command, command); - - commandThread.detach(); + //Todo add logging and exiting from function with bead request } - - static std::string generate_random_string(size_t length, const std::string& char_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") { - std::random_device rd; - std::mt19937 generator(rd()); - std::uniform_int_distribution<> distribution(0, char_set.size() - 1); - - std::string random_string; - for (size_t i = 0; i < length; ++i) { - char random_char = char_set[distribution(generator)]; - random_string += random_char; - } - - return random_string; + } + + void dotnet_publish(const std::string& path) + { + std::string dll_file_name = file_processing.find_file_by_suffix(path, "dll"); + + std::string command = R"(dotnet )" + path + "/" + dll_file_name; + + std::thread commandThread(&CommandService::execute_command, command); + + commandThread.detach(); + } + + static std::string generate_random_string(size_t length, const std::string& char_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") { + std::random_device rd; + std::mt19937 generator(rd()); + std::uniform_int_distribution<> distribution(0, char_set.size() - 1); + + std::string random_string; + for (size_t i = 0; i < length; ++i) { + char random_char = char_set[distribution(generator)]; + random_string += random_char; } + + return random_string; + } }; \ No newline at end of file diff --git a/SpCloudMain/Service/FileProcessingService.cpp b/SpCloudMain/Service/FileProcessingService.cpp index 7bbcfc6..1d3be89 100644 --- a/SpCloudMain/Service/FileProcessingService.cpp +++ b/SpCloudMain/Service/FileProcessingService.cpp @@ -1,27 +1,92 @@ -// ReSharper disable CppClangTidyBugproneSuspiciousInclude +// ReSharper disable CppClangTidyBugproneSuspiciousInclude #include #include +#include #include #include #include #include "CommandService.cpp" - +//#include +//#include +//#include class FileProcessingService { public: - FileProcessingService() + FileProcessingService(/*&Logger logger*/) { } bool save_file(const std::string& filename, const std::string& content) { + + //std::lock_guard lock(file_mutex); // Блокируем мьютекс//Todo TEST STABILITY OF THIS + std::ofstream ofs(filename, std::ios::binary); + if (!ofs) return false; + ofs << content; + return ofs.good(); } + //bool save_file(const std::string& filename, const std::string& content) { + // Mutex::ScopedLock lock(file_mutex); // Блокируем мьютекс + + // try { + // Poco::File file(filename); + // Poco::FileOutputStream ofs(filename, std::ios::binary | std::ios::trunc); + + // if (!ofs.good()) { + // std::cerr << "Error opening file: " << filename << std::endl; + // return false; + // } + + // ofs.write(content.c_str(), content.size()); + + // if (!ofs.good()) { + // std::cerr << "Error writing to file: " << filename << std::endl; + // return false; + // } + + // ofs.close(); // Явно закрываем файл + // } + // catch (const Poco::Exception& ex) { + // std::cerr << "Poco exception: " << ex.displayText() << std::endl; + // return false; + // } + + // return true; + //} + + + //bool save_file_with_timeout(const std::string& filename, const std::string& content, std::chrono::milliseconds timeout) { + // // Запускаем асинхронную задачу для записи файла + // auto future = std::async(std::launch::async, &FileProcessingService::save_file, this, filename, content); + + // // Ожидаем завершения задачи или истечения тайм-аута + // if (future.wait_for(timeout) == std::future_status::ready) { + // return future.get(); // Возвращаем результат записи + // } + // else { + // std::cerr << "Timeout occurred while saving file: " << filename << std::endl; + // return false; // Тайм-аут + // } + //} + + + //bool save_file_with_retry(const std::string& filename, const std::string& content, int max_retries = 5, std::chrono::milliseconds timeout = std::chrono::milliseconds(1000)) { + // for (int i = 0; i < max_retries; ++i) { + // if (save_file_with_timeout(filename, content, timeout)) { + // return true; + // } + // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Пауза перед повторной попыткой + // } + // std::cerr << "Failed to save file after " << max_retries << " attempts: " << filename << std::endl; + // return false; + //} + void create_directory(const std::string& path) { std::filesystem::create_directories(path); } @@ -32,7 +97,6 @@ public: //Windows version //std::string command = R"(powershell -Command "& \"C:\Program Files\WinRAR\WinRAR.exe\" x \")" + file_path + R"(\" \")" + final_files_directory + R"(\")"; - std::cout << "unzip start\n"; //Linux version //std::string command = "unzip " + file_path + " -d " + final_files_directory; @@ -69,4 +133,7 @@ public: // int result = system(command.c_str());//Todo solve unsafe warning //} +/*private: + std::mutex file_mutex; */// Мьютекс для синхронизации доступа к файлу + }; diff --git a/SpCloudMain/Service/Logger.cpp b/SpCloudMain/Service/Logger.cpp new file mode 100644 index 0000000..3469b73 --- /dev/null +++ b/SpCloudMain/Service/Logger.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +enum LogLevel { DEBUG, INFO, WARNING, ERROR, CRITICAL }; + +class Logger { +public: + // Constructor: Opens the log file in append mode + Logger( std::string& filename) + { + logFile.open(filename, std::ios::app); + if (!logFile.is_open()) { + std::cerr << "Error opening log file." << '\n'; + } + } + + // Destructor: Closes the log file + ~Logger() { logFile.close(); } + + // Logs a message with a given log level + void log(LogLevel level, const std::string& message) + { + // Get current timestamp + time_t now = time(0); + tm* timeinfo = localtime(&now); + char timestamp[20]; + strftime(timestamp, sizeof(timestamp), + "%Y-%m-%d %H:%M:%S", timeinfo); + + // Create log entry + + std::ostringstream logEntry; + logEntry << "[" << timestamp << "] " + << levelToString(level) << ": " << message + << std::endl; + + // Output to console + std::cout << logEntry.str(); + + // Output to log file + if (logFile.is_open()) { + logFile << logEntry.str(); + logFile.flush(); // Ensure immediate write to file + } + } + +private: + std::ofstream logFile; // File stream for the log file + + // Converts log level to a string for output + std::string levelToString(LogLevel level) + { + switch (level) { + case DEBUG: + return "DEBUG"; + case INFO: + return "INFO"; + case WARNING: + return "WARNING"; + case ERROR: + return "ERROR"; + case CRITICAL: + return "CRITICAL"; + default: + return "UNKNOWN"; + } + } +}; \ No newline at end of file diff --git a/SpCloudMain/SpCloudMain.cpp b/SpCloudMain/SpCloudMain.cpp index 3602f99..bb66214 100644 --- a/SpCloudMain/SpCloudMain.cpp +++ b/SpCloudMain/SpCloudMain.cpp @@ -7,77 +7,15 @@ #include "httplib.h" #include "Controllers/PublishController.cpp" //#include "Service/AuthorizationService.cpp" +#include "Service/Logger.cpp" //#include "Service/FileProcessingService.cpp" using namespace std; -enum LogLevel { DEBUG, INFO, WARNING, ERROR, CRITICAL }; - -class Logger { -public: - // Constructor: Opens the log file in append mode - Logger(const string& filename) - { - logFile.open(filename, ios::app); - if (!logFile.is_open()) { - cerr << "Error opening log file." << endl; - } - } - - // Destructor: Closes the log file - ~Logger() { logFile.close(); } - - // Logs a message with a given log level - void log(LogLevel level, const string& message) - { - // Get current timestamp - time_t now = time(0); - tm* timeinfo = localtime(&now); - char timestamp[20]; - strftime(timestamp, sizeof(timestamp), - "%Y-%m-%d %H:%M:%S", timeinfo); - - // Create log entry - ostringstream logEntry; - logEntry << "[" << timestamp << "] " - << levelToString(level) << ": " << message - << endl; - - // Output to console - cout << logEntry.str(); - - // Output to log file - if (logFile.is_open()) { - logFile << logEntry.str(); - logFile.flush(); // Ensure immediate write to file - } - } - -private: - ofstream logFile; // File stream for the log file - - // Converts log level to a string for output - string levelToString(LogLevel level) - { - switch (level) { - case DEBUG: - return "DEBUG"; - case INFO: - return "INFO"; - case WARNING: - return "WARNING"; - case ERROR: - return "ERROR"; - case CRITICAL: - return "CRITICAL"; - default: - return "UNKNOWN"; - } - } -}; - int main() { - Logger logger("logfile.txt"); + string logger_name = "logfile.txt"; + + Logger logger(logger_name); std::cout << "SpCloud start\n"; @@ -96,8 +34,8 @@ int main() httplib::Headers test = req.headers; }); - // Предполагается, что эти классы определены где-то еще AuthorizationService authorization_service; + FileProcessingService file_processing; PublishController publish_controller(svr, authorization_service, file_processing);