From bebb5e839a0473a61fa7e057e2bfc21732b2801d Mon Sep 17 00:00:00 2001 From: Alex Macocian Date: Thu, 9 May 2024 01:03:25 +0200 Subject: [PATCH] Improve caching Rely on modified time Strip extra code --- GWToolboxdll/CMakeLists.txt | 1 + GWToolboxdll/Modules/Resources.cpp | 111 +++++++---------------------- cmake/openssl.cmake | 9 --- 3 files changed, 28 insertions(+), 93 deletions(-) delete mode 100644 cmake/openssl.cmake diff --git a/GWToolboxdll/CMakeLists.txt b/GWToolboxdll/CMakeLists.txt index 2913fa135..4c30037ca 100644 --- a/GWToolboxdll/CMakeLists.txt +++ b/GWToolboxdll/CMakeLists.txt @@ -65,6 +65,7 @@ target_link_libraries(GWToolboxdll PRIVATE IconFontCppHeaders nativefiledialog wintoast + wolfssl # libs: Dbghelp.lib # for MiniDump diff --git a/GWToolboxdll/Modules/Resources.cpp b/GWToolboxdll/Modules/Resources.cpp index c2d193cc6..e4b636baf 100644 --- a/GWToolboxdll/Modules/Resources.cpp +++ b/GWToolboxdll/Modules/Resources.cpp @@ -543,95 +543,44 @@ void Resources::Download(const std::string& url, AsyncLoadMbCallback callback, v void Resources::Download(const std::string& url, AsyncLoadMbCallback callback, void* context, std::chrono::seconds cache_duration) { - const auto get_cache_expiration = [](const std::filesystem::path& file_name) -> std::optional { - /* - * Load the expiration time from the cache. The expiration time - * is the last 8 bytes at the end of the file. They represent - * the amount of seconds from epoch until when the cache should expire. - */ - std::ifstream cache_file(file_name, std::ios::binary | std::ios::ate); - if (!cache_file.is_open()) { - return std::optional(); - } + const auto hash_name = [](const std::filesystem::path& file_name) -> std::filesystem::path { + const auto str = file_name.string(); + const auto bytes_to_hash = std::vector(str.begin(), str.end()); + auto hash = std::vector(WC_MD5_DIGEST_SIZE); + wc_Md5Hash(bytes_to_hash.data(), bytes_to_hash.size(), hash.data()); + const auto hash_str = std::string(hash.begin(), hash.end()); + const auto hash_file = std::filesystem::path(hash_str); + return hash_file; + }; - try { - std::streampos file_size = cache_file.tellg(); - if (file_size < 8) { - cache_file.close(); - return std::optional(); - } - cache_file.seekg(-8, std::ios::end); - std::vector duration_bytes; - duration_bytes.resize(8); - - cache_file.read(duration_bytes.data(), 8); - long long seconds; - std::memcpy(&seconds, duration_bytes.data(), sizeof(seconds)); - cache_file.close(); - return std::chrono::seconds(seconds); - } - catch (...) { - cache_file.close(); - return std::optional(); + const auto get_cache_modified_time = [&hash_name](const std::filesystem::path& file_name) -> std::optional { + if (!std::filesystem::exists(file_name)) { + return std::optional(); } + + const auto file_time = std::filesystem::last_write_time(file_name); + return file_time; }; const auto load_from_cache = [](const std::filesystem::path& file_name) -> std::optional { - /* - * Load the file from cache. The last 8 bytes - * are the expiration time, so we don't need to load those. - */ - std::ifstream cache_file(file_name, std::ios::binary | std::ios::ate); + std::ifstream cache_file(file_name); if (!cache_file.is_open()) { return std::optional(); } - try { - std::streampos file_size = cache_file.tellg(); - if (file_size < 8) { - cache_file.close(); - return std::optional(); - } - - cache_file.seekg(0, std::ios::beg); - std::string file_buffer; - file_buffer.resize(static_cast(file_size - std::streamoff(8))); - cache_file.read(file_buffer.data(), file_buffer.size()); - cache_file.close(); - return file_buffer; - } catch (...) { - cache_file.close(); - return std::optional(); - } + std::string contents((std::istreambuf_iterator(cache_file)), std::istreambuf_iterator()); + return contents; }; - const auto save_to_cache = [](const std::filesystem::path& file_name, const std::string& content, const std::chrono::seconds cache_duration) -> bool { - /* - * Save the file contents to a cached file. At the end of the file, - * append 8 bytes representing the amount of seconds since epoch - * until the cache should expire - */ + const auto save_to_cache = [](const std::filesystem::path& file_name, const std::string& content) -> bool { std::filesystem::create_directories(file_name.parent_path()); std::ofstream cache_file(file_name); if (!cache_file.is_open()) { return false; } - try { - cache_file << content; - std::vector duration_buff; - const long long seconds = cache_duration.count(); - duration_buff.resize(8); - std::memcpy(duration_buff.data(), &seconds, duration_buff.size()); - for (const auto c : duration_buff) { - cache_file << c; - } - cache_file.close(); - return true; - } catch (...) { - cache_file.close(); - return false; - } + cache_file << content; + return true; }; const auto remove_protocol = [](const std::string& url) -> std::string { @@ -648,18 +597,13 @@ void Resources::Download(const std::string& url, AsyncLoadMbCallback callback, v return url; // Return the original if no match is found }; - EnqueueWorkerTask([url, callback, context, cache_duration, &get_cache_expiration, &load_from_cache, &save_to_cache, &remove_protocol] { + EnqueueWorkerTask([url, callback, context, cache_duration, &get_cache_modified_time, &load_from_cache, &save_to_cache, &remove_protocol, &hash_name] { const auto computer_path = Resources::GetComputerFolderPath(); - auto cache_path_str = (computer_path / "cache" / remove_protocol(url)).string(); - for (char& c : cache_path_str) { - if (c == '/') { - c = '\\'; - } - } - const auto cache_path = std::filesystem::path(cache_path_str); - const auto expiration = get_cache_expiration(cache_path); + const auto cache_path = (computer_path / "cache" / remove_protocol(url)); + const auto hashed_path = hash_name(cache_path); + const auto expiration = get_cache_modified_time(cache_path); if (expiration.has_value() && - expiration.value() > std::chrono::system_clock::now().time_since_epoch()) { + expiration.value() - std::chrono::file_clock::now() < std::chrono::days(30)) { const auto response = load_from_cache(cache_path); if (response.has_value()) { EnqueueMainTask([callback, context, response] { @@ -670,8 +614,7 @@ void Resources::Download(const std::string& url, AsyncLoadMbCallback callback, v } std::string response; bool ok = Download(url, response); - const auto expiration_time = std::chrono::duration_cast((std::chrono::system_clock::now() + cache_duration).time_since_epoch()); - save_to_cache(cache_path, response, expiration_time); + save_to_cache(cache_path, response); EnqueueMainTask([callback, ok, response, context] { callback(ok, response, context); }); diff --git a/cmake/openssl.cmake b/cmake/openssl.cmake deleted file mode 100644 index 02ef590d6..000000000 --- a/cmake/openssl.cmake +++ /dev/null @@ -1,9 +0,0 @@ -include_guard() - -set(OPENSSL_FOLDER "${PROJECT_SOURCE_DIR}/Dependencies/openssl") - -add_library(openssl INTERFACE) -target_include_directories(openssl INTERFACE "${OPENSSL_FOLDER}/include") -target_link_libraries(openssl INTERFACE - "${OPENSSL_FOLDER}/lib/libssl.lib" - "${OPENSSL_FOLDER}/lib/libcrypto.lib")