From cdb38f27a73daaef3927e2b5162fcc5e72ff36a5 Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Mon, 30 Dec 2024 02:27:52 +0000 Subject: [PATCH] simplify etag caching requests --- sphaira/include/download.hpp | 22 ++++++++++++++++++++++ sphaira/source/download.cpp | 17 ++++++++++++++++- sphaira/source/ui/menus/appstore.cpp | 26 ++++---------------------- sphaira/source/ui/menus/ghdl.cpp | 5 +---- sphaira/source/ui/menus/main_menu.cpp | 6 +----- sphaira/source/ui/menus/themezer.cpp | 16 ++-------------- 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/sphaira/include/download.hpp b/sphaira/include/download.hpp index ab5fb4c..e99c0bb 100644 --- a/sphaira/include/download.hpp +++ b/sphaira/include/download.hpp @@ -10,6 +10,16 @@ namespace sphaira::curl { +enum { + Flag_None = 0, + // requests to download send etag in the header. + // the received etag is then saved on success. + // this api is only available on downloading to file. + Flag_CacheEtag = 1 << 0, + Flag_CacheLmt = 1 << 1, + Flag_Cache = Flag_CacheEtag | Flag_CacheLmt, +}; + enum class Priority { Normal, // gets pushed to the back of the queue High, // gets pushed to the front of the queue @@ -46,6 +56,12 @@ struct Header { } }; +struct Flags { + Flags() = default; + Flags(u32 flags) : m_flags{flags} {} + u32 m_flags{Flag_None}; +}; + struct ApiResult { bool success; long code; @@ -99,6 +115,7 @@ struct Api { template auto ToMemory(Ts&&... ts) { static_assert(std::disjunction_v...>, "Url must be specified"); + static_assert(!std::disjunction_v...>, "Path must not valid for memory"); Api::set_option(std::forward(ts)...); return curl::ToMemory(*this); } @@ -115,6 +132,7 @@ struct Api { auto ToMemoryAsync(Ts&&... ts) { static_assert(std::disjunction_v...>, "Url must be specified"); static_assert(std::disjunction_v...>, "OnComplete must be specified"); + static_assert(!std::disjunction_v...>, "Path must not valid for memory"); Api::set_option(std::forward(ts)...); return curl::ToMemoryAsync(*this); } @@ -131,6 +149,7 @@ struct Api { Url m_url; Fields m_fields{}; Header m_header{}; + Flags m_flags{}; Path m_path{}; OnComplete m_on_complete = nullptr; OnProgress m_on_progress = nullptr; @@ -146,6 +165,9 @@ private: void SetOption(Header&& v) { m_header = v; } + void SetOption(Flags&& v) { + m_flags = v; + } void SetOption(Path&& v) { m_path = v; } diff --git a/sphaira/source/download.cpp b/sphaira/source/download.cpp index c04092e..b8550d6 100644 --- a/sphaira/source/download.cpp +++ b/sphaira/source/download.cpp @@ -389,6 +389,7 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult { const bool has_post = !e.m_fields.m_str.empty() && e.m_fields.m_str != ""; DataStruct chunk; + Header header_in = e.m_header; Header header_out; fs::FsNativeSd fs; @@ -405,6 +406,13 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult { log_write("failed to open file: %s\n", tmp_buf); return {}; } + + if (e.m_flags.m_flags & Flag_CacheEtag) { + header_in.m_map.emplace("if-none-match", cache::etag_get(e.m_path)); + } + if (e.m_flags.m_flags & Flag_CacheLmt) { + header_in.m_map.emplace("if-modified-since", cache::lmt_get(e.m_path)); + } } // reserve the first chunk @@ -430,7 +438,7 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult { struct curl_slist* list = NULL; ON_SCOPE_EXIT(if (list) { curl_slist_free_all(list); } ); - for (auto& [key, value] : e.m_header.m_map) { + for (const auto& [key, value] : header_in.m_map) { if (value.empty()) { continue; } @@ -481,6 +489,13 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult { fsFileClose(&chunk.f); if (res == CURLE_OK && http_code != 304) { + if (e.m_flags.m_flags & Flag_CacheEtag) { + cache::etag_set(e.m_path, header_out); + } + if (e.m_flags.m_flags & Flag_CacheLmt) { + cache::lmt_set(e.m_path, header_out); + } + fs.DeleteFile(e.m_path, true); fs.CreateDirectoryRecursivelyWithPath(e.m_path, true); if (R_FAILED(fs.RenameFile(tmp_buf, e.m_path, true))) { diff --git a/sphaira/source/ui/menus/appstore.cpp b/sphaira/source/ui/menus/appstore.cpp index 23da9ea..77311de 100644 --- a/sphaira/source/ui/menus/appstore.cpp +++ b/sphaira/source/ui/menus/appstore.cpp @@ -716,15 +716,9 @@ EntryMenu::EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu) curl::Api().ToFileAsync( curl::Url{url}, curl::Path{path}, - curl::Header{ - { "if-none-match", curl::cache::etag_get(path) }, - { "if-modified-since", curl::cache::lmt_get(path) }, - }, + curl::Flags{curl::Flag_Cache}, curl::OnComplete{[this, path](auto& result){ if (result.success) { - curl::cache::etag_set(result.path, result.header); - curl::cache::lmt_set(result.path, result.header); - if (result.code == 304) { m_banner.cached = false; } else { @@ -1030,15 +1024,9 @@ Menu::Menu(const std::vector& nro_entries) : MenuBase{"AppStore"_i18n} curl::Api().ToFileAsync( curl::Url{URL_JSON}, curl::Path{REPO_PATH}, - curl::Header{ - { "if-none-match", curl::cache::etag_get(REPO_PATH) }, - { "if-modified-since", curl::cache::lmt_get(REPO_PATH) }, - }, + curl::Flags{curl::Flag_Cache}, curl::OnComplete{[this](auto& result){ if (result.success) { - curl::cache::etag_set(result.path, result.header); - curl::cache::lmt_set(result.path, result.header); - if (result.code == 304) { log_write("appstore json not updated\n"); } else { @@ -1126,16 +1114,10 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { curl::Api().ToFileAsync( curl::Url{url}, curl::Path{path}, - curl::Header{ - { "if-none-match", curl::cache::etag_get(path) }, - { "if-modified-since", curl::cache::lmt_get(path) }, - }, + curl::Flags{curl::Flag_Cache}, curl::OnComplete{[this, &image](auto& result) { if (result.success) { - curl::cache::etag_set(result.path, result.header); - curl::cache::lmt_set(result.path, result.header); - - image.state = ImageDownloadState::Done; + image.state = ImageDownloadState::Done; // data hasn't changed if (result.code == 304) { log_write("downloaded appstore image, was cached\n"); diff --git a/sphaira/source/ui/menus/ghdl.cpp b/sphaira/source/ui/menus/ghdl.cpp index 4038601..825f322 100644 --- a/sphaira/source/ui/menus/ghdl.cpp +++ b/sphaira/source/ui/menus/ghdl.cpp @@ -210,10 +210,9 @@ auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& ou curl::Url{url}, curl::Path{path}, curl::OnProgress{pbox->OnDownloadProgressCallback()}, + curl::Flags{curl::Flag_Cache}, curl::Header{ { "Accept", "application/vnd.github+json" }, - { "if-none-match", curl::cache::etag_get(path) }, - { "if-modified-since", curl::cache::lmt_get(path) }, } ); @@ -222,8 +221,6 @@ auto DownloadAssetJson(ProgressBox* pbox, const std::string& url, GhApiEntry& ou return false; } - curl::cache::etag_set(result.path, result.header); - curl::cache::lmt_set(result.path, result.header); from_json(result.path, out); } diff --git a/sphaira/source/ui/menus/main_menu.cpp b/sphaira/source/ui/menus/main_menu.cpp index 4fc4dd5..d8769f1 100644 --- a/sphaira/source/ui/menus/main_menu.cpp +++ b/sphaira/source/ui/menus/main_menu.cpp @@ -145,10 +145,9 @@ MainMenu::MainMenu() { curl::Api().ToFileAsync( curl::Url{GITHUB_URL}, curl::Path{CACHE_PATH}, + curl::Flags{curl::Flag_Cache}, curl::Header{ { "Accept", "application/vnd.github+json" }, - { "if-none-match", curl::cache::etag_get(CACHE_PATH) }, - { "if-modified-since", curl::cache::lmt_get(CACHE_PATH) }, }, curl::OnComplete{[this](auto& result){ log_write("inside github download\n"); @@ -165,9 +164,6 @@ MainMenu::MainMenu() { log_write("etag changed\n"); } - curl::cache::etag_set(result.path, result.header); - curl::cache::lmt_set(result.path, result.header); - auto json = yyjson_read_file(CACHE_PATH, YYJSON_READ_NOFLAG, nullptr, nullptr); R_UNLESS(json, false); ON_SCOPE_EXIT(yyjson_doc_free(json)); diff --git a/sphaira/source/ui/menus/themezer.cpp b/sphaira/source/ui/menus/themezer.cpp index 1c9201a..1003d3d 100644 --- a/sphaira/source/ui/menus/themezer.cpp +++ b/sphaira/source/ui/menus/themezer.cpp @@ -656,15 +656,9 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { curl::Api().ToFileAsync( curl::Url{url}, curl::Path{path}, - curl::Header{ - { "if-none-match", curl::cache::etag_get(path) }, - { "if-modified-since", curl::cache::lmt_get(path) }, - }, + curl::Flags{curl::Flag_Cache}, curl::OnComplete{[this, &image](auto& result) { if (result.success) { - curl::cache::etag_set(result.path, result.header); - curl::cache::lmt_set(result.path, result.header); - image.state = ImageDownloadState::Done; // data hasn't changed if (result.code == 304) { @@ -751,10 +745,7 @@ void Menu::PackListDownload() { curl::Api().ToFileAsync( curl::Url{packList_url}, curl::Path{packlist_path}, - curl::Header{ - { "if-none-match", curl::cache::etag_get(packlist_path) }, - { "if-modified-since", curl::cache::lmt_get(packlist_path) }, - }, + curl::Flags{curl::Flag_Cache}, curl::OnComplete{[this, page_index](auto& result){ log_write("got themezer data\n"); if (!result.success) { @@ -764,9 +755,6 @@ void Menu::PackListDownload() { return; } - curl::cache::etag_set(result.path, result.header); - curl::cache::lmt_set(result.path, result.header); - PackList a; from_json(result.path, a);