simplify etag caching requests
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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))) {
|
||||
|
||||
@@ -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,15 +1114,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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user