mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 04:45:47 +00:00
Update checker (#132)
(with some extra spice) Maybe this should be a target for Android as well. Signed-off-by: swurl <swurl@swurl.xyz> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/132 Co-authored-by: swurl <swurl@swurl.xyz> Co-committed-by: swurl <swurl@swurl.xyz>
This commit is contained in:
parent
71df7b1451
commit
4235492079
12 changed files with 208 additions and 9 deletions
|
@ -34,10 +34,9 @@ else
|
|||
export EXTRA_CMAKE_FLAGS=(-DYUZU_USE_PRECOMPILED_HEADERS=OFF)
|
||||
fi
|
||||
|
||||
# TODO(crueter): update checker
|
||||
# if [ "$GITHUB_REF_TYPE" == "tag" ]; then
|
||||
# export EXTRA_CMAKE_FLAGS=($EXTRA_CMAKE_FLAGS -DENABLE_QT_UPDATE_CHECKER=ON)
|
||||
# fi
|
||||
if [ "$RELEASE" == "1" ]; then
|
||||
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" -DENABLE_QT_UPDATE_CHECKER=ON)
|
||||
fi
|
||||
|
||||
mkdir -p build && cd build
|
||||
cmake .. -G Ninja \
|
||||
|
|
2
.github/workflows/trigger_release.yml
vendored
2
.github/workflows/trigger_release.yml
vendored
|
@ -93,7 +93,7 @@ jobs:
|
|||
fetch-tags: true
|
||||
|
||||
- name: Build
|
||||
run: TARGET=appimage ./.ci/linux/build.sh v3 8
|
||||
run: TARGET=appimage RELEASE=1 ./.ci/linux/build.sh v3 8
|
||||
|
||||
- name: Package AppImage
|
||||
run: ./.ci/linux/package.sh v3 &> /dev/null
|
||||
|
|
|
@ -34,9 +34,11 @@ cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID"
|
|||
|
||||
option(ENABLE_OPENGL "Enable OpenGL" ON)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
|
@ -353,6 +355,9 @@ endif()
|
|||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
find_package(cpp-jwt 1.4 CONFIG)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER)
|
||||
find_package(httplib 0.12 MODULE COMPONENTS OpenSSL)
|
||||
endif()
|
||||
|
||||
|
|
2
externals/CMakeLists.txt
vendored
2
externals/CMakeLists.txt
vendored
|
@ -119,7 +119,7 @@ endif()
|
|||
add_subdirectory(sirit)
|
||||
|
||||
# httplib
|
||||
if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
|
||||
if ((ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER) AND NOT TARGET httplib::httplib)
|
||||
set(HTTPLIB_REQUIRE_OPENSSL ON)
|
||||
add_subdirectory(cpp-httplib)
|
||||
endif()
|
||||
|
|
|
@ -266,6 +266,12 @@ file(GLOB COMPAT_LIST
|
|||
file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*)
|
||||
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
|
||||
|
||||
if (ENABLE_QT_UPDATE_CHECKER)
|
||||
target_link_libraries(yuzu PRIVATE httplib::httplib)
|
||||
target_sources(yuzu PRIVATE update_checker.cpp)
|
||||
target_compile_definitions(yuzu PUBLIC ENABLE_QT_UPDATE_CHECKER)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT_TRANSLATION)
|
||||
set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
|
||||
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "input_common/drivers/virtual_amiibo.h"
|
||||
#include "input_common/main.h"
|
||||
#include "ui_qt_amiibo_settings.h"
|
||||
#include "web_service/web_result.h"
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
#include "web_service/web_backend.h"
|
||||
#endif
|
||||
|
|
|
@ -296,6 +296,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
|
|||
INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
|
||||
tr("Forcibly disables the use of the controller applet by guests.\nWhen a guest "
|
||||
"attempts to open the controller applet, it is immediately closed."));
|
||||
INSERT(UISettings,
|
||||
check_for_updates,
|
||||
tr("Check for updates"),
|
||||
tr("Whether or not to check for updates upon startup."));
|
||||
|
||||
// Linux
|
||||
INSERT(Settings, enable_gamemode, tr("Enable Gamemode"), QString());
|
||||
|
|
|
@ -52,6 +52,10 @@
|
|||
#include "yuzu/multiplayer/state.h"
|
||||
#include "yuzu/util/controller_navigation.h"
|
||||
|
||||
#ifdef ENABLE_QT_UPDATE_CHECKER
|
||||
#include "yuzu/update_checker.h"
|
||||
#endif
|
||||
|
||||
#ifdef YUZU_ROOM
|
||||
#include "dedicated_room/yuzu_room.h"
|
||||
#endif
|
||||
|
@ -313,6 +317,7 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
|
|||
provider{std::make_unique<FileSys::ManualContentProvider>()} {
|
||||
Common::FS::CreateEdenPaths();
|
||||
this->config = std::make_unique<QtConfig>();
|
||||
|
||||
#ifdef __unix__
|
||||
SetupSigInterrupts();
|
||||
SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue());
|
||||
|
@ -410,6 +415,27 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
|
|||
|
||||
show();
|
||||
|
||||
#ifdef ENABLE_QT_UPDATE_CHECKER
|
||||
if (UISettings::values.check_for_updates) {
|
||||
update_future = QtConcurrent::run([]() -> QString {
|
||||
const bool is_prerelease =
|
||||
((strstr(Common::g_build_fullname, "pre-alpha") != NULL) ||
|
||||
(strstr(Common::g_build_fullname, "alpha") != NULL) ||
|
||||
(strstr(Common::g_build_fullname, "beta") != NULL) ||
|
||||
(strstr(Common::g_build_fullname, "rc") != NULL));
|
||||
const std::optional<std::string> latest_release_tag =
|
||||
UpdateChecker::GetLatestRelease(is_prerelease);
|
||||
if (latest_release_tag && latest_release_tag.value() != Common::g_build_fullname) {
|
||||
return QString::fromStdString(latest_release_tag.value());
|
||||
}
|
||||
return QString{};
|
||||
});
|
||||
QObject::connect(&update_watcher, &QFutureWatcher<QString>::finished, this,
|
||||
&GMainWindow::OnEmulatorUpdateAvailable);
|
||||
update_watcher.setFuture(update_future);
|
||||
}
|
||||
#endif
|
||||
|
||||
system->SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||
system->RegisterContentProvider(FileSys::ContentProviderUnionSlot::FrontendManual,
|
||||
provider.get());
|
||||
|
@ -4767,6 +4793,28 @@ void GMainWindow::MigrateConfigFiles() {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_QT_UPDATE_CHECKER
|
||||
void GMainWindow::OnEmulatorUpdateAvailable() {
|
||||
QString version_string = update_future.result();
|
||||
if (version_string.isEmpty())
|
||||
return;
|
||||
|
||||
QMessageBox update_prompt(this);
|
||||
update_prompt.setWindowTitle(tr("Update Available"));
|
||||
update_prompt.setIcon(QMessageBox::Information);
|
||||
update_prompt.addButton(QMessageBox::Yes);
|
||||
update_prompt.addButton(QMessageBox::Ignore);
|
||||
update_prompt.setText(tr("Update %1 for Eden is available.\nWould you like to download it?")
|
||||
.arg(version_string));
|
||||
update_prompt.exec();
|
||||
if (update_prompt.button(QMessageBox::Yes) == update_prompt.clickedButton()) {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QString::fromStdString("https://github.com/eden-emulator/Releases/releases/tag/") +
|
||||
version_string));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_view title_version,
|
||||
std::string_view gpu_vendor) {
|
||||
const auto branch_name = std::string(Common::g_scm_branch);
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <QTimer>
|
||||
#include <QTranslator>
|
||||
|
||||
#include "common/announce_multiplayer_room.h"
|
||||
#include "common/common_types.h"
|
||||
#include "configuration/qt_config.h"
|
||||
#include "frontend_common/content_manager.h"
|
||||
|
@ -21,14 +20,19 @@
|
|||
#include "user_data_migration.h"
|
||||
#include "yuzu/compatibility_list.h"
|
||||
#include "yuzu/hotkeys.h"
|
||||
#include "yuzu/util/controller_navigation.h"
|
||||
|
||||
#ifdef __unix__
|
||||
#include <QDBusObjectPath>
|
||||
#include <QVariant>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QtDBus>
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_QT_UPDATE_CHECKER
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
#endif
|
||||
|
||||
class QtConfig;
|
||||
class ClickableLabel;
|
||||
class EmuThread;
|
||||
|
@ -414,6 +418,10 @@ private slots:
|
|||
void OnEmulationStopped();
|
||||
void OnEmulationStopTimeExpired();
|
||||
|
||||
#ifdef ENABLE_QT_UPDATE_CHECKER
|
||||
void OnEmulatorUpdateAvailable();
|
||||
#endif
|
||||
|
||||
private:
|
||||
QString GetGameListErrorRemoving(InstalledEntryType type) const;
|
||||
void RemoveBaseContent(u64 program_id, InstalledEntryType type);
|
||||
|
@ -483,6 +491,11 @@ private:
|
|||
std::unique_ptr<PlayTime::PlayTimeManager> play_time_manager;
|
||||
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
|
||||
|
||||
#ifdef ENABLE_QT_UPDATE_CHECKER
|
||||
QFuture<QString> update_future;
|
||||
QFutureWatcher<QString> update_watcher;
|
||||
#endif
|
||||
|
||||
MultiplayerState* multiplayer_state = nullptr;
|
||||
|
||||
GRenderWindow* render_window;
|
||||
|
|
|
@ -141,6 +141,7 @@ struct Values {
|
|||
true,
|
||||
true};
|
||||
Setting<bool> disable_web_applet{linkage, true, "disable_web_applet", Category::Ui};
|
||||
Setting<bool> check_for_updates{linkage, true, "check_for_updates", Category::UiGeneral};
|
||||
|
||||
// Discord RPC
|
||||
Setting<bool> enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui};
|
||||
|
|
109
src/yuzu/update_checker.cpp
Normal file
109
src/yuzu/update_checker.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// SPDX-FileCopyrightText: eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "update_checker.h"
|
||||
#include "common/logging/log.h"
|
||||
#include <fmt/format.h>
|
||||
#include <httplib.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
std::optional<std::string> UpdateChecker::GetResponse(std::string url, std::string path)
|
||||
{
|
||||
constexpr std::size_t timeout_seconds = 15;
|
||||
|
||||
std::unique_ptr<httplib::Client> client = std::make_unique<httplib::Client>(url);
|
||||
client->set_connection_timeout(timeout_seconds);
|
||||
client->set_read_timeout(timeout_seconds);
|
||||
client->set_write_timeout(timeout_seconds);
|
||||
|
||||
if (client == nullptr) {
|
||||
LOG_ERROR(Frontend, "Invalid URL {}{}", url, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
httplib::Request request{
|
||||
.method = "GET",
|
||||
.path = path,
|
||||
};
|
||||
|
||||
client->set_follow_location(true);
|
||||
const auto result = client->send(request);
|
||||
if (!result) {
|
||||
LOG_ERROR(Frontend, "GET to {}{} returned null", url, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto& response = result.value();
|
||||
if (response.status >= 400) {
|
||||
LOG_ERROR(Frontend, "GET to {}{} returned error status code: {}", url, path, response.status);
|
||||
return {};
|
||||
}
|
||||
if (!response.headers.contains("content-type")) {
|
||||
LOG_ERROR(Frontend, "GET to {}{} returned no content", url, path);
|
||||
return {};
|
||||
}
|
||||
|
||||
return response.body;
|
||||
}
|
||||
|
||||
std::optional<std::string> UpdateChecker::GetLatestRelease(bool include_prereleases)
|
||||
{
|
||||
constexpr auto update_check_url = "http://api.github.com";
|
||||
std::string update_check_path = "/repos/eden-emulator/Releases";
|
||||
try {
|
||||
if (include_prereleases) { // This can return either a prerelease or a stable release,
|
||||
// whichever is more recent.
|
||||
const auto update_check_tags_path = update_check_path + "/tags";
|
||||
const auto update_check_releases_path = update_check_path + "/releases";
|
||||
|
||||
const auto tags_response = GetResponse(update_check_url, update_check_tags_path);
|
||||
const auto releases_response = GetResponse(update_check_url, update_check_releases_path);
|
||||
|
||||
if (!tags_response || !releases_response)
|
||||
return {};
|
||||
|
||||
const std::string latest_tag
|
||||
= nlohmann::json::parse(tags_response.value()).at(0).at("name");
|
||||
const bool latest_tag_has_release = releases_response.value().find(
|
||||
fmt::format("\"{}\"", latest_tag))
|
||||
!= std::string::npos;
|
||||
|
||||
// If there is a newer tag, but that tag has no associated release, don't prompt the
|
||||
// user to update.
|
||||
if (!latest_tag_has_release)
|
||||
return {};
|
||||
|
||||
return latest_tag;
|
||||
} else { // This is a stable release, only check for other stable releases.
|
||||
update_check_path += "/releases/latest";
|
||||
const auto response = GetResponse(update_check_url, update_check_path);
|
||||
|
||||
if (!response)
|
||||
return {};
|
||||
|
||||
const std::string latest_tag = nlohmann::json::parse(response.value()).at("tag_name");
|
||||
return latest_tag;
|
||||
}
|
||||
|
||||
} catch (nlohmann::detail::out_of_range&) {
|
||||
LOG_ERROR(Frontend,
|
||||
"Parsing JSON response from {}{} failed during update check: "
|
||||
"nlohmann::detail::out_of_range",
|
||||
update_check_url,
|
||||
update_check_path);
|
||||
return {};
|
||||
} catch (nlohmann::detail::type_error&) {
|
||||
LOG_ERROR(Frontend,
|
||||
"Parsing JSON response from {}{} failed during update check: "
|
||||
"nlohmann::detail::type_error",
|
||||
update_check_url,
|
||||
update_check_path);
|
||||
return {};
|
||||
}
|
||||
}
|
13
src/yuzu/update_checker.h
Normal file
13
src/yuzu/update_checker.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace UpdateChecker {
|
||||
std::optional<std::string> GetResponse(std::string url, std::string path);
|
||||
std::optional<std::string> GetLatestRelease(bool);
|
||||
} // namespace UpdateChecker
|
Loading…
Add table
Add a link
Reference in a new issue