use stop token to manage object lifetime across async callbacks, such as download async

This commit is contained in:
ITotalJustice
2025-01-14 15:35:09 +00:00
parent 4e5e1a801b
commit 64a40ae672
7 changed files with 96 additions and 37 deletions

View File

@@ -421,7 +421,9 @@ void App::Loop() {
}
} else if constexpr(std::is_same_v<T, curl::DownloadEventData>) {
log_write("[DownloadEventData] got event\n");
arg.callback(arg.result);
if (arg.callback && !arg.stoken.stop_requested()) {
arg.callback(arg.result);
}
} else {
static_assert(false, "non-exhaustive visitor!");
}

View File

@@ -308,7 +308,7 @@ struct ThreadQueue {
ThreadQueueEntry entry{};
entry.api = api;
switch (api.m_prio) {
switch (api.GetPriority()) {
case Priority::Normal:
m_entries.emplace_back(entry);
break;
@@ -350,13 +350,13 @@ auto ProgressCallbackFunc1(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
}
auto ProgressCallbackFunc2(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) -> size_t {
if (!g_running) {
auto api = static_cast<Api*>(clientp);
if (!g_running || api->GetToken().stop_requested()) {
return 1;
}
// log_write("pcall called %u %u %u %u\n", dltotal, dlnow, ultotal, ulnow);
auto callback = *static_cast<OnProgress*>(clientp);
if (!callback(dltotal, dlnow, ultotal, ulnow)) {
if (!api->GetOnProgress()(dltotal, dlnow, ultotal, ulnow)) {
return 1;
}
@@ -444,11 +444,11 @@ auto header_callback(char* b, size_t size, size_t nitems, void* userdata) -> siz
auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult {
fs::FsPath tmp_buf;
const bool has_file = !e.m_path.empty() && e.m_path != "";
const bool has_post = !e.m_fields.m_str.empty() && e.m_fields.m_str != "";
const bool has_file = !e.GetPath().empty() && e.GetPath() != "";
const bool has_post = !e.GetFields().empty() && e.GetFields() != "";
DataStruct chunk;
Header header_in = e.m_header;
Header header_in = e.GetHeader();
Header header_out;
fs::FsNativeSd fs;
@@ -466,8 +466,8 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult {
return {};
}
if (e.m_flags.m_flags & Flag_Cache) {
g_cache.get(e.m_path, header_in);
if (e.GetFlags() & Flag_Cache) {
g_cache.get(e.GetPath(), header_in);
}
}
@@ -475,7 +475,7 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult {
chunk.data.reserve(CHUNK_SIZE);
curl_easy_reset(curl);
CURL_EASY_SETOPT_LOG(curl, CURLOPT_URL, e.m_url.m_str.c_str());
CURL_EASY_SETOPT_LOG(curl, CURLOPT_URL, e.GetUrl().c_str());
CURL_EASY_SETOPT_LOG(curl, CURLOPT_USERAGENT, "TotalJustice");
CURL_EASY_SETOPT_LOG(curl, CURLOPT_FOLLOWLOCATION, 1L);
CURL_EASY_SETOPT_LOG(curl, CURLOPT_SSL_VERIFYPEER, 0L);
@@ -487,8 +487,8 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult {
CURL_EASY_SETOPT_LOG(curl, CURLOPT_HEADERDATA, &header_out);
if (has_post) {
CURL_EASY_SETOPT_LOG(curl, CURLOPT_POSTFIELDS, e.m_fields.m_str.c_str());
log_write("setting post field: %s\n", e.m_fields.m_str.c_str());
CURL_EASY_SETOPT_LOG(curl, CURLOPT_POSTFIELDS, e.GetFields().c_str());
log_write("setting post field: %s\n", e.GetFields().c_str());
}
struct curl_slist* list = NULL;
@@ -517,8 +517,8 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult {
}
// progress calls.
if (e.m_on_progress) {
CURL_EASY_SETOPT_LOG(curl, CURLOPT_XFERINFODATA, &e.m_on_progress);
if (e.GetOnProgress()) {
CURL_EASY_SETOPT_LOG(curl, CURLOPT_XFERINFODATA, &e);
CURL_EASY_SETOPT_LOG(curl, CURLOPT_XFERINFOFUNCTION, ProgressCallbackFunc2);
} else {
CURL_EASY_SETOPT_LOG(curl, CURLOPT_XFERINFOFUNCTION, ProgressCallbackFunc1);
@@ -546,16 +546,16 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult {
if (res == CURLE_OK) {
if (http_code == 304) {
log_write("cached download: %s\n", e.m_url.m_str.c_str());
log_write("cached download: %s\n", e.GetUrl().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);
log_write("un-cached download: %s code: %u\n", e.GetUrl().c_str(), http_code);
if (e.GetFlags() & Flag_Cache) {
g_cache.set(e.GetPath(), header_out);
}
fs.DeleteFile(e.m_path);
fs.CreateDirectoryRecursivelyWithPath(e.m_path);
if (R_FAILED(fs.RenameFile(tmp_buf, e.m_path))) {
fs.DeleteFile(e.GetPath());
fs.CreateDirectoryRecursivelyWithPath(e.GetPath());
if (R_FAILED(fs.RenameFile(tmp_buf, e.GetPath()))) {
success = false;
}
}
@@ -568,8 +568,8 @@ auto DownloadInternal(CURL* curl, const Api& e) -> ApiResult {
}
}
log_write("Downloaded %s %s\n", e.m_url.m_str.c_str(), curl_easy_strerror(res));
return {success, http_code, header_out, chunk.data, e.m_path};
log_write("Downloaded %s %s\n", e.GetUrl().c_str(), curl_easy_strerror(res));
return {success, http_code, header_out, chunk.data, e.GetPath()};
}
auto DownloadInternal(const Api& e) -> ApiResult {
@@ -604,8 +604,8 @@ void ThreadEntry::ThreadFunc(void* p) {
#if 1
const auto result = DownloadInternal(data->m_curl, data->m_api);
if (g_running) {
const DownloadEventData event_data{data->m_api.m_on_complete, result};
if (g_running && data->m_api.GetOnComplete() && !data->m_api.GetToken().stop_requested()) {
const DownloadEventData event_data{data->m_api.GetOnComplete(), result, data->m_api.GetToken()};
evman::push(std::move(event_data), false);
} else {
break;
@@ -736,14 +736,14 @@ void Exit() {
}
auto ToMemory(const Api& e) -> ApiResult {
if (!e.m_path.empty()) {
if (!e.GetPath().empty()) {
return {};
}
return DownloadInternal(e);
}
auto ToFile(const Api& e) -> ApiResult {
if (e.m_path.empty()) {
if (e.GetPath().empty()) {
return {};
}
return DownloadInternal(e);

View File

@@ -663,6 +663,7 @@ EntryMenu::EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu)
curl::Url{URL_POST_FEEDBACK},
curl::Path{file},
curl::Fields{post},
curl::StopToken{this->GetToken()},
curl::OnComplete{[](auto& result){
if (result.success) {
log_write("got feedback!\n");
@@ -697,6 +698,7 @@ EntryMenu::EntryMenu(Entry& entry, const LazyImage& default_icon, Menu& menu)
curl::Url{url},
curl::Path{path},
curl::Flags{curl::Flag_Cache},
curl::StopToken{this->GetToken()},
curl::OnComplete{[this, path](auto& result){
if (result.success) {
if (result.code == 304) {
@@ -990,6 +992,7 @@ Menu::Menu(const std::vector<NroEntry>& nro_entries) : MenuBase{"AppStore"_i18n}
curl::Url{URL_JSON},
curl::Path{REPO_PATH},
curl::Flags{curl::Flag_Cache},
curl::StopToken{this->GetToken()},
curl::OnComplete{[this](auto& result){
if (result.success) {
m_repo_download_state = ImageDownloadState::Done;
@@ -1071,6 +1074,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
curl::Url{url},
curl::Path{path},
curl::Flags{curl::Flag_Cache},
curl::StopToken{this->GetToken()},
curl::OnComplete{[this, &image](auto& result) {
if (result.success) {
image.state = ImageDownloadState::Done;

View File

@@ -150,6 +150,7 @@ MainMenu::MainMenu() {
curl::Url{GITHUB_URL},
curl::Path{CACHE_PATH},
curl::Flags{curl::Flag_Cache},
curl::StopToken{this->GetToken()},
curl::Header{
{ "Accept", "application/vnd.github+json" },
},

View File

@@ -647,6 +647,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) {
curl::Url{url},
curl::Path{path},
curl::Flags{curl::Flag_Cache},
curl::StopToken{this->GetToken()},
curl::OnComplete{[this, &image](auto& result) {
if (result.success) {
image.state = ImageDownloadState::Done;
@@ -733,6 +734,7 @@ void Menu::PackListDownload() {
curl::Url{packList_url},
curl::Path{packlist_path},
curl::Flags{curl::Flag_Cache},
curl::StopToken{this->GetToken()},
curl::OnComplete{[this, page_index](auto& result){
log_write("got themezer data\n");
if (!result.success) {