mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 12:51:42 +00:00
Update checker.
This commit is contained in:
parent
21c1d36836
commit
4c1aa74101
8 changed files with 218 additions and 1 deletions
9
.gitmodules
vendored
9
.gitmodules
vendored
|
|
@ -61,3 +61,12 @@
|
||||||
[submodule "thirdparty/implot"]
|
[submodule "thirdparty/implot"]
|
||||||
path = thirdparty/implot
|
path = thirdparty/implot
|
||||||
url = https://github.com/epezent/implot.git
|
url = https://github.com/epezent/implot.git
|
||||||
|
[submodule "thirdparty/json"]
|
||||||
|
path = thirdparty/json
|
||||||
|
url = https://github.com/nlohmann/json
|
||||||
|
[submodule "thirdparty/cpp-httplib"]
|
||||||
|
path = thirdparty/cpp-httplib
|
||||||
|
url = https://github.com/yhirose/cpp-httplib
|
||||||
|
[submodule "thirdparty/curl"]
|
||||||
|
path = thirdparty/curl
|
||||||
|
url = https://github.com/curl/curl
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ set(UNLEASHED_RECOMP_THIRDPARTY_INCLUDES
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/ddspp"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/ddspp"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/imgui"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/implot"
|
||||||
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/json/include"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/libmspack/libmspack/mspack"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include"
|
||||||
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb"
|
"${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb"
|
||||||
|
|
@ -321,6 +322,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(directx-dxc REQUIRED)
|
find_package(directx-dxc REQUIRED)
|
||||||
|
find_package(CURL REQUIRED)
|
||||||
|
|
||||||
if (UNLEASHED_RECOMP_D3D12)
|
if (UNLEASHED_RECOMP_D3D12)
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
|
||||||
|
|
@ -366,6 +368,7 @@ target_link_libraries(UnleashedRecomp PRIVATE
|
||||||
tomlplusplus::tomlplusplus
|
tomlplusplus::tomlplusplus
|
||||||
UnleashedRecompLib
|
UnleashedRecompLib
|
||||||
xxHash::xxhash
|
xxHash::xxhash
|
||||||
|
CURL::libcurl
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(UnleashedRecomp PRIVATE
|
target_include_directories(UnleashedRecomp PRIVATE
|
||||||
|
|
|
||||||
166
UnleashedRecomp/install/update_checker.cpp
Normal file
166
UnleashedRecomp/install/update_checker.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
#include "update_checker.h"
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <shellapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// UpdateChecker
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
static const char *CHECK_URL = "https://api.github.com/repos/blueskythlikesclouds/MikuMikuLibrary/releases/latest";
|
||||||
|
static const char *VISIT_URL = "https://github.com/hedge-dev/UnleashedRecomp/releases/latest";
|
||||||
|
static const char *USER_AGENT = "UnleashedRecomp-Agent";
|
||||||
|
|
||||||
|
static std::atomic<bool> g_updateCheckerInProgress = false;
|
||||||
|
static std::atomic<bool> g_updateCheckerFinished = false;
|
||||||
|
static UpdateChecker::Result g_updateCheckerResult = UpdateChecker::NotStarted;
|
||||||
|
|
||||||
|
size_t updateCheckerWriteCallback(void *contents, size_t size, size_t nmemb, std::string *output)
|
||||||
|
{
|
||||||
|
size_t totalSize = size * nmemb;
|
||||||
|
output->append((char *)contents, totalSize);
|
||||||
|
return totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parseVersion(const std::string &versionStr, int &major, int &minor, int &revision) {
|
||||||
|
size_t start = 0;
|
||||||
|
if (versionStr[0] == 'v') {
|
||||||
|
start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t firstDot = versionStr.find('.', start);
|
||||||
|
size_t secondDot = versionStr.find('.', firstDot + 1);
|
||||||
|
|
||||||
|
if (firstDot == std::string::npos || secondDot == std::string::npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
major = std::stoi(versionStr.substr(start, firstDot - start));
|
||||||
|
minor = std::stoi(versionStr.substr(firstDot + 1, secondDot - firstDot - 1));
|
||||||
|
revision = std::stoi(versionStr.substr(secondDot + 1));
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
fmt::println("Error while parsing version: {}.", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCheckerThread()
|
||||||
|
{
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
CURLcode res;
|
||||||
|
int major, minor, revision;
|
||||||
|
std::string response;
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, CHECK_URL);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, updateCheckerWriteCallback);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT);
|
||||||
|
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
if (res == CURLE_OK)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json root = json::parse(response);
|
||||||
|
auto tag_name_element = root.find("tag_name");
|
||||||
|
if (tag_name_element != root.end() && tag_name_element->is_string())
|
||||||
|
{
|
||||||
|
if (parseVersion(*tag_name_element, major, minor, revision))
|
||||||
|
{
|
||||||
|
if ((g_versionMajor < major) || (g_versionMajor == major && g_versionMinor < minor) || (g_versionMajor == major && g_versionMinor == minor && g_versionRevision < revision))
|
||||||
|
{
|
||||||
|
g_updateCheckerResult = UpdateChecker::Result::UpdateAvailable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_updateCheckerResult = UpdateChecker::Result::AlreadyUpToDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fmt::println("Error while parsing response: tag_name does not contain a valid version string.");
|
||||||
|
g_updateCheckerResult = UpdateChecker::Result::Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fmt::println("Error while parsing response: tag_name not found or not the right type.");
|
||||||
|
g_updateCheckerResult = UpdateChecker::Result::Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const json::exception &e)
|
||||||
|
{
|
||||||
|
fmt::println("Error while parsing response: {}", e.what());
|
||||||
|
g_updateCheckerResult = UpdateChecker::Result::Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fmt::println("Error while performing request: {}", curl_easy_strerror(res));
|
||||||
|
g_updateCheckerResult = UpdateChecker::Result::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
g_updateCheckerFinished = true;
|
||||||
|
g_updateCheckerInProgress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateChecker::initialize()
|
||||||
|
{
|
||||||
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateChecker::start()
|
||||||
|
{
|
||||||
|
if (g_updateCheckerInProgress)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_updateCheckerInProgress = true;
|
||||||
|
g_updateCheckerFinished = false;
|
||||||
|
g_updateCheckerResult = InProgress;
|
||||||
|
std::thread thread(&updateCheckerThread);
|
||||||
|
thread.detach();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateChecker::Result UpdateChecker::check()
|
||||||
|
{
|
||||||
|
if (g_updateCheckerFinished)
|
||||||
|
{
|
||||||
|
return g_updateCheckerResult;
|
||||||
|
}
|
||||||
|
else if (g_updateCheckerInProgress)
|
||||||
|
{
|
||||||
|
return UpdateChecker::InProgress;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return UpdateChecker::NotStarted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateChecker::visitWebsite()
|
||||||
|
{
|
||||||
|
#if defined(WIN32)
|
||||||
|
ShellExecuteA(0, 0, VISIT_URL, 0, 0, SW_SHOW);
|
||||||
|
#elif defined(__linux__)
|
||||||
|
std::string command = "xdg-open " + std::string(VISIT_URL) + " &";
|
||||||
|
std::system(command.c_str());
|
||||||
|
#else
|
||||||
|
static_assert(false, "Visit website not implemented for this platform.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
18
UnleashedRecomp/install/update_checker.h
Normal file
18
UnleashedRecomp/install/update_checker.h
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct UpdateChecker
|
||||||
|
{
|
||||||
|
enum Result
|
||||||
|
{
|
||||||
|
NotStarted,
|
||||||
|
InProgress,
|
||||||
|
AlreadyUpToDate,
|
||||||
|
UpdateAvailable,
|
||||||
|
Failed
|
||||||
|
};
|
||||||
|
|
||||||
|
static void initialize();
|
||||||
|
static bool start();
|
||||||
|
static Result check();
|
||||||
|
static void visitWebsite();
|
||||||
|
};
|
||||||
|
|
@ -15,12 +15,17 @@
|
||||||
#include <user/registry.h>
|
#include <user/registry.h>
|
||||||
#include <kernel/xdbf.h>
|
#include <kernel/xdbf.h>
|
||||||
#include <install/installer.h>
|
#include <install/installer.h>
|
||||||
|
#include <install/update_checker.h>
|
||||||
#include <os/logger.h>
|
#include <os/logger.h>
|
||||||
#include <os/process.h>
|
#include <os/process.h>
|
||||||
#include <os/registry.h>
|
#include <os/registry.h>
|
||||||
#include <ui/installer_wizard.h>
|
#include <ui/installer_wizard.h>
|
||||||
#include <mod/mod_loader.h>
|
#include <mod/mod_loader.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <timeapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
const size_t XMAIOBegin = 0x7FEA0000;
|
const size_t XMAIOBegin = 0x7FEA0000;
|
||||||
const size_t XMAIOEnd = XMAIOBegin + 0x0000FFFF;
|
const size_t XMAIOEnd = XMAIOBegin + 0x0000FFFF;
|
||||||
|
|
||||||
|
|
@ -172,6 +177,18 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
Config::Load();
|
Config::Load();
|
||||||
|
|
||||||
|
// Check the time since the last time an update was checked. Store the new time if the difference is more than six hours.
|
||||||
|
constexpr double TimeBetweenUpdateChecksInSeconds = 6 * 60 * 60;
|
||||||
|
time_t timeNow = std::time(nullptr);
|
||||||
|
double timeDifferenceSeconds = difftime(timeNow, Config::LastChecked);
|
||||||
|
if (timeDifferenceSeconds > TimeBetweenUpdateChecksInSeconds)
|
||||||
|
{
|
||||||
|
UpdateChecker::initialize();
|
||||||
|
UpdateChecker::start();
|
||||||
|
Config::LastChecked = timeNow;
|
||||||
|
Config::Save();
|
||||||
|
}
|
||||||
|
|
||||||
if (Config::ShowConsole)
|
if (Config::ShowConsole)
|
||||||
os::process::ShowConsole();
|
os::process::ShowConsole();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,3 +85,5 @@ CONFIG_DEFINE_HIDDEN("Exports", bool, SaveScoreAtCheckpoints, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Exports", bool, SkipIntroLogos, false);
|
CONFIG_DEFINE_HIDDEN("Exports", bool, SkipIntroLogos, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Exports", bool, UseOfficialTitleOnTitleBar, false);
|
CONFIG_DEFINE_HIDDEN("Exports", bool, UseOfficialTitleOnTitleBar, false);
|
||||||
CONFIG_DEFINE_HIDDEN("Exports", bool, HUDToggleHotkey, false);
|
CONFIG_DEFINE_HIDDEN("Exports", bool, HUDToggleHotkey, false);
|
||||||
|
|
||||||
|
CONFIG_DEFINE("Update", time_t, LastChecked, 0);
|
||||||
|
|
|
||||||
1
thirdparty/json
vendored
Submodule
1
thirdparty/json
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 606b6347edf0758c531abb6c36743e09a4c48a84
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
"platform": "windows"
|
"platform": "windows"
|
||||||
},
|
},
|
||||||
"directx-dxc",
|
"directx-dxc",
|
||||||
"freetype"
|
"freetype",
|
||||||
|
"curl"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue