forgot the files
This commit is contained in:
parent
23b5b23b8b
commit
c04bdcbc6b
|
|
@ -0,0 +1,179 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "overrides_updater.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QtConcurrent>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/game_overrides.h"
|
||||||
|
#include "qt_common/config/uisettings.h"
|
||||||
|
|
||||||
|
#include <httplib.h>
|
||||||
|
|
||||||
|
#ifdef YUZU_BUNDLED_OPENSSL
|
||||||
|
#include <openssl/cert.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OverridesUpdater::OverridesUpdater(QWidget* parent)
|
||||||
|
: QObject(parent), parent_widget(parent) {}
|
||||||
|
|
||||||
|
OverridesUpdater::~OverridesUpdater() = default;
|
||||||
|
|
||||||
|
void OverridesUpdater::CheckAndUpdate() {
|
||||||
|
if (!UISettings::values.enable_global_overrides.GetValue()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UISettings::values.overrides_consent_given.GetValue()) {
|
||||||
|
ShowConsentDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UISettings::values.auto_update_overrides.GetValue()) {
|
||||||
|
(void)QtConcurrent::run([this] {
|
||||||
|
DownloadAndSave();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverridesUpdater::ShowConsentDialog() {
|
||||||
|
QMessageBox msgBox(parent_widget);
|
||||||
|
msgBox.setWindowTitle(tr("Game Overrides Database"));
|
||||||
|
msgBox.setIcon(QMessageBox::Question);
|
||||||
|
msgBox.setText(tr("Would you like to update the game overrides database?"));
|
||||||
|
msgBox.setInformativeText(
|
||||||
|
tr("This will download a config file from GitHub to enable critical per-game settings.\n\n"
|
||||||
|
"Your choice will be saved. You can change this later in:\n"
|
||||||
|
"Settings -> General -> Enable global game overrides"));
|
||||||
|
|
||||||
|
QCheckBox autoUpdateCheckbox(tr("Automatically update the list"), &msgBox);
|
||||||
|
autoUpdateCheckbox.setChecked(true);
|
||||||
|
msgBox.setCheckBox(&autoUpdateCheckbox);
|
||||||
|
|
||||||
|
auto* yesButton = msgBox.addButton(tr("Yes, Enable"), QMessageBox::AcceptRole);
|
||||||
|
msgBox.addButton(tr("No Thanks"), QMessageBox::RejectRole);
|
||||||
|
|
||||||
|
msgBox.setDefaultButton(yesButton);
|
||||||
|
msgBox.exec();
|
||||||
|
|
||||||
|
auto* clicked = msgBox.clickedButton();
|
||||||
|
|
||||||
|
UISettings::values.overrides_consent_given.SetValue(true);
|
||||||
|
|
||||||
|
if (clicked == yesButton) {
|
||||||
|
UISettings::values.auto_update_overrides.SetValue(autoUpdateCheckbox.isChecked());
|
||||||
|
UISettings::values.enable_global_overrides.SetValue(true);
|
||||||
|
emit ConfigChanged();
|
||||||
|
DownloadOverrides();
|
||||||
|
} else {
|
||||||
|
UISettings::values.auto_update_overrides.SetValue(false);
|
||||||
|
UISettings::values.enable_global_overrides.SetValue(false);
|
||||||
|
emit ConfigChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverridesUpdater::DownloadOverrides() {
|
||||||
|
(void)QtConcurrent::run([this] {
|
||||||
|
const bool success = DownloadAndSave();
|
||||||
|
emit UpdateCompleted(success, success
|
||||||
|
? tr("Game overrides updated successfully.")
|
||||||
|
: tr("Failed to download game overrides."));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> OverridesUpdater::FetchOverridesFile() {
|
||||||
|
try {
|
||||||
|
constexpr std::size_t timeout_seconds = 3;
|
||||||
|
|
||||||
|
std::unique_ptr<httplib::Client> client = std::make_unique<httplib::Client>(kOverridesUrl);
|
||||||
|
client->set_connection_timeout(timeout_seconds);
|
||||||
|
client->set_read_timeout(timeout_seconds);
|
||||||
|
client->set_write_timeout(timeout_seconds);
|
||||||
|
|
||||||
|
#ifdef YUZU_BUNDLED_OPENSSL
|
||||||
|
client->load_ca_cert_store(kCert, sizeof(kCert));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
httplib::Request request{
|
||||||
|
.method = "GET",
|
||||||
|
.path = kOverridesPath,
|
||||||
|
};
|
||||||
|
|
||||||
|
client->set_follow_location(true);
|
||||||
|
httplib::Result result = client->send(request);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
LOG_ERROR(Frontend, "GET to {}{} returned null", kOverridesUrl, kOverridesPath);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.value().body;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG_ERROR(Frontend, "Failed to fetch overrides: {}", e.what());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OverridesUpdater::DownloadAndSave() {
|
||||||
|
LOG_INFO(Frontend, "Checking for game overrides updates...");
|
||||||
|
|
||||||
|
const auto response = FetchOverridesFile();
|
||||||
|
if (!response) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& data = *response;
|
||||||
|
|
||||||
|
auto remote_version = ParseVersion(data);
|
||||||
|
if (!remote_version) {
|
||||||
|
LOG_ERROR(Frontend, "Downloaded overrides file has invalid format (no version header)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto local_version = Core::GameOverrides::GetOverridesFileVersion();
|
||||||
|
if (local_version && *local_version >= *remote_version) {
|
||||||
|
LOG_INFO(Frontend, "Game overrides are up to date (v{})", *local_version);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto path = Core::GameOverrides::GetOverridesPath();
|
||||||
|
std::filesystem::create_directories(path.parent_path());
|
||||||
|
|
||||||
|
std::ofstream file(path, std::ios::binary);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
LOG_ERROR(Frontend, "Failed to write overrides file: {}", path.string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write(data.data(), static_cast<std::streamsize>(data.size()));
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
LOG_INFO(Frontend, "Game overrides updated to version {}", *remote_version);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::uint32_t> OverridesUpdater::ParseVersion(const std::string& data) {
|
||||||
|
// Look for "; version=X" on first line
|
||||||
|
const auto newline_pos = data.find('\n');
|
||||||
|
const std::string first_line = (newline_pos != std::string::npos)
|
||||||
|
? data.substr(0, newline_pos)
|
||||||
|
: data;
|
||||||
|
|
||||||
|
constexpr const char* prefix = "; version=";
|
||||||
|
const auto prefix_pos = first_line.find(prefix);
|
||||||
|
if (prefix_pos == std::string::npos) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto version_str = first_line.substr(prefix_pos + std::strlen(prefix));
|
||||||
|
try {
|
||||||
|
return static_cast<std::uint32_t>(std::stoul(version_str));
|
||||||
|
} catch (...) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
class QWidget;
|
||||||
|
|
||||||
|
class OverridesUpdater : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit OverridesUpdater(QWidget* parent = nullptr);
|
||||||
|
~OverridesUpdater() override;
|
||||||
|
|
||||||
|
void CheckAndUpdate();
|
||||||
|
void DownloadOverrides();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void ConfigChanged();
|
||||||
|
void UpdateCompleted(bool success, const QString& message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ShowConsentDialog();
|
||||||
|
bool DownloadAndSave();
|
||||||
|
static std::optional<std::uint32_t> ParseVersion(const std::string& data);
|
||||||
|
static std::optional<std::string> FetchOverridesFile();
|
||||||
|
|
||||||
|
QWidget* parent_widget{};
|
||||||
|
|
||||||
|
static constexpr const char* kOverridesUrl = "https://raw.githubusercontent.com";
|
||||||
|
static constexpr const char* kOverridesPath = "/eden-emulator/eden-overrides/refs/heads/master/overrides.ini";
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue