Browse Source

add threaded download and mutex, else it blocks the start for to long when in sync

pull/3308/head
Maufeat 3 weeks ago
committed by crueter
parent
commit
691ede2882
  1. 86
      src/core/hle/service/bcat/news/builtin_news.cpp

86
src/core/hle/service/bcat/news/builtin_news.cpp

@ -20,10 +20,12 @@
#include <cstring>
#include <filesystem>
#include <fstream>
#include <future>
#include <iomanip>
#include <mutex>
#include <optional>
#include <sstream>
#include <thread>
#ifdef YUZU_BUNDLED_OPENSSL
#include <openssl/cert.h>
@ -41,6 +43,8 @@ bool default_logos_loaded = false;
std::unordered_map<std::string, std::vector<u8>> news_images_small;
std::unordered_map<std::string, std::vector<u8>> news_images_large;
std::mutex images_mutex;
std::filesystem::path GetCachePath() {
return Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir) / "news" / "github_releases.json";
@ -147,16 +151,19 @@ void LoadDefaultLogos() {
std::vector<u8> GetNewsImage(std::string_view news_id, bool large) {
const std::string id_str{news_id};
auto& cache = large ? news_images_large : news_images_small;
if (auto it = cache.find(id_str); it != cache.end()) {
return it->second;
{
std::lock_guard lock{images_mutex};
auto& cache = large ? news_images_large : news_images_small;
if (auto it = cache.find(id_str); it != cache.end()) {
return it->second;
}
}
const auto cache_path = GetNewsImagePath(news_id, large);
auto data = TryLoadFromDisk(cache_path);
if (data.empty()) {
const std::string url = fmt::format("/news/{}_{}.jpg", news_id, large ? "large" : "small");
const std::string url = fmt::format("/news/{}_{}.jpg", id_str, large ? "large" : "small");
data = DownloadImage(url, cache_path);
}
@ -164,9 +171,48 @@ std::vector<u8> GetNewsImage(std::string_view news_id, bool large) {
data = large ? default_logo_large : default_logo_small;
}
{
std::lock_guard lock{images_mutex};
auto& cache = large ? news_images_large : news_images_small;
cache[id_str] = data;
}
return data;
}
void PreloadNewsImages(const std::vector<u32>& news_ids) {
std::vector<std::future<void>> futures;
futures.reserve(news_ids.size() * 2);
for (const u32 id : news_ids) {
const std::string id_str = fmt::format("{}", id);
{
std::lock_guard lock{images_mutex};
if (news_images_small.contains(id_str) && news_images_large.contains(id_str)) {
continue;
}
}
const auto path_small = GetNewsImagePath(id_str, false);
const auto path_large = GetNewsImagePath(id_str, true);
if (std::filesystem::exists(path_small) && std::filesystem::exists(path_large)) {
continue;
}
futures.push_back(std::async(std::launch::async, [id_str]() {
GetNewsImage(id_str, false);
}));
futures.push_back(std::async(std::launch::async, [id_str]() {
GetNewsImage(id_str, true);
}));
}
for (auto& f : futures) {
f.wait();
}
}
std::optional<std::string> ReadCachedJson() {
const auto path = GetCachePath();
if (!std::filesystem::exists(path)) return std::nullopt;
@ -307,6 +353,19 @@ void ImportReleases(std::string_view json_text) {
if (!root.is_array()) return;
std::vector<u32> news_ids;
for (const auto& rel : root) {
if (!rel.is_object()) continue;
std::string title = rel.value("name", rel.value("tag_name", std::string{}));
if (title.empty()) continue;
const u64 release_id = rel.value("id", 0);
const u32 news_id = release_id ? static_cast<u32>(release_id & 0x7FFFFFFF) : HashToNewsId(title);
news_ids.push_back(news_id);
}
PreloadNewsImages(news_ids);
for (const auto& rel : root) {
if (!rel.is_object()) continue;
@ -472,19 +531,18 @@ void EnsureBuiltinNewsLoaded() {
std::call_once(once, [] {
LoadDefaultLogos();
if (const auto fresh = DownloadReleasesJson()) {
WriteCachedJson(*fresh);
ImportReleases(*fresh);
LOG_DEBUG(Service_BCAT, ", {} entries, downloaded", NewsStorage::Instance().ListAll().size());
return;
}
// Fallback to cached JSON if download failed
if (const auto cached = ReadCachedJson()) {
ImportReleases(*cached);
LOG_DEBUG(Service_BCAT, ", {} entries, cached", NewsStorage::Instance().ListAll().size());
return;
LOG_DEBUG(Service_BCAT, "news: {} entries loaded from cache", NewsStorage::Instance().ListAll().size());
}
std::thread([] {
if (const auto fresh = DownloadReleasesJson()) {
WriteCachedJson(*fresh);
ImportReleases(*fresh);
LOG_DEBUG(Service_BCAT, "news: {} entries updated from GitHub", NewsStorage::Instance().ListAll().size());
}
}).detach();
});
}

Loading…
Cancel
Save