fix etag cache not being returned upon the 2nd request, add jump page support for all menus.

- all menus feature page jumping, using L2/R2 (or DPAD_LEFT/DPAD_RIGHT in list menus)
- successive calls to fetch the etag would fail, this was seen in themezer and github menus.
- add limit the number of icons loaded per frame in homebrew menu.
- display default icon the image is not ready to be loaded / invalid.

fixes #53
This commit is contained in:
ITotalJustice
2024-12-31 03:57:08 +00:00
parent 588eb01379
commit e452615c77
13 changed files with 227 additions and 228 deletions

View File

@@ -93,48 +93,14 @@ struct Cache {
}
void get(const fs::FsPath& path, curl::Header& header) {
mutexLock(&m_mutex);
ON_SCOPE_EXIT(mutexUnlock(&m_mutex));
if (!fs::FsNativeSd().FileExists(path)) {
return;
const auto [etag, last_modified] = get_internal(path);
if (!etag.empty()) {
header.m_map.emplace("if-none-match", etag);
}
const auto kkey = generate_key_from_path(path);
const auto it = m_cache.find(kkey);
if (it != m_cache.end()) {
return;
if (!last_modified.empty()) {
header.m_map.emplace("if-modified-since", last_modified);
}
auto hash_key = yyjson_mut_obj_getn(m_root, kkey.c_str(), kkey.length());
if (!hash_key) {
return;
}
auto etag_key = yyjson_mut_obj_get(hash_key, ETAG_STR);
auto last_modified_key = yyjson_mut_obj_get(hash_key, LAST_MODIFIED_STR);
const auto etag_value = yyjson_mut_get_str(etag_key);
const auto etag_value_len = yyjson_mut_get_len(etag_key);
const auto last_modified_value = yyjson_mut_get_str(last_modified_key);
const auto last_modified_value_len = yyjson_mut_get_len(last_modified_key);
if ((!etag_value || !etag_value_len) && (!last_modified_value || !last_modified_value_len)) {
return;
}
std::string etag;
std::string last_modified;
if (etag_value && etag_value_len) {
etag.assign(etag_value, etag_value_len);
}
if (last_modified_value && last_modified_value_len) {
last_modified.assign(last_modified_value, last_modified_value_len);
}
m_cache.insert_or_assign(it, kkey, Value{etag, last_modified});
header.m_map.emplace("if-none-match", etag);
header.m_map.emplace("if-modified-since", last_modified);
}
void set(const fs::FsPath& path, const curl::Header& value) {
@@ -157,6 +123,48 @@ struct Cache {
}
private:
auto get_internal(const fs::FsPath& path) -> Value {
if (!fs::FsNativeSd().FileExists(path)) {
return {};
}
const auto kkey = generate_key_from_path(path);
const auto it = m_cache.find(kkey);
if (it != m_cache.end()) {
return it->second;
}
auto hash_key = yyjson_mut_obj_getn(m_root, kkey.c_str(), kkey.length());
if (!hash_key) {
return {};
}
auto etag_key = yyjson_mut_obj_get(hash_key, ETAG_STR);
auto last_modified_key = yyjson_mut_obj_get(hash_key, LAST_MODIFIED_STR);
const auto etag_value = yyjson_mut_get_str(etag_key);
const auto etag_value_len = yyjson_mut_get_len(etag_key);
const auto last_modified_value = yyjson_mut_get_str(last_modified_key);
const auto last_modified_value_len = yyjson_mut_get_len(last_modified_key);
if ((!etag_value || !etag_value_len) && (!last_modified_value || !last_modified_value_len)) {
return {};
}
std::string etag;
std::string last_modified;
if (etag_value && etag_value_len) {
etag.assign(etag_value, etag_value_len);
}
if (last_modified_value && last_modified_value_len) {
last_modified.assign(last_modified_value, last_modified_value_len);
}
const Value ret{etag, last_modified};
m_cache.insert_or_assign(it, kkey, ret);
return ret;
}
void set_internal(const fs::FsPath& path, const Value& value) {
const auto kkey = generate_key_from_path(path);
@@ -536,15 +544,20 @@ 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_Cache) {
g_cache.set(e.m_path, header_out);
}
if (res == CURLE_OK) {
if (http_code == 304) {
log_write("cached download: %s\n", e.m_url.m_str.c_str());
} else {
log_write("un-cached download: %s code: %u\n", e.m_url.m_str.c_str(), http_code);
if (e.m_flags.m_flags & Flag_Cache) {
g_cache.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))) {
success = false;
fs.DeleteFile(e.m_path, true);
fs.CreateDirectoryRecursivelyWithPath(e.m_path, true);
if (R_FAILED(fs.RenameFile(tmp_buf, e.m_path, true))) {
success = false;
}
}
}
chunk.data.clear();