mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-20 22:05:12 +00:00
Replace QNetwork operations with libcurl + wolfssl
This commit is contained in:
parent
132c3e1c1a
commit
b1d8bf754e
17 changed files with 590 additions and 437 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -91,4 +91,6 @@ target_link_libraries(rpcs3_ui
|
|||
3rdparty::hidapi
|
||||
3rdparty::libusb
|
||||
3rdparty::libpng
|
||||
3rdparty::7z)
|
||||
3rdparty::7z
|
||||
3rdparty::wolfssl
|
||||
3rdparty::libcurl)
|
||||
|
|
|
|||
|
|
@ -4,22 +4,56 @@
|
|||
|
||||
#include <QMessageBox>
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkReply>
|
||||
#include <QThread>
|
||||
|
||||
LOG_CHANNEL(compat_log, "Compat");
|
||||
|
||||
constexpr auto qstr = QString::fromStdString;
|
||||
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
|
||||
|
||||
size_t curl_write_cb_compat(char* ptr, size_t /*size*/, size_t nmemb, void* userdata)
|
||||
{
|
||||
game_compatibility* gm_cmp = reinterpret_cast<game_compatibility*>(userdata);
|
||||
return gm_cmp->update_buffer(ptr, nmemb);
|
||||
}
|
||||
|
||||
game_compatibility::game_compatibility(std::shared_ptr<gui_settings> settings) : m_xgui_settings(settings)
|
||||
{
|
||||
m_filepath = m_xgui_settings->GetSettingsDir() + "/compat_database.dat";
|
||||
m_url = "https://rpcs3.net/compatibility?api=v1&export";
|
||||
m_network_request = QNetworkRequest(QUrl(m_url));
|
||||
|
||||
m_curl = curl_easy_init();
|
||||
|
||||
RequestCompatibility();
|
||||
}
|
||||
|
||||
size_t game_compatibility::update_buffer(char* data, size_t size)
|
||||
{
|
||||
if (m_curl_abort)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto old_size = m_curl_buf.size();
|
||||
const auto new_size = old_size + size;
|
||||
m_curl_buf.resize(static_cast<int>(new_size));
|
||||
memcpy(m_curl_buf.data() + old_size, data, size);
|
||||
|
||||
if (m_actual_dwnld_size < 0)
|
||||
{
|
||||
if (curl_easy_getinfo(m_curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &m_actual_dwnld_size) == CURLE_OK && m_actual_dwnld_size > 0)
|
||||
{
|
||||
if (m_progress_dialog)
|
||||
m_progress_dialog->setMaximum(static_cast<int>(m_actual_dwnld_size));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_progress_dialog)
|
||||
m_progress_dialog->setValue(static_cast<int>(new_size));
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool game_compatibility::ReadJSON(const QJsonObject& json_data, bool after_download)
|
||||
{
|
||||
int return_code = json_data["return_code"].toInt();
|
||||
|
|
@ -118,112 +152,44 @@ void game_compatibility::RequestCompatibility(bool online)
|
|||
return;
|
||||
}
|
||||
|
||||
if (QSslSocket::supportsSsl() == false)
|
||||
{
|
||||
compat_log.error("Can not retrieve the online database! Please make sure your system supports SSL. Visit our quickstart guide for more information: https://rpcs3.net/quickstart");
|
||||
const QString message = tr("Can not retrieve the online database!<br>Please make sure your system supports SSL.<br>Visit our <a href='https://rpcs3.net/quickstart'>quickstart guide</a> for more information.");
|
||||
QMessageBox box(QMessageBox::Icon::Warning, tr("Warning!"), message, QMessageBox::StandardButton::Ok, nullptr);
|
||||
box.setTextFormat(Qt::RichText);
|
||||
box.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
compat_log.notice("SSL supported! Beginning compatibility database download from: %s", sstr(m_url));
|
||||
|
||||
// Send request and wait for response
|
||||
m_network_access_manager.reset(new QNetworkAccessManager());
|
||||
QNetworkReply* network_reply = m_network_access_manager->get(m_network_request);
|
||||
compat_log.notice("Beginning compatibility database download from: %s", m_url);
|
||||
|
||||
// Show Progress
|
||||
m_progress_dialog = new progress_dialog(tr("Downloading Database"), tr(".Please wait."), tr("Abort"), 0, 100, true);
|
||||
m_progress_dialog = new progress_dialog(tr("Downloading Database"), tr("Please wait ..."), tr("Abort"), 0, 100, true);
|
||||
m_progress_dialog->show();
|
||||
|
||||
// Animate progress dialog a bit more
|
||||
m_progress_timer.reset(new QTimer(this));
|
||||
connect(m_progress_timer.get(), &QTimer::timeout, [&]()
|
||||
{
|
||||
switch (++m_timer_count % 3)
|
||||
{
|
||||
case 0:
|
||||
m_timer_count = 0;
|
||||
m_progress_dialog->setLabelText(tr(".Please wait."));
|
||||
break;
|
||||
case 1:
|
||||
m_progress_dialog->setLabelText(tr("..Please wait.."));
|
||||
break;
|
||||
default:
|
||||
m_progress_dialog->setLabelText(tr("...Please wait..."));
|
||||
break;
|
||||
}
|
||||
});
|
||||
m_progress_timer->start(500);
|
||||
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, curl_write_cb_compat);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this);
|
||||
curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
|
||||
m_curl_buf.clear();
|
||||
m_curl_abort = false;
|
||||
|
||||
// Handle abort
|
||||
connect(m_progress_dialog, &QProgressDialog::canceled, network_reply, &QNetworkReply::abort);
|
||||
connect(m_progress_dialog, &QProgressDialog::canceled, [this] { m_curl_abort = true; });
|
||||
connect(m_progress_dialog, &QProgressDialog::finished, m_progress_dialog, &QProgressDialog::deleteLater);
|
||||
|
||||
// Handle progress
|
||||
connect(network_reply, &QNetworkReply::downloadProgress, [&](qint64 bytesReceived, qint64 bytesTotal)
|
||||
QThread::create([&]
|
||||
{
|
||||
m_progress_dialog->setMaximum(bytesTotal);
|
||||
m_progress_dialog->setValue(bytesReceived);
|
||||
});
|
||||
const auto result = curl_easy_perform(m_curl);
|
||||
|
||||
// Handle network error
|
||||
connect(network_reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), [=, this](QNetworkReply::NetworkError error)
|
||||
{
|
||||
if (error == QNetworkReply::NoError)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (error != QNetworkReply::OperationCanceledError)
|
||||
{
|
||||
// We failed to retrieve a new database, therefore refresh gamelist to old state
|
||||
const QString error = network_reply->errorString();
|
||||
Q_EMIT DownloadError(error);
|
||||
compat_log.error("Network Error - %s", sstr(error));
|
||||
}
|
||||
|
||||
// Clean up Progress Dialog
|
||||
if (m_progress_dialog)
|
||||
{
|
||||
m_progress_dialog->close();
|
||||
}
|
||||
if (m_progress_timer)
|
||||
{
|
||||
m_progress_timer->stop();
|
||||
m_progress_dialog = nullptr;
|
||||
}
|
||||
|
||||
network_reply->deleteLater();
|
||||
});
|
||||
|
||||
// Handle response according to its contents
|
||||
connect(network_reply, &QNetworkReply::finished, [=, this]()
|
||||
{
|
||||
if (network_reply->error() != QNetworkReply::NoError)
|
||||
if (result != CURLE_OK)
|
||||
{
|
||||
Q_EMIT DownloadError(qstr("Curl error: ") + qstr(curl_easy_strerror(result)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up Progress Dialog
|
||||
if (m_progress_dialog)
|
||||
{
|
||||
m_progress_dialog->close();
|
||||
}
|
||||
if (m_progress_timer)
|
||||
{
|
||||
m_progress_timer->stop();
|
||||
}
|
||||
|
||||
compat_log.notice("Database download finished");
|
||||
|
||||
// Read data from network reply
|
||||
QByteArray data = network_reply->readAll();
|
||||
network_reply->deleteLater();
|
||||
|
||||
// Create new map from database and write database to file if database was valid
|
||||
if (ReadJSON(QJsonDocument::fromJson(data).object(), online))
|
||||
if (ReadJSON(QJsonDocument::fromJson(m_curl_buf).object(), online))
|
||||
{
|
||||
// We have a new database in map, therefore refresh gamelist to new state
|
||||
Q_EMIT DownloadFinished();
|
||||
|
|
@ -242,12 +208,12 @@ void game_compatibility::RequestCompatibility(bool online)
|
|||
return;
|
||||
}
|
||||
|
||||
file.write(data);
|
||||
file.write(m_curl_buf);
|
||||
file.close();
|
||||
|
||||
compat_log.success("Write database to file: %s", sstr(m_filepath));
|
||||
compat_log.success("Wrote database to file: %s", sstr(m_filepath));
|
||||
}
|
||||
});
|
||||
})->start();
|
||||
|
||||
// We want to retrieve a new database, therefore refresh gamelist and indicate that
|
||||
Q_EMIT DownloadStarted();
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
#include <QPainter>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QTimer>
|
||||
|
||||
#define NOMINMAX
|
||||
#define CURL_STATICLIB
|
||||
#include <curl/curl.h>
|
||||
|
||||
class gui_settings;
|
||||
class progress_dialog;
|
||||
|
|
@ -39,12 +40,13 @@ private:
|
|||
};
|
||||
int m_timer_count = 0;
|
||||
QString m_filepath;
|
||||
QString m_url;
|
||||
QNetworkRequest m_network_request;
|
||||
std::string m_url;
|
||||
std::atomic<bool> m_curl_abort = false;
|
||||
double m_actual_dwnld_size = -1.0;
|
||||
CURL *m_curl = nullptr;
|
||||
QByteArray m_curl_buf;
|
||||
progress_dialog* m_progress_dialog = nullptr;
|
||||
std::shared_ptr<gui_settings> m_xgui_settings;
|
||||
std::unique_ptr<QTimer> m_progress_timer;
|
||||
std::unique_ptr<QNetworkAccessManager> m_network_access_manager;
|
||||
std::map<std::string, compat_status> m_compat_database;
|
||||
|
||||
/** Creates new map from the database */
|
||||
|
|
@ -63,6 +65,8 @@ public:
|
|||
/** Returns the data for the requested status */
|
||||
compat_status GetStatusData(const QString& status);
|
||||
|
||||
size_t update_buffer(char* data, size_t size);
|
||||
|
||||
Q_SIGNALS:
|
||||
void DownloadStarted();
|
||||
void DownloadFinished();
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <QScreen>
|
||||
#include <QFontDatabase>
|
||||
#include <QLibraryInfo>
|
||||
#include <QDirIterator>
|
||||
|
||||
#include <clocale>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@
|
|||
#include <thread>
|
||||
|
||||
#include <QScreen>
|
||||
#include <QDirIterator>
|
||||
#include <QMimeData>
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "rpcs3_version.h"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <QActionGroup>
|
||||
#include <QMainWindow>
|
||||
#include <QIcon>
|
||||
#include <QMimeData>
|
||||
|
||||
#include "update_manager.h"
|
||||
#include "settings.h"
|
||||
|
|
|
|||
|
|
@ -7,10 +7,15 @@
|
|||
#include "Emu/System.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QThread>
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#include <CpuArch.h>
|
||||
#include <7z.h>
|
||||
|
|
@ -29,9 +34,40 @@
|
|||
|
||||
LOG_CHANNEL(update_log, "UPDATER");
|
||||
|
||||
size_t curl_write_cb(char* ptr, size_t /*size*/, size_t nmemb, void* userdata)
|
||||
{
|
||||
update_manager* upd_mgr = reinterpret_cast<update_manager*>(userdata);
|
||||
return upd_mgr->update_buffer(ptr, nmemb);
|
||||
}
|
||||
|
||||
update_manager::update_manager()
|
||||
{
|
||||
m_manager.setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
m_curl = curl_easy_init();
|
||||
|
||||
#ifdef _WIN32
|
||||
// This shouldn't be needed on linux
|
||||
curl_easy_setopt(m_curl, CURLOPT_CAINFO, "cacert.pem");
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t update_manager::update_buffer(char* data, size_t size)
|
||||
{
|
||||
if (m_curl_abort)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto old_size = m_curl_buf.size();
|
||||
const auto new_size = old_size + size;
|
||||
m_curl_buf.resize(static_cast<int>(new_size));
|
||||
memcpy(m_curl_buf.data() + old_size, data, size);
|
||||
|
||||
if (m_progress_dialog && m_update_dialog)
|
||||
{
|
||||
m_progress_dialog->setValue(static_cast<int>(new_size));
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void update_manager::check_for_updates(bool automatic, QWidget* parent)
|
||||
|
|
@ -44,91 +80,54 @@ void update_manager::check_for_updates(bool automatic, QWidget* parent)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (QSslSocket::supportsSsl() == false)
|
||||
{
|
||||
update_log.error("Unable to update RPCS3! Please make sure your system supports SSL. Visit our quickstart guide for more information: https://rpcs3.net/quickstart");
|
||||
if (!automatic)
|
||||
{
|
||||
const QString message = tr("Unable to update RPCS3!<br>Please make sure your system supports SSL.<br>Visit our <a href='https://rpcs3.net/quickstart'>Quickstart</a> guide for more information.");
|
||||
QMessageBox box(QMessageBox::Icon::Warning, tr("Auto-updater"), message, QMessageBox::StandardButton::Ok, parent);
|
||||
box.setTextFormat(Qt::RichText);
|
||||
box.exec();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_parent = parent;
|
||||
|
||||
const std::string request_url = m_update_url + rpcs3::get_commit_and_hash().second;
|
||||
QNetworkReply* reply_json = m_manager.get(QNetworkRequest(QUrl(QString::fromStdString(request_url))));
|
||||
m_parent = parent;
|
||||
m_curl_abort = false;
|
||||
m_update_dialog = false;
|
||||
m_curl_buf.clear();
|
||||
|
||||
m_progress_dialog = new progress_dialog(tr("Checking For Updates"), tr("Please wait..."), tr("Abort"), 0, 100, true, parent);
|
||||
m_progress_dialog->setAutoClose(false);
|
||||
m_progress_dialog->setAutoReset(false);
|
||||
m_progress_dialog->show();
|
||||
|
||||
connect(m_progress_dialog, &QProgressDialog::canceled, reply_json, &QNetworkReply::abort);
|
||||
connect(m_progress_dialog, &QProgressDialog::canceled, [&]() { m_curl_abort = true; });
|
||||
connect(m_progress_dialog, &QProgressDialog::finished, m_progress_dialog, &QProgressDialog::deleteLater);
|
||||
|
||||
// clang-format off
|
||||
connect(reply_json, &QNetworkReply::downloadProgress, [&](qint64 bytesReceived, qint64 bytesTotal)
|
||||
const std::string request_url = m_update_url + rpcs3::get_commit_and_hash().second;
|
||||
curl_easy_setopt(m_curl, CURLOPT_URL, request_url.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, curl_write_cb);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this);
|
||||
|
||||
bool result_json = false;
|
||||
|
||||
if (const auto curl_result = curl_easy_perform(m_curl); curl_result != CURLE_OK)
|
||||
{
|
||||
m_progress_dialog->setMaximum(bytesTotal);
|
||||
m_progress_dialog->setValue(bytesReceived);
|
||||
});
|
||||
|
||||
connect(reply_json, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &update_manager::handle_error);
|
||||
connect(reply_json, &QNetworkReply::finished, [=, this]()
|
||||
update_log.error("Curl error(query): %s", curl_easy_strerror(curl_result));
|
||||
}
|
||||
else
|
||||
{
|
||||
handle_reply(reply_json, &update_manager::handle_json, automatic, "Retrieved JSON Info");
|
||||
});
|
||||
// clang-format on
|
||||
}
|
||||
result_json = handle_json(automatic);
|
||||
}
|
||||
|
||||
void update_manager::handle_error(QNetworkReply::NetworkError error)
|
||||
{
|
||||
if (error != QNetworkReply::NoError)
|
||||
if (!result_json && !m_curl_abort)
|
||||
{
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (!reply)
|
||||
return;
|
||||
|
||||
m_progress_dialog->close();
|
||||
|
||||
reply->deleteLater();
|
||||
if (error != QNetworkReply::OperationCanceledError)
|
||||
if (!automatic)
|
||||
{
|
||||
const QString err_str = reply->errorString();
|
||||
update_log.error("Network Error: %s", err_str.toStdString());
|
||||
QMessageBox::warning(m_parent, tr("Auto-updater"), tr("An error occurred during the auto-updating process.\nCheck the log for more information."));
|
||||
}
|
||||
|
||||
if (m_progress_dialog)
|
||||
{
|
||||
m_progress_dialog->close();
|
||||
m_progress_dialog = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool update_manager::handle_reply(QNetworkReply* reply, const std::function<bool(update_manager& man, const QByteArray&, bool)>& func, bool automatic, const std::string& message)
|
||||
bool update_manager::handle_json(bool automatic)
|
||||
{
|
||||
if (auto error = reply->error(); error != QNetworkReply::NoError)
|
||||
return false;
|
||||
|
||||
// Read data from network reply
|
||||
const QByteArray data = reply->readAll();
|
||||
reply->deleteLater();
|
||||
|
||||
update_log.notice("%s", message);
|
||||
if (!func(*this, data, automatic))
|
||||
{
|
||||
m_progress_dialog->close();
|
||||
|
||||
if (!automatic)
|
||||
QMessageBox::warning(m_parent, tr("Auto-updater"), tr("An error occurred during the auto-updating process.\nCheck the log for more information."));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_manager::handle_json(const QByteArray& data, bool automatic)
|
||||
{
|
||||
const QJsonObject json_data = QJsonDocument::fromJson(data).object();
|
||||
int return_code = json_data["return_code"].toInt(-255);
|
||||
const QJsonObject json_data = QJsonDocument::fromJson(m_curl_buf).object();
|
||||
const int return_code = json_data["return_code"].toInt(-255);
|
||||
|
||||
bool hash_found = true;
|
||||
|
||||
|
|
@ -218,7 +217,7 @@ bool update_manager::handle_json(const QByteArray& data, bool automatic)
|
|||
{
|
||||
update_log.notice("Converting string: %s", str);
|
||||
std::istringstream input(str);
|
||||
input.imbue(std::locale(setlocale(LC_ALL, "C")));
|
||||
input.imbue(std::locale(setlocale(LC_TIME, "C")));
|
||||
input >> std::get_time(tm, format.c_str());
|
||||
|
||||
return !input.fail();
|
||||
|
|
@ -232,7 +231,7 @@ bool update_manager::handle_json(const QByteArray& data, bool automatic)
|
|||
s64 u_timediff = static_cast<s64>(std::difftime(lts_time, cur_time));
|
||||
update_log.notice("Current: %lld, latest: %lld, difference: %lld", static_cast<s64>(cur_time), static_cast<s64>(lts_time), u_timediff);
|
||||
|
||||
timediff = tr("Your version is %1 day(s), %2 hour(s) and %3 minute(s) old.").arg(u_timediff / (60 * 60 * 24)).arg((u_timediff / (60 * 60)) % 24).arg((u_timediff / 60) % 60);
|
||||
timediff = tr("Your version is %1 day(s), %2 hour(s) and %3 minute(s) old.").arg(u_timediff / (60 * 60 * 24)).arg((u_timediff / (60 * 60)) % 24).arg((u_timediff / 60) % 60);
|
||||
}
|
||||
|
||||
const QString to_show = tr("A new version of RPCS3 is available!\n\nCurrent version: %1\nLatest version: %2\n%3\n\nDo you want to update?")
|
||||
|
|
@ -252,33 +251,52 @@ bool update_manager::handle_json(const QByteArray& data, bool automatic)
|
|||
m_progress_dialog->setWindowTitle(tr("Downloading Update"));
|
||||
|
||||
// Download RPCS3
|
||||
m_progress_dialog->setMaximum(m_expected_size);
|
||||
m_progress_dialog->setValue(0);
|
||||
QNetworkReply* reply_rpcs3 = m_manager.get(QNetworkRequest(QUrl(latest[os]["download"].toString())));
|
||||
m_update_dialog = true;
|
||||
|
||||
connect(m_progress_dialog, &QProgressDialog::canceled, reply_rpcs3, &QNetworkReply::abort);
|
||||
const std::string request_url = latest[os]["download"].toString().toStdString();
|
||||
curl_easy_setopt(m_curl, CURLOPT_URL, request_url.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
|
||||
// clang-format off
|
||||
connect(reply_rpcs3, &QNetworkReply::downloadProgress, [&](qint64 bytesReceived, qint64 bytesTotal)
|
||||
m_curl_buf.clear();
|
||||
|
||||
QThread::create([this, automatic]
|
||||
{
|
||||
m_progress_dialog->setMaximum(bytesTotal);
|
||||
m_progress_dialog->setValue(bytesReceived);
|
||||
});
|
||||
bool result_rpcs3 = false;
|
||||
|
||||
connect(reply_rpcs3, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &update_manager::handle_error);
|
||||
connect(reply_rpcs3, &QNetworkReply::finished, [=, this]()
|
||||
{
|
||||
handle_reply(reply_rpcs3, &update_manager::handle_rpcs3, automatic, "Retrieved RPCS3");
|
||||
});
|
||||
// clang-format on
|
||||
if (const auto curl_result = curl_easy_perform(m_curl); curl_result != CURLE_OK)
|
||||
{
|
||||
update_log.error("Curl error(download): %s", curl_easy_strerror(curl_result));
|
||||
}
|
||||
else
|
||||
{
|
||||
result_rpcs3 = handle_rpcs3();
|
||||
}
|
||||
|
||||
if (!result_rpcs3 && !m_curl_abort)
|
||||
{
|
||||
if (!automatic)
|
||||
{
|
||||
QMessageBox::warning(m_parent, tr("Auto-updater"), tr("An error occurred during the auto-updating process.\nCheck the log for more information."));
|
||||
}
|
||||
|
||||
if (m_progress_dialog)
|
||||
{
|
||||
m_progress_dialog->close();
|
||||
m_progress_dialog = nullptr;
|
||||
}
|
||||
}
|
||||
})->start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_manager::handle_rpcs3(const QByteArray& rpcs3_data, bool /*automatic*/)
|
||||
bool update_manager::handle_rpcs3()
|
||||
{
|
||||
if (m_expected_size != rpcs3_data.size() + 0u)
|
||||
if (m_expected_size != m_curl_buf.size() + 0u)
|
||||
{
|
||||
update_log.error("Download size mismatch: %d expected: %d", rpcs3_data.size(), m_expected_size);
|
||||
update_log.error("Download size mismatch: %d expected: %d", m_curl_buf.size(), m_expected_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +304,7 @@ bool update_manager::handle_rpcs3(const QByteArray& rpcs3_data, bool /*automatic
|
|||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts_ret(&ctx, 0);
|
||||
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(rpcs3_data.data()), rpcs3_data.size());
|
||||
mbedtls_sha256_update_ret(&ctx, reinterpret_cast<const unsigned char*>(m_curl_buf.data()), m_curl_buf.size());
|
||||
mbedtls_sha256_finish_ret(&ctx, res_hash);
|
||||
|
||||
std::string res_hash_string("0000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
|
@ -348,7 +366,7 @@ bool update_manager::handle_rpcs3(const QByteArray& rpcs3_data, bool /*automatic
|
|||
update_log.error("Failed to create new AppImage file: %s", replace_path);
|
||||
return false;
|
||||
}
|
||||
if (new_appimage.write(rpcs3_data.data(), rpcs3_data.size()) != rpcs3_data.size() + 0u)
|
||||
if (new_appimage.write(m_curl_buf.data(), m_curl_buf.size()) != m_curl_buf.size() + 0u)
|
||||
{
|
||||
update_log.error("Failed to write new AppImage file: %s", replace_path);
|
||||
return false;
|
||||
|
|
@ -378,7 +396,7 @@ bool update_manager::handle_rpcs3(const QByteArray& rpcs3_data, bool /*automatic
|
|||
update_log.error("Failed to create temporary file: %s", tmpfile_path);
|
||||
return false;
|
||||
}
|
||||
if (tmpfile.write(rpcs3_data.data(), rpcs3_data.size()) != rpcs3_data.size())
|
||||
if (tmpfile.write(m_curl_buf.data(), m_curl_buf.size()) != m_curl_buf.size())
|
||||
{
|
||||
update_log.error("Failed to write temporary file: %s", tmpfile_path);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,36 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <QtNetwork>
|
||||
#define NOMINMAX
|
||||
#define CURL_STATICLIB
|
||||
#include <curl/curl.h>
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
|
||||
class progress_dialog;
|
||||
|
||||
class update_manager : public QObject
|
||||
class update_manager final : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
const std::string m_update_url = "https://update.rpcs3.net/?api=v1&c=";
|
||||
const std::string m_tmp_folder = "/rpcs3_old/";
|
||||
|
||||
private:
|
||||
std::atomic<bool> m_update_dialog = false;
|
||||
progress_dialog* m_progress_dialog = nullptr;
|
||||
QWidget* m_parent = nullptr;
|
||||
|
||||
QNetworkAccessManager m_manager;
|
||||
CURL *m_curl = nullptr;
|
||||
QByteArray m_curl_buf;
|
||||
std::atomic<bool> m_curl_abort = false;
|
||||
|
||||
std::string m_expected_hash;
|
||||
u64 m_expected_size = 0;
|
||||
|
||||
private:
|
||||
bool handle_reply(QNetworkReply* reply, const std::function<bool(update_manager& man, const QByteArray&, bool)>& func, bool automatic, const std::string& message);
|
||||
bool handle_json(const QByteArray& json_data, bool automatic);
|
||||
bool handle_rpcs3(const QByteArray& rpcs3_data, bool automatic);
|
||||
bool handle_json(bool automatic);
|
||||
bool handle_rpcs3();
|
||||
|
||||
public:
|
||||
update_manager();
|
||||
void check_for_updates(bool automatic, QWidget* parent = nullptr);
|
||||
|
||||
private Q_SLOTS:
|
||||
void handle_error(QNetworkReply::NetworkError error);
|
||||
size_t update_buffer(char *data, size_t size);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue