simplify etag caching requests

This commit is contained in:
ITotalJustice
2024-12-30 02:27:52 +00:00
parent 7804bbbcbc
commit cdb38f27a7
6 changed files with 46 additions and 46 deletions

View File

@@ -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 <typename... Ts>
auto ToMemory(Ts&&... ts) {
static_assert(std::disjunction_v<std::is_same<Url, Ts>...>, "Url must be specified");
static_assert(!std::disjunction_v<std::is_same<Path, Ts>...>, "Path must not valid for memory");
Api::set_option(std::forward<Ts>(ts)...);
return curl::ToMemory(*this);
}
@@ -115,6 +132,7 @@ struct Api {
auto ToMemoryAsync(Ts&&... ts) {
static_assert(std::disjunction_v<std::is_same<Url, Ts>...>, "Url must be specified");
static_assert(std::disjunction_v<std::is_same<OnComplete, Ts>...>, "OnComplete must be specified");
static_assert(!std::disjunction_v<std::is_same<Path, Ts>...>, "Path must not valid for memory");
Api::set_option(std::forward<Ts>(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;
}

View File

@@ -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))) {

View File

@@ -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<NroEntry>& 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");

View File

@@ -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);
}

View File

@@ -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));

View File

@@ -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);