patch_manager: add download button

This commit is contained in:
Megamouse 2020-09-06 11:47:45 +02:00
parent 1e4655aef6
commit 46e8b4f561
10 changed files with 147 additions and 22 deletions

View File

@ -98,19 +98,24 @@ static void append_log_message(std::stringstream* log_messages, const std::strin
*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
fs::file file{ path };
if (!file)
if (content.empty())
{
// Do nothing
return true;
// Load patch file
fs::file file{path};
if (!file)
{
// Do nothing
return true;
}
content = file.to_string();
}
// Interpret yaml nodes
auto [root, error] = yaml_load(file.to_string());
auto [root, error] = yaml_load(content);
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;
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);
return count == 0 || save_patches(existing_patches, path, log_messages);

View File

@ -99,7 +99,7 @@ public:
static std::string get_imported_patch_path();
// 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
static bool read_patch_node(patch_info& info, YAML::Node node, const YAML::Node& root, std::stringstream* log_messages = nullptr);

View File

@ -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);
}
downloader::downloader(const std::string& thread_name, QWidget* parent)
downloader::downloader(QWidget* parent)
: QObject(parent)
, m_parent(parent)
, m_thread_name(thread_name)
{
m_curl = new curl_handle(this);
}

View File

@ -12,7 +12,7 @@ class downloader : public QObject
Q_OBJECT
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);
size_t update_buffer(char* data, size_t size);
@ -32,7 +32,6 @@ Q_SIGNALS:
private:
QWidget* m_parent = nullptr;
std::string m_thread_name;
curl_handle* m_curl = nullptr;
QByteArray m_curl_buf;

View File

@ -16,7 +16,7 @@ game_compatibility::game_compatibility(std::shared_ptr<gui_settings> settings, Q
, m_gui_settings(settings)
{
m_filepath = m_gui_settings->GetSettingsDir() + "/compat_database.dat";
m_downloader = new downloader("Compat Update", parent);
m_downloader = new downloader(parent);
RequestCompatibility();
connect(m_downloader, &downloader::signal_download_error, this, &game_compatibility::handle_download_error);

View File

@ -8,16 +8,19 @@
#include <QCheckBox>
#include <QMessageBox>
#include <QTimer>
#include <QJsonObject>
#include <QJsonDocument>
#include "ui_patch_manager_dialog.h"
#include "patch_manager_dialog.h"
#include "table_item_delegate.h"
#include "gui_settings.h"
#include "downloader.h"
#include "qt_utils.h"
#include "Utilities/File.h"
#include "util/logs.hpp"
LOG_CHANNEL(patch_log);
LOG_CHANNEL(patch_log, "PAT");
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_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
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);
@ -87,6 +94,23 @@ patch_manager_dialog::patch_manager_dialog(std::shared_ptr<gui_settings> gui_set
{
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;
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);
@ -805,3 +829,96 @@ void patch_manager_dialog::dragLeaveEvent(QDragLeaveEvent* event)
{
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;
}

View File

@ -12,6 +12,7 @@ namespace Ui
class patch_manager_dialog;
}
class downloader;
class gui_settings;
class patch_manager_dialog : public QDialog
@ -55,6 +56,8 @@ private:
void save_config();
void update_patch_info(const gui_patch_info& info);
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;
@ -64,6 +67,8 @@ private:
patch_engine::patch_map m_map;
bool m_legacy_patches_enabled = false;
downloader* m_downloader = nullptr;
Ui::patch_manager_dialog *ui;
protected:

View File

@ -255,7 +255,7 @@
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults|QDialogButtonBox::Save</set>
</property>
</widget>
</item>

View File

@ -52,7 +52,7 @@ void update_manager::check_for_updates(bool automatic, bool check_only, QWidget*
#endif
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*/)
{

View File

@ -36,12 +36,12 @@ std::pair<YAML::Node, std::string> yaml_load(const std::string& 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>