update_manager: use v3 api for all OS

This commit is contained in:
Megamouse 2025-02-03 02:19:10 +01:00 committed by Ani
parent 6123838a48
commit 50387cc516
5 changed files with 169 additions and 109 deletions

View file

@ -61,15 +61,6 @@ DYNAMIC_IMPORT("ntdll.dll", NtSetTimerResolution, NTSTATUS(ULONG DesiredResoluti
#if defined(__APPLE__)
#include <dispatch/dispatch.h>
#if defined (__x86_64__)
// sysinfo_darwin.mm
namespace Darwin_Version
{
extern int getNSmajorVersion();
extern int getNSminorVersion();
extern int getNSpatchVersion();
}
#endif
#endif
#include "Utilities/Config.h"
@ -618,12 +609,10 @@ int main(int argc, char** argv)
#endif
#if defined(__APPLE__) && defined(__x86_64__)
const int osx_ver_major = Darwin_Version::getNSmajorVersion();
const int osx_ver_minor = Darwin_Version::getNSminorVersion();
if ((osx_ver_major == 14 && osx_ver_minor < 3) && (utils::get_cpu_brand().rfind("VirtualApple", 0) == 0))
if (const utils::OS_version os = utils::get_OS_version();
os.version_major == 14 && os.version_minor < 3 && (utils::get_cpu_brand().rfind("VirtualApple", 0) == 0))
{
const int osx_ver_patch = Darwin_Version::getNSpatchVersion();
report_fatal_error(fmt::format("RPCS3 requires macOS 14.3.0 or later.\nYou're currently using macOS %i.%i.%i.\nPlease update macOS from System Settings.\n\n", osx_ver_major, osx_ver_minor, osx_ver_patch));
report_fatal_error(fmt::format("RPCS3 requires macOS 14.3.0 or later.\nYou're currently using macOS %i.%i.%i.\nPlease update macOS from System Settings.\n\n", os.version_major, os.version_minor, os.version_patch));
}
#endif
@ -659,7 +648,7 @@ int main(int argc, char** argv)
// Write OS version
logs::stored_message os{sys_log.always()};
os.text = utils::get_OS_version();
os.text = utils::get_OS_version_string();
// Write Qt version
logs::stored_message qt{(strcmp(QT_VERSION_STR, qVersion()) != 0) ? sys_log.error : sys_log.notice};

View file

@ -11,6 +11,7 @@
#include "Crypto/utils.h"
#include "util/logs.hpp"
#include "util/types.hpp"
#include "util/sysinfo.hpp"
#include <QApplication>
#include <QCheckBox>
@ -45,16 +46,6 @@
#include <sys/stat.h>
#endif
#if defined(__APPLE__)
// sysinfo_darwin.mm
namespace Darwin_Version
{
extern int getNSmajorVersion();
extern int getNSminorVersion();
extern int getNSpatchVersion();
}
#endif
LOG_CHANNEL(update_log, "UPDATER");
update_manager::update_manager(QObject* parent, std::shared_ptr<gui_settings> gui_settings)
@ -116,26 +107,11 @@ void update_manager::check_for_updates(bool automatic, bool check_only, bool aut
Q_EMIT signal_update_available(result_json && !m_update_message.isEmpty());
});
#if defined(__APPLE__)
const std::string url = fmt::format("https://update.rpcs3.net/"
"?api=v3"
"&c=%s"
"&os_type=macos"
"&os_arch="
#if defined(ARCH_X64)
"x64"
#elif defined(ARCH_ARM64)
"arm64"
#endif
"&os_version=%i.%i.%i",
rpcs3::get_commit_and_hash().second,
Darwin_Version::getNSmajorVersion(),
Darwin_Version::getNSminorVersion(),
Darwin_Version::getNSpatchVersion());
#else
const std::string url = "https://update.rpcs3.net/?api=v2&c=" + rpcs3::get_commit_and_hash().second;
#endif
const utils::OS_version os = utils::get_OS_version();
const std::string url = fmt::format("https://update.rpcs3.net/?api=v3&c=%s&os_type=%s&os_arch=%s&os_version=%i.%i.%i",
rpcs3::get_commit_and_hash().second, os.type, os.arch, os.version_major, os.version_minor, os.version_patch);
m_downloader->start(url, true, !automatic, tr("Checking For Updates"), true);
}
@ -199,11 +175,25 @@ bool update_manager::handle_json(bool automatic, bool check_only, bool auto_acce
#endif
// Check that every bit of info we need is there
if (!latest[os].isObject() || !latest[os]["download"].isString() || !latest[os]["size"].isDouble() || !latest[os]["checksum"].isString() || !latest["version"].isString() ||
!latest["datetime"].isString() ||
(hash_found && (!current.isObject() || !current["version"].isString() || !current["datetime"].isString())))
const auto check_json = [](bool cond, std::string_view msg) -> bool
{
if (cond) return true;
update_log.error("%s", msg);
return false;
};
if (!(check_json(latest[os].isObject(), fmt::format("Node 'latest_build: %s' not found", os)) &&
check_json(latest[os]["download"].isString(), fmt::format("Node 'latest_build: %s: download' not found or not a string", os)) &&
check_json(latest[os]["size"].isDouble(), fmt::format("Node 'latest_build: %s: size' not found or not a double", os)) &&
check_json(latest[os]["checksum"].isString(), fmt::format("Node 'latest_build: %s: checksum' not found or not a string", os)) &&
check_json(latest["version"].isString(), "Node 'latest_build: version' not found or not a string") &&
check_json(latest["datetime"].isString(), "Node 'latest_build: datetime' not found or not a string")
) ||
(hash_found && !(
check_json(current.isObject(), "JSON doesn't contain current_build section") &&
check_json(current["version"].isString(), "Node 'current_build: datetime' not found or not a string") &&
check_json(current["datetime"].isString(), "Node 'current_build: version' not found or not a string")
)))
{
update_log.error("Some information seems unavailable");
return false;
}

View file

@ -129,20 +129,6 @@ namespace utils
per_core_usage.resize(utils::get_thread_count());
std::fill(per_core_usage.begin(), per_core_usage.end(), 0.0);
#if defined(_WIN32) || defined(__linux__)
const auto string_to_number = [](const std::string& str) -> std::pair<bool, size_t>
{
std::add_pointer_t<char> eval;
const size_t number = std::strtol(str.c_str(), &eval, 10);
if (str.c_str() + str.size() == eval)
{
return { true, number };
}
return { false, 0 };
};
#ifdef _WIN32
if (!m_cpu_cores || !m_cpu_query)
{
@ -304,7 +290,6 @@ namespace utils
{
perf_log.error("Failed to open /proc/stat (%s)", strerror(errno));
}
#endif
#else
total_usage = get_usage();
#endif

View file

@ -74,45 +74,45 @@ namespace Darwin_ProcessInfo
namespace utils
{
#ifdef _WIN32
// Some helpers for sanity
const auto read_reg_dword = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, DWORD>
{
DWORD val = 0;
DWORD len = sizeof(val);
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&val), &len))
{
return { false, 0 };
}
return { true, val };
};
const auto read_reg_sz = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, std::string>
{
constexpr usz MAX_SZ_LEN = 255;
char sz[MAX_SZ_LEN + 1] {};
DWORD sz_len = MAX_SZ_LEN;
// Safety; null terminate
sz[0] = 0;
sz[MAX_SZ_LEN] = 0;
// Read string
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(sz), &sz_len))
{
return { false, "" };
}
// Safety, force null terminator
if (sz_len < MAX_SZ_LEN)
{
sz[sz_len] = 0;
}
return { true, sz };
};
// Alternative way to read OS version using the registry.
static std::string get_fallback_windows_version()
{
// Some helpers for sanity
const auto read_reg_dword = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, DWORD>
{
DWORD val;
DWORD len = sizeof(val);
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&val), &len))
{
return { false, 0 };
}
return { true, val };
};
const auto read_reg_sz = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, std::string>
{
constexpr usz MAX_SZ_LEN = 255;
char sz[MAX_SZ_LEN + 1];
DWORD sz_len = MAX_SZ_LEN;
// Safety; null terminate
sz[0] = 0;
sz[MAX_SZ_LEN] = 0;
// Read string
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(sz), &sz_len))
{
return { false, "" };
}
// Safety, force null terminator
if (sz_len < MAX_SZ_LEN)
{
sz[sz_len] = 0;
}
return { true, sz };
};
HKEY hKey;
if (ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey))
{
@ -661,14 +661,88 @@ std::string utils::get_firmware_version()
return {};
}
std::string utils::get_OS_version()
utils::OS_version utils::get_OS_version()
{
OS_version res {};
#if _WIN32
res.type = "windows";
#elif __linux__
res.type = "linux";
#elif __APPLE__
res.type = "macos";
#elif __FreeBSD__
res.type = "freebsd";
#else
res.type = "unknown";
#endif
#if defined(ARCH_X64)
res.arch = "x64";
#elif defined(ARCH_ARM64)
res.arch = "arm64";
#else
res.arch = "unknown";
#endif
#ifdef _WIN32
// GetVersionEx is deprecated, RtlGetVersion is kernel-mode only and AnalyticsInfo is UWP only.
// So we're forced to read PEB instead to get Windows version info. It's ugly but works.
#if defined(ARCH_X64)
constexpr DWORD peb_offset = 0x60;
const INT_PTR peb = __readgsqword(peb_offset);
res.version_major = *reinterpret_cast<const DWORD*>(peb + 0x118);
res.version_minor = *reinterpret_cast<const DWORD*>(peb + 0x11c);
res.version_patch = *reinterpret_cast<const WORD*>(peb + 0x120);
#else
HKEY hKey;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
const auto [check_major, version_major] = read_reg_dword(hKey, "CurrentMajorVersionNumber");
const auto [check_minor, version_minor] = read_reg_dword(hKey, "CurrentMinorVersionNumber");
const auto [check_build, version_patch] = read_reg_sz(hKey, "CurrentBuildNumber");
if (check_major) res.version_major = version_major;
if (check_minor) res.version_minor = version_minor;
if (check_build) res.version_patch = stoi(version_patch);
RegCloseKey(hKey);
}
#endif
#elif defined (__APPLE__)
res.version_major = Darwin_Version::getNSmajorVersion();
res.version_minor = Darwin_Version::getNSminorVersion();
res.version_patch = Darwin_Version::getNSpatchVersion();
#else
if (struct utsname details = {}; !uname(&details))
{
const std::vector<std::string> version_list = fmt::split(details.release, { "." });
const auto get_version_part = [&version_list](usz i) -> usz
{
if (version_list.size() <= i) return 0;
if (const auto [success, version_part] = string_to_number(version_list[i]); success)
{
return version_part;
}
return 0;
};
res.version_major = get_version_part(0);
res.version_minor = get_version_part(1);
res.version_patch = get_version_part(2);
}
#endif
return res;
}
std::string utils::get_OS_version_string()
{
std::string output;
#ifdef _WIN32
// GetVersionEx is deprecated, RtlGetVersion is kernel-mode only and AnalyticsInfo is UWP only.
// So we're forced to read PEB instead to get Windows version info. It's ugly but works.
#if defined(ARCH_X64)
const DWORD peb_offset = 0x60;
constexpr DWORD peb_offset = 0x60;
const INT_PTR peb = __readgsqword(peb_offset);
const DWORD version_major = *reinterpret_cast<const DWORD*>(peb + 0x118);
const DWORD version_minor = *reinterpret_cast<const DWORD*>(peb + 0x11c);
@ -1014,10 +1088,20 @@ u32 utils::get_cpu_model()
#endif
}
namespace utils
u64 utils::_get_main_tid()
{
u64 _get_main_tid()
{
return thread_ctrl::get_tid();
}
return thread_ctrl::get_tid();
}
std::pair<bool, usz> utils::string_to_number(std::string_view str)
{
std::add_pointer_t<char> eval;
const usz number = std::strtol(str.data(), &eval, 10);
if (str.data() + str.size() == eval)
{
return { true, number };
}
return { false, 0 };
}

View file

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "util/types.hpp"
#include <string>
@ -67,7 +67,17 @@ namespace utils
std::string get_firmware_version();
std::string get_OS_version();
struct OS_version
{
std::string type;
std::string arch;
int version_major = 0;
int version_minor = 0;
int version_patch = 0;
};
OS_version get_OS_version();
std::string get_OS_version_string();
int get_maxfiles();
@ -94,4 +104,6 @@ namespace utils
{
return s_tsc_freq;
}
std::pair<bool, usz> string_to_number(std::string_view str);
}