mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 06:21:26 +12:00
patch_manager: add download button
This commit is contained in:
parent
1e4655aef6
commit
46e8b4f561
10 changed files with 147 additions and 22 deletions
|
@ -98,19 +98,24 @@ static void append_log_message(std::stringstream* log_messages, const std::strin
|
||||||
*log_messages << message << std::endl;
|
*log_messages << message << std::endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool patch_engine::load(patch_map& patches_map, const std::string& path, bool importing, std::stringstream* log_messages)
|
bool patch_engine::load(patch_map& patches_map, const std::string& path, std::string content, bool importing, std::stringstream* log_messages)
|
||||||
{
|
{
|
||||||
// Load patch file
|
if (content.empty())
|
||||||
fs::file file{ path };
|
|
||||||
|
|
||||||
if (!file)
|
|
||||||
{
|
{
|
||||||
// Do nothing
|
// Load patch file
|
||||||
return true;
|
fs::file file{path};
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
content = file.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpret yaml nodes
|
// Interpret yaml nodes
|
||||||
auto [root, error] = yaml_load(file.to_string());
|
auto [root, error] = yaml_load(content);
|
||||||
|
|
||||||
if (!error.empty() || !root)
|
if (!error.empty() || !root)
|
||||||
{
|
{
|
||||||
|
@ -1059,7 +1064,7 @@ bool patch_engine::import_patches(const patch_engine::patch_map& patches, const
|
||||||
{
|
{
|
||||||
patch_engine::patch_map existing_patches;
|
patch_engine::patch_map existing_patches;
|
||||||
|
|
||||||
if (load(existing_patches, path, true, log_messages))
|
if (load(existing_patches, path, "", true, log_messages))
|
||||||
{
|
{
|
||||||
append_patches(existing_patches, patches, count, total, log_messages);
|
append_patches(existing_patches, patches, count, total, log_messages);
|
||||||
return count == 0 || save_patches(existing_patches, path, log_messages);
|
return count == 0 || save_patches(existing_patches, path, log_messages);
|
||||||
|
|
|
@ -99,7 +99,7 @@ public:
|
||||||
static std::string get_imported_patch_path();
|
static std::string get_imported_patch_path();
|
||||||
|
|
||||||
// Load from file and append to specified patches map
|
// Load from file and append to specified patches map
|
||||||
static bool load(patch_map& patches, const std::string& path, bool importing = false, std::stringstream* log_messages = nullptr);
|
static bool load(patch_map& patches, const std::string& path, std::string content = "", bool importing = false, std::stringstream* log_messages = nullptr);
|
||||||
|
|
||||||
// Read and add a patch node to the patch info
|
// Read and add a patch node to the patch info
|
||||||
static bool read_patch_node(patch_info& info, YAML::Node node, const YAML::Node& root, std::stringstream* log_messages = nullptr);
|
static bool read_patch_node(patch_info& info, YAML::Node node, const YAML::Node& root, std::stringstream* log_messages = nullptr);
|
||||||
|
|
|
@ -15,10 +15,9 @@ size_t curl_write_cb_compat(char* ptr, size_t /*size*/, size_t nmemb, void* user
|
||||||
return download->update_buffer(ptr, nmemb);
|
return download->update_buffer(ptr, nmemb);
|
||||||
}
|
}
|
||||||
|
|
||||||
downloader::downloader(const std::string& thread_name, QWidget* parent)
|
downloader::downloader(QWidget* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_parent(parent)
|
, m_parent(parent)
|
||||||
, m_thread_name(thread_name)
|
|
||||||
{
|
{
|
||||||
m_curl = new curl_handle(this);
|
m_curl = new curl_handle(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class downloader : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
downloader(const std::string& thread_name, QWidget* parent = nullptr);
|
downloader(QWidget* parent = nullptr);
|
||||||
|
|
||||||
void start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title = "", bool keep_progress_dialog_open = false, int expected_size = -1);
|
void start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title = "", bool keep_progress_dialog_open = false, int expected_size = -1);
|
||||||
size_t update_buffer(char* data, size_t size);
|
size_t update_buffer(char* data, size_t size);
|
||||||
|
@ -32,7 +32,6 @@ Q_SIGNALS:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* m_parent = nullptr;
|
QWidget* m_parent = nullptr;
|
||||||
std::string m_thread_name;
|
|
||||||
|
|
||||||
curl_handle* m_curl = nullptr;
|
curl_handle* m_curl = nullptr;
|
||||||
QByteArray m_curl_buf;
|
QByteArray m_curl_buf;
|
||||||
|
|
|
@ -16,7 +16,7 @@ game_compatibility::game_compatibility(std::shared_ptr<gui_settings> settings, Q
|
||||||
, m_gui_settings(settings)
|
, m_gui_settings(settings)
|
||||||
{
|
{
|
||||||
m_filepath = m_gui_settings->GetSettingsDir() + "/compat_database.dat";
|
m_filepath = m_gui_settings->GetSettingsDir() + "/compat_database.dat";
|
||||||
m_downloader = new downloader("Compat Update", parent);
|
m_downloader = new downloader(parent);
|
||||||
RequestCompatibility();
|
RequestCompatibility();
|
||||||
|
|
||||||
connect(m_downloader, &downloader::signal_download_error, this, &game_compatibility::handle_download_error);
|
connect(m_downloader, &downloader::signal_download_error, this, &game_compatibility::handle_download_error);
|
||||||
|
|
|
@ -8,16 +8,19 @@
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include "ui_patch_manager_dialog.h"
|
#include "ui_patch_manager_dialog.h"
|
||||||
#include "patch_manager_dialog.h"
|
#include "patch_manager_dialog.h"
|
||||||
#include "table_item_delegate.h"
|
#include "table_item_delegate.h"
|
||||||
#include "gui_settings.h"
|
#include "gui_settings.h"
|
||||||
|
#include "downloader.h"
|
||||||
#include "qt_utils.h"
|
#include "qt_utils.h"
|
||||||
#include "Utilities/File.h"
|
#include "Utilities/File.h"
|
||||||
#include "util/logs.hpp"
|
#include "util/logs.hpp"
|
||||||
|
|
||||||
LOG_CHANNEL(patch_log);
|
LOG_CHANNEL(patch_log, "PAT");
|
||||||
|
|
||||||
enum patch_column : int
|
enum patch_column : int
|
||||||
{
|
{
|
||||||
|
@ -68,6 +71,10 @@ patch_manager_dialog::patch_manager_dialog(std::shared_ptr<gui_settings> gui_set
|
||||||
ui->cb_enable_legacy_patches->setChecked(m_legacy_patches_enabled);
|
ui->cb_enable_legacy_patches->setChecked(m_legacy_patches_enabled);
|
||||||
ui->cb_owned_games_only->setChecked(m_show_owned_games_only);
|
ui->cb_owned_games_only->setChecked(m_show_owned_games_only);
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setText(tr("Download latest patches"));
|
||||||
|
|
||||||
|
m_downloader = new downloader(parent);
|
||||||
|
|
||||||
// Create connects
|
// Create connects
|
||||||
connect(ui->patch_filter, &QLineEdit::textChanged, this, &patch_manager_dialog::filter_patches);
|
connect(ui->patch_filter, &QLineEdit::textChanged, this, &patch_manager_dialog::filter_patches);
|
||||||
connect(ui->patch_tree, &QTreeWidget::currentItemChanged, this, &patch_manager_dialog::handle_item_selected);
|
connect(ui->patch_tree, &QTreeWidget::currentItemChanged, this, &patch_manager_dialog::handle_item_selected);
|
||||||
|
@ -87,6 +94,23 @@ patch_manager_dialog::patch_manager_dialog(std::shared_ptr<gui_settings> gui_set
|
||||||
{
|
{
|
||||||
save_config();
|
save_config();
|
||||||
}
|
}
|
||||||
|
else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults))
|
||||||
|
{
|
||||||
|
download_update();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(m_downloader, &downloader::signal_download_error, this, [this](const QString& /*error*/)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Patch downloader"), tr("An error occurred during the download process.\nCheck the log for more information."));
|
||||||
|
});
|
||||||
|
connect(m_downloader, &downloader::signal_download_finished, this, [this](const QByteArray& data)
|
||||||
|
{
|
||||||
|
const bool result_json = handle_json(data);
|
||||||
|
|
||||||
|
if (!result_json)
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Patch downloader"), tr("An error occurred during the download process.\nCheck the log for more information."));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,7 +748,7 @@ void patch_manager_dialog::dropEvent(QDropEvent* event)
|
||||||
patch_engine::patch_map patches;
|
patch_engine::patch_map patches;
|
||||||
std::stringstream log_message;
|
std::stringstream log_message;
|
||||||
|
|
||||||
if (patch_engine::load(patches, path, true, &log_message))
|
if (patch_engine::load(patches, path, "", true, &log_message))
|
||||||
{
|
{
|
||||||
patch_log.success("Successfully validated patch file %s", path);
|
patch_log.success("Successfully validated patch file %s", path);
|
||||||
|
|
||||||
|
@ -805,3 +829,96 @@ void patch_manager_dialog::dragLeaveEvent(QDragLeaveEvent* event)
|
||||||
{
|
{
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void patch_manager_dialog::download_update()
|
||||||
|
{
|
||||||
|
m_downloader->start("https://rpcs3.net/compatibility?patch&api=v1", true, true, tr("Downloading latest patches"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool patch_manager_dialog::handle_json(const QByteArray& data)
|
||||||
|
{
|
||||||
|
const QJsonObject json_data = QJsonDocument::fromJson(data).object();
|
||||||
|
const int return_code = json_data["return_code"].toInt(-255);
|
||||||
|
|
||||||
|
if (return_code < 0)
|
||||||
|
{
|
||||||
|
std::string error_message;
|
||||||
|
switch (return_code)
|
||||||
|
{
|
||||||
|
case -1: error_message = "Hash not found"; break;
|
||||||
|
case -2: error_message = "Server Error - Maintenance Mode"; break;
|
||||||
|
case -255: error_message = "Server Error - Return code not found"; break;
|
||||||
|
default: error_message = "Server Error - Unknown Error"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (return_code != -1)
|
||||||
|
patch_log.error("Patch download error: %s return code: %d", error_message, return_code);
|
||||||
|
else
|
||||||
|
patch_log.warning("Patch download error: %s return code: %d", error_message, return_code);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QJsonValue& version_obj = json_data["version"];
|
||||||
|
|
||||||
|
if (!version_obj.isString())
|
||||||
|
{
|
||||||
|
patch_log.error("JSON doesn't contain version");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const std::string version = version_obj.toString().toStdString();
|
||||||
|
version != patch_engine_version)
|
||||||
|
{
|
||||||
|
patch_log.error("JSON contains wrong version: %s (needed: %s)", version, patch_engine_version);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QJsonValue& patch = json_data["patch"];
|
||||||
|
|
||||||
|
if (!patch.isString() || patch.toString().isEmpty())
|
||||||
|
{
|
||||||
|
patch_log.error("JSON doesn't contain patch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
patch_engine::patch_map patches;
|
||||||
|
std::stringstream log_message;
|
||||||
|
|
||||||
|
const std::string content = patch.toString().toStdString();
|
||||||
|
|
||||||
|
if (patch_engine::load(patches, "From Download", content, true, &log_message))
|
||||||
|
{
|
||||||
|
patch_log.success("Successfully validated downloaded patch file");
|
||||||
|
|
||||||
|
const std::string path = patch_engine::get_patches_path() + "patch.yml";
|
||||||
|
const std::string path_old = path + ".old";
|
||||||
|
|
||||||
|
// Back up current patch file
|
||||||
|
if (!fs::copy_file(path, path_old, true))
|
||||||
|
{
|
||||||
|
patch_log.error("Could not back up current patches to %s", path_old);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite current patch file
|
||||||
|
if (fs::file patch_file = fs::file(path, fs::rewrite))
|
||||||
|
{
|
||||||
|
patch_file.write(content);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
patch_log.error("Could not save new patches to %s", path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
patch_log.error("Errors found in downloaded patch file");
|
||||||
|
QMessageBox::critical(this, tr("Validation failed"), tr("Errors were found in the downloaded patch file.\n\nLog:\n%0").arg(QString::fromStdString(log_message.str())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace Ui
|
||||||
class patch_manager_dialog;
|
class patch_manager_dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class downloader;
|
||||||
class gui_settings;
|
class gui_settings;
|
||||||
|
|
||||||
class patch_manager_dialog : public QDialog
|
class patch_manager_dialog : public QDialog
|
||||||
|
@ -55,6 +56,8 @@ private:
|
||||||
void save_config();
|
void save_config();
|
||||||
void update_patch_info(const gui_patch_info& info);
|
void update_patch_info(const gui_patch_info& info);
|
||||||
bool is_valid_file(const QMimeData& md, QStringList* drop_paths = nullptr);
|
bool is_valid_file(const QMimeData& md, QStringList* drop_paths = nullptr);
|
||||||
|
void download_update();
|
||||||
|
bool handle_json(const QByteArray& data);
|
||||||
|
|
||||||
std::shared_ptr<gui_settings> m_gui_settings;
|
std::shared_ptr<gui_settings> m_gui_settings;
|
||||||
|
|
||||||
|
@ -64,6 +67,8 @@ private:
|
||||||
patch_engine::patch_map m_map;
|
patch_engine::patch_map m_map;
|
||||||
bool m_legacy_patches_enabled = false;
|
bool m_legacy_patches_enabled = false;
|
||||||
|
|
||||||
|
downloader* m_downloader = nullptr;
|
||||||
|
|
||||||
Ui::patch_manager_dialog *ui;
|
Ui::patch_manager_dialog *ui;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -255,7 +255,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
|
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -52,7 +52,7 @@ void update_manager::check_for_updates(bool automatic, bool check_only, QWidget*
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_parent = parent;
|
m_parent = parent;
|
||||||
m_downloader = new downloader("RPCS3 Updater", parent);
|
m_downloader = new downloader(parent);
|
||||||
|
|
||||||
connect(m_downloader, &downloader::signal_download_error, this, [this, automatic](const QString& /*error*/)
|
connect(m_downloader, &downloader::signal_download_error, this, [this, automatic](const QString& /*error*/)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,12 +36,12 @@ std::pair<YAML::Node, std::string> yaml_load(const std::string& from)
|
||||||
{
|
{
|
||||||
result = YAML::Load(from);
|
result = YAML::Load(from);
|
||||||
}
|
}
|
||||||
catch(const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
return{YAML::Node(), std::string("YAML exception: ") + e.what()};
|
return {YAML::Node(), std::string("YAML exception: ") + e.what()};
|
||||||
}
|
}
|
||||||
|
|
||||||
return{result, ""};
|
return {result, ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue