mirror of
https://github.com/UltimMC/Launcher.git
synced 2025-12-23 20:12:34 +00:00
Merge branch 'MultiMC:develop' into develop
This commit is contained in:
1
BUILD.md
1
BUILD.md
@@ -15,6 +15,7 @@ MultiMC is a portable application and is not supposed to be installed into any s
|
||||
That would be anything outside your home folder. Before running `make install`, make sure
|
||||
you set the install path to something you have write access to. Never build this under
|
||||
an administrator/root level account. Don't use `sudo`. It won't work and it's not supposed to work.
|
||||
Also note that this guide is for development purposes only. No support is given for building your own fork or special build for any reason whatsoever.
|
||||
|
||||
|
||||
# Getting the source
|
||||
|
||||
@@ -653,6 +653,7 @@ SET(MULTIMC_SOURCES
|
||||
pages/instance/VersionPage.h
|
||||
pages/instance/TexturePackPage.h
|
||||
pages/instance/ResourcePackPage.h
|
||||
pages/instance/ShaderPackPage.h
|
||||
pages/instance/ModFolderPage.cpp
|
||||
pages/instance/ModFolderPage.h
|
||||
pages/instance/NotesPage.cpp
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "pages/instance/ModFolderPage.h"
|
||||
#include "pages/instance/ResourcePackPage.h"
|
||||
#include "pages/instance/TexturePackPage.h"
|
||||
#include "pages/instance/ShaderPackPage.h"
|
||||
#include "pages/instance/NotesPage.h"
|
||||
#include "pages/instance/ScreenshotsPage.h"
|
||||
#include "pages/instance/InstanceSettingsPage.h"
|
||||
@@ -44,6 +45,7 @@ public:
|
||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
|
||||
values.append(new ResourcePackPage(onesix.get()));
|
||||
values.append(new TexturePackPage(onesix.get()));
|
||||
values.append(new ShaderPackPage(onesix.get()));
|
||||
values.append(new NotesPage(onesix.get()));
|
||||
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
||||
values.append(new ServersPage(onesix));
|
||||
|
||||
@@ -223,6 +223,11 @@ QString MinecraftInstance::texturePacksDir() const
|
||||
return FS::PathCombine(gameRoot(), "texturepacks");
|
||||
}
|
||||
|
||||
QString MinecraftInstance::shaderPacksDir() const
|
||||
{
|
||||
return FS::PathCombine(gameRoot(), "shaderpacks");
|
||||
}
|
||||
|
||||
QString MinecraftInstance::instanceConfigFolder() const
|
||||
{
|
||||
return FS::PathCombine(gameRoot(), "config");
|
||||
@@ -1027,6 +1032,17 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::texturePackList() const
|
||||
return m_texture_pack_list;
|
||||
}
|
||||
|
||||
std::shared_ptr<ModFolderModel> MinecraftInstance::shaderPackList() const
|
||||
{
|
||||
if (!m_shader_pack_list)
|
||||
{
|
||||
m_shader_pack_list.reset(new ResourcePackFolderModel(shaderPacksDir()));
|
||||
m_shader_pack_list->disableInteraction(isRunning());
|
||||
connect(this, &BaseInstance::runningStatusChanged, m_shader_pack_list.get(), &ModFolderModel::disableInteraction);
|
||||
}
|
||||
return m_shader_pack_list;
|
||||
}
|
||||
|
||||
std::shared_ptr<WorldList> MinecraftInstance::worldList() const
|
||||
{
|
||||
if (!m_world_list)
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
QString jarModsDir() const;
|
||||
QString resourcePacksDir() const;
|
||||
QString texturePacksDir() const;
|
||||
QString shaderPacksDir() const;
|
||||
QString loaderModsDir() const;
|
||||
QString coreModsDir() const;
|
||||
QString modsCacheLocation() const;
|
||||
@@ -72,6 +73,7 @@ public:
|
||||
std::shared_ptr<ModFolderModel> coreModList() const;
|
||||
std::shared_ptr<ModFolderModel> resourcePackList() const;
|
||||
std::shared_ptr<ModFolderModel> texturePackList() const;
|
||||
std::shared_ptr<ModFolderModel> shaderPackList() const;
|
||||
std::shared_ptr<WorldList> worldList() const;
|
||||
std::shared_ptr<GameOptions> gameOptionsModel() const;
|
||||
|
||||
@@ -125,6 +127,7 @@ protected: // data
|
||||
mutable std::shared_ptr<ModFolderModel> m_loader_mod_list;
|
||||
mutable std::shared_ptr<ModFolderModel> m_core_mod_list;
|
||||
mutable std::shared_ptr<ModFolderModel> m_resource_pack_list;
|
||||
mutable std::shared_ptr<ModFolderModel> m_shader_pack_list;
|
||||
mutable std::shared_ptr<ModFolderModel> m_texture_pack_list;
|
||||
mutable std::shared_ptr<WorldList> m_world_list;
|
||||
mutable std::shared_ptr<GameOptions> m_game_options;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include "Env.h"
|
||||
|
||||
using OAuth2 = Katabasis::OAuth2;
|
||||
using Requestor = AuthRequest;
|
||||
using Activity = Katabasis::Activity;
|
||||
|
||||
AuthContext::AuthContext(AccountData * data, QObject *parent) :
|
||||
@@ -164,8 +163,8 @@ void AuthContext::doUserAuth() {
|
||||
QNetworkRequest request = QNetworkRequest(QUrl("https://user.auth.xboxlive.com/user/authenticate"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Accept", "application/json");
|
||||
auto *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onUserAuthDone);
|
||||
auto *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onUserAuthDone);
|
||||
requestor->post(request, xbox_auth_data.toUtf8());
|
||||
qDebug() << "First layer of XBox auth ... commencing.";
|
||||
}
|
||||
@@ -358,8 +357,8 @@ void AuthContext::doSTSAuthMinecraft() {
|
||||
QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Accept", "application/json");
|
||||
Requestor *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onSTSAuthMinecraftDone);
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onSTSAuthMinecraftDone);
|
||||
requestor->post(request, xbox_auth_data.toUtf8());
|
||||
qDebug() << "Getting Minecraft services STS token...";
|
||||
}
|
||||
@@ -428,8 +427,8 @@ void AuthContext::doMinecraftAuth() {
|
||||
QNetworkRequest request = QNetworkRequest(QUrl("https://api.minecraftservices.com/authentication/login_with_xbox"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Accept", "application/json");
|
||||
Requestor *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onMinecraftAuthDone);
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onMinecraftAuthDone);
|
||||
requestor->post(request, data.toUtf8());
|
||||
qDebug() << "Getting Minecraft access token...";
|
||||
}
|
||||
@@ -518,8 +517,8 @@ void AuthContext::doSTSAuthGeneric() {
|
||||
QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Accept", "application/json");
|
||||
Requestor *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onSTSAuthGenericDone);
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onSTSAuthGenericDone);
|
||||
requestor->post(request, xbox_auth_data.toUtf8());
|
||||
qDebug() << "Getting generic STS token...";
|
||||
}
|
||||
@@ -574,8 +573,8 @@ void AuthContext::doXBoxProfile() {
|
||||
request.setRawHeader("Accept", "application/json");
|
||||
request.setRawHeader("x-xbl-contract-version", "3");
|
||||
request.setRawHeader("Authorization", QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8());
|
||||
Requestor *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onXBoxProfileDone);
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onXBoxProfileDone);
|
||||
requestor->get(request);
|
||||
qDebug() << "Getting Xbox profile...";
|
||||
}
|
||||
@@ -753,8 +752,8 @@ void AuthContext::doMinecraftProfile() {
|
||||
// request.setRawHeader("Accept", "application/json");
|
||||
request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
|
||||
|
||||
Requestor *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onMinecraftProfileDone);
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onMinecraftProfileDone);
|
||||
requestor->get(request);
|
||||
}
|
||||
|
||||
@@ -801,8 +800,8 @@ void AuthContext::doMigrationEligibilityCheck() {
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
|
||||
|
||||
Requestor *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onMigrationEligibilityCheckDone);
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onMigrationEligibilityCheckDone);
|
||||
requestor->get(request);
|
||||
}
|
||||
|
||||
@@ -853,8 +852,8 @@ void AuthContext::doGetSkin() {
|
||||
|
||||
auto url = QUrl(m_data->minecraftProfile.skin.url);
|
||||
QNetworkRequest request = QNetworkRequest(url);
|
||||
Requestor *requestor = new Requestor(this);
|
||||
connect(requestor, &Requestor::finished, this, &AuthContext::onSkinDone);
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &AuthContext::onSkinDone);
|
||||
requestor->get(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,10 @@ void PackInstallTask::downloadPack()
|
||||
auto relpath = FS::PathCombine("minecraft", file.path, file.name);
|
||||
auto path = FS::PathCombine(m_stagingPath, relpath);
|
||||
|
||||
if (filesToCopy.contains(entry->getFullPath())) {
|
||||
qWarning() << "Ignoring" << file.url << "as a file of that path is already downloading.";
|
||||
continue;
|
||||
}
|
||||
qDebug() << "Will download" << file.url << "to" << path;
|
||||
filesToCopy[entry->getFullPath()] = path;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ deploy() {
|
||||
|
||||
runmmc() {
|
||||
cd ${INSTDIR}
|
||||
./MultiMC "$@"
|
||||
exec ./MultiMC "$@"
|
||||
}
|
||||
|
||||
if [[ ! -f ${INSTDIR}/MultiMC ]]; then
|
||||
|
||||
22
launcher/pages/instance/ShaderPackPage.h
Normal file
22
launcher/pages/instance/ShaderPackPage.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "ModFolderPage.h"
|
||||
#include "ui_ModFolderPage.h"
|
||||
|
||||
class ShaderPackPage : public ModFolderPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ShaderPackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
||||
: ModFolderPage(instance, instance->shaderPackList(), "shaderpacks",
|
||||
"shaderpacks", tr("Shader packs"), "Resource-packs", parent)
|
||||
{
|
||||
ui->actionView_configs->setVisible(false);
|
||||
}
|
||||
virtual ~ShaderPackPage() {}
|
||||
|
||||
virtual bool shouldDisplay() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -30,6 +30,7 @@
|
||||
<file>scalable/resourcepacks.svg</file>
|
||||
<file>scalable/screenshots.svg</file>
|
||||
<file>scalable/settings.svg</file>
|
||||
<file>scalable/shaderpacks.svg</file>
|
||||
<file>scalable/status-bad.svg</file>
|
||||
<file>scalable/status-good.svg</file>
|
||||
<file>scalable/status-yellow.svg</file>
|
||||
|
||||
83
launcher/resources/pe_colored/scalable/shaderpacks.svg
Normal file
83
launcher/resources/pe_colored/scalable/shaderpacks.svg
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 32 32"
|
||||
viewBox="0 0 32 32"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="Calque_1"
|
||||
version="1.1"
|
||||
sodipodi:docname="shaderpacks.svg"
|
||||
inkscape:version="1.1 (c4e8f9ed74, 2021-05-24)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><sodipodi:namedview
|
||||
id="namedview14"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.584077"
|
||||
inkscape:cx="24.478752"
|
||||
inkscape:cy="13.165043"
|
||||
inkscape:window-width="2399"
|
||||
inkscape:window-height="1183"
|
||||
inkscape:window-x="2321"
|
||||
inkscape:window-y="798"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Calque_1" /><metadata
|
||||
id="metadata19"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs17"><linearGradient
|
||||
id="linearGradient3249"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3247" /></linearGradient>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</defs><g
|
||||
id="g6"><path
|
||||
id="path2"
|
||||
d="M26,0H6C2.7,0,0,2.7,0,6v3h32V6C32,2.7,29.3,0,26,0z"
|
||||
fill="#39B54A" /><path
|
||||
id="path4"
|
||||
d="M0,26c0,3.3,2.7,6,6,6h20c3.3,0,6-2.7,6-6V9H0V26z"
|
||||
fill="#8C6239" /></g><path
|
||||
fill="#F2F2F2"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
id="path8"
|
||||
d="M28,6c0-1.1-0.9-2-2-2H6C4.9,4,4,4.9,4,6v20c0,1.1,0.9,2,2,2h20 c1.1,0,2-0.9,2-2V6z" /><rect
|
||||
x="6.0678372"
|
||||
y="6.0678444"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="none"
|
||||
width="19.864313"
|
||||
height="19.864313"
|
||||
id="rect838"
|
||||
style="stroke-width:1.98049" /><path
|
||||
id="polygon840"
|
||||
style="clip-rule:evenodd;fill:#294eab;fill-rule:evenodd;stroke-width:3.19043"
|
||||
transform="matrix(0.62075979,0,0,0.62075979,293.47962,-158.4335)"
|
||||
d="m -433,272.1 v 17.8 l -14,7.1 v -17.8 z" /><path
|
||||
id="polygon842"
|
||||
style="clip-rule:evenodd;fill:#39b54a;fill-rule:evenodd;stroke-width:3.19043"
|
||||
transform="matrix(0.62075979,0,0,0.62075979,293.47962,-158.4335)"
|
||||
d="m -461,272.1 v 17.8 l 14,7.1 v -17.8 z" /><path
|
||||
id="polygon844"
|
||||
style="clip-rule:evenodd;fill:#ed4c31;fill-rule:evenodd;stroke-width:3.19043"
|
||||
transform="matrix(0.62075979,0,0,0.62075979,293.47962,-158.4335)"
|
||||
d="m -447,265 -14,7.1 14,7.1 14,-7.1 z" /></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
@@ -28,24 +28,19 @@ find_package(Qt5 COMPONENTS Core Network REQUIRED)
|
||||
|
||||
set( katabasis_PRIVATE
|
||||
src/OAuth2.cpp
|
||||
|
||||
src/JsonResponse.cpp
|
||||
src/JsonResponse.h
|
||||
src/PollServer.cpp
|
||||
src/Reply.cpp
|
||||
src/ReplyServer.cpp
|
||||
src/Requestor.cpp
|
||||
)
|
||||
|
||||
set( katabasis_PUBLIC
|
||||
include/katabasis/OAuth2.h
|
||||
|
||||
include/katabasis/Globals.h
|
||||
include/katabasis/PollServer.h
|
||||
include/katabasis/Reply.h
|
||||
include/katabasis/ReplyServer.h
|
||||
|
||||
include/katabasis/Requestor.h
|
||||
include/katabasis/RequestParameter.h
|
||||
)
|
||||
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QUrl>
|
||||
#include <QByteArray>
|
||||
#include <QHttpMultiPart>
|
||||
|
||||
#include "Reply.h"
|
||||
|
||||
namespace Katabasis {
|
||||
|
||||
class OAuth2;
|
||||
|
||||
/// Makes authenticated requests.
|
||||
class Requestor: public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Requestor(QNetworkAccessManager *manager, OAuth2 *authenticator, QObject *parent = 0);
|
||||
~Requestor();
|
||||
|
||||
public slots:
|
||||
int get(const QNetworkRequest &req, int timeout = 60*1000);
|
||||
int post(const QNetworkRequest &req, const QByteArray &data, int timeout = 60*1000);
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
/// Emitted when a request has been completed or failed.
|
||||
void finished(int id, QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers);
|
||||
|
||||
/// Emitted when an upload has progressed.
|
||||
void uploadProgress(int id, qint64 bytesSent, qint64 bytesTotal);
|
||||
|
||||
protected slots:
|
||||
/// Handle refresh completion.
|
||||
void onRefreshFinished(QNetworkReply::NetworkError error);
|
||||
|
||||
/// Handle request finished.
|
||||
void onRequestFinished();
|
||||
|
||||
/// Handle request error.
|
||||
void onRequestError(QNetworkReply::NetworkError error);
|
||||
|
||||
/// Handle ssl errors.
|
||||
void onSslErrors(QList<QSslError> errors);
|
||||
|
||||
/// Re-try request (after successful token refresh).
|
||||
void retry();
|
||||
|
||||
/// Finish the request, emit finished() signal.
|
||||
void finish();
|
||||
|
||||
/// Handle upload progress.
|
||||
void onUploadProgress(qint64 uploaded, qint64 total);
|
||||
|
||||
protected:
|
||||
int setup(const QNetworkRequest &request, QNetworkAccessManager::Operation operation, const QByteArray &verb = QByteArray());
|
||||
|
||||
enum Status {
|
||||
Idle, Requesting, ReRequesting
|
||||
};
|
||||
|
||||
QNetworkAccessManager *manager_;
|
||||
OAuth2 *authenticator_;
|
||||
QNetworkRequest request_;
|
||||
QByteArray data_;
|
||||
QNetworkReply *reply_;
|
||||
Status status_;
|
||||
int id_;
|
||||
QNetworkAccessManager::Operation operation_;
|
||||
QUrl url_;
|
||||
ReplyList timedReplies_;
|
||||
QNetworkReply::NetworkError error_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
#include <cassert>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QBuffer>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include "katabasis/Requestor.h"
|
||||
#include "katabasis/OAuth2.h"
|
||||
#include "katabasis/Globals.h"
|
||||
|
||||
namespace Katabasis {
|
||||
|
||||
Requestor::Requestor(QNetworkAccessManager *manager, OAuth2 *authenticator, QObject *parent): QObject(parent), reply_(NULL), status_(Idle) {
|
||||
manager_ = manager;
|
||||
authenticator_ = authenticator;
|
||||
if (authenticator) {
|
||||
timedReplies_.setIgnoreSslErrors(authenticator->ignoreSslErrors());
|
||||
}
|
||||
qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
|
||||
connect(authenticator, &OAuth2::refreshFinished, this, &Requestor::onRefreshFinished);
|
||||
}
|
||||
|
||||
Requestor::~Requestor() {
|
||||
}
|
||||
|
||||
int Requestor::get(const QNetworkRequest &req, int timeout/* = 60*1000*/) {
|
||||
if (-1 == setup(req, QNetworkAccessManager::GetOperation)) {
|
||||
return -1;
|
||||
}
|
||||
reply_ = manager_->get(request_);
|
||||
timedReplies_.add(new Reply(reply_, timeout));
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()));
|
||||
connect(reply_, &QNetworkReply::sslErrors, this, &Requestor::onSslErrors);
|
||||
return id_;
|
||||
}
|
||||
|
||||
int Requestor::post(const QNetworkRequest &req, const QByteArray &data, int timeout/* = 60*1000*/) {
|
||||
if (-1 == setup(req, QNetworkAccessManager::PostOperation)) {
|
||||
return -1;
|
||||
}
|
||||
data_ = data;
|
||||
reply_ = manager_->post(request_, data_);
|
||||
timedReplies_.add(new Reply(reply_, timeout));
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)));
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()));
|
||||
connect(reply_, &QNetworkReply::sslErrors, this, &Requestor::onSslErrors);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
return id_;
|
||||
}
|
||||
|
||||
void Requestor::onRefreshFinished(QNetworkReply::NetworkError error) {
|
||||
if (status_ != Requesting) {
|
||||
qWarning() << "O2Requestor::onRefreshFinished: No pending request";
|
||||
return;
|
||||
}
|
||||
if (QNetworkReply::NoError == error) {
|
||||
QTimer::singleShot(100, this, &Requestor::retry);
|
||||
} else {
|
||||
error_ = error;
|
||||
QTimer::singleShot(10, this, &Requestor::finish);
|
||||
}
|
||||
}
|
||||
|
||||
void Requestor::onRequestFinished() {
|
||||
if (status_ == Idle) {
|
||||
return;
|
||||
}
|
||||
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
|
||||
return;
|
||||
}
|
||||
if (reply_->error() == QNetworkReply::NoError) {
|
||||
QTimer::singleShot(10, this, SLOT(finish()));
|
||||
}
|
||||
}
|
||||
|
||||
void Requestor::onRequestError(QNetworkReply::NetworkError error) {
|
||||
qWarning() << "O2Requestor::onRequestError: Error" << (int)error;
|
||||
if (status_ == Idle) {
|
||||
return;
|
||||
}
|
||||
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
|
||||
return;
|
||||
}
|
||||
qWarning() << "O2Requestor::onRequestError: Error string: " << reply_->errorString();
|
||||
int httpStatus = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
qWarning() << "O2Requestor::onRequestError: HTTP status" << httpStatus << reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||
if ((status_ == Requesting) && (httpStatus == 401)) {
|
||||
// Call OAuth2::refresh. Note the O2 instance might live in a different thread
|
||||
if (QMetaObject::invokeMethod(authenticator_, "refresh")) {
|
||||
return;
|
||||
}
|
||||
qCritical() << "O2Requestor::onRequestError: Invoking remote refresh failed";
|
||||
}
|
||||
error_ = error;
|
||||
QTimer::singleShot(10, this, SLOT(finish()));
|
||||
}
|
||||
|
||||
void Requestor::onSslErrors(QList<QSslError> errors) {
|
||||
int i = 1;
|
||||
for (auto error : errors) {
|
||||
qCritical() << "LOGIN SSL Error #" << i << " : " << error.errorString();
|
||||
auto cert = error.certificate();
|
||||
qCritical() << "Certificate in question:\n" << cert.toText();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Requestor::onUploadProgress(qint64 uploaded, qint64 total) {
|
||||
if (status_ == Idle) {
|
||||
qWarning() << "O2Requestor::onUploadProgress: No pending request";
|
||||
return;
|
||||
}
|
||||
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
|
||||
return;
|
||||
}
|
||||
// Restart timeout because request in progress
|
||||
Reply *o2Reply = timedReplies_.find(reply_);
|
||||
if(o2Reply)
|
||||
o2Reply->start();
|
||||
emit uploadProgress(id_, uploaded, total);
|
||||
}
|
||||
|
||||
int Requestor::setup(const QNetworkRequest &req, QNetworkAccessManager::Operation operation, const QByteArray &verb) {
|
||||
static int currentId;
|
||||
|
||||
if (status_ != Idle) {
|
||||
qWarning() << "O2Requestor::setup: Another request pending";
|
||||
return -1;
|
||||
}
|
||||
|
||||
request_ = req;
|
||||
operation_ = operation;
|
||||
id_ = currentId++;
|
||||
url_ = req.url();
|
||||
|
||||
QUrl url = url_;
|
||||
request_.setUrl(url);
|
||||
|
||||
if (!verb.isEmpty()) {
|
||||
request_.setRawHeader(HTTP_HTTP_HEADER, verb);
|
||||
}
|
||||
|
||||
status_ = Requesting;
|
||||
error_ = QNetworkReply::NoError;
|
||||
return id_;
|
||||
}
|
||||
|
||||
void Requestor::finish() {
|
||||
QByteArray data;
|
||||
if (status_ == Idle) {
|
||||
qWarning() << "O2Requestor::finish: No pending request";
|
||||
return;
|
||||
}
|
||||
data = reply_->readAll();
|
||||
status_ = Idle;
|
||||
timedReplies_.remove(reply_);
|
||||
reply_->disconnect(this);
|
||||
reply_->deleteLater();
|
||||
QList<QNetworkReply::RawHeaderPair> headers = reply_->rawHeaderPairs();
|
||||
emit finished(id_, error_, data, headers);
|
||||
}
|
||||
|
||||
void Requestor::retry() {
|
||||
if (status_ != Requesting) {
|
||||
qWarning() << "O2Requestor::retry: No pending request";
|
||||
return;
|
||||
}
|
||||
timedReplies_.remove(reply_);
|
||||
reply_->disconnect(this);
|
||||
reply_->deleteLater();
|
||||
QUrl url = url_;
|
||||
request_.setUrl(url);
|
||||
|
||||
status_ = ReRequesting;
|
||||
switch (operation_) {
|
||||
case QNetworkAccessManager::GetOperation:
|
||||
reply_ = manager_->get(request_);
|
||||
break;
|
||||
case QNetworkAccessManager::PostOperation:
|
||||
reply_ = manager_->post(request_, data_);
|
||||
break;
|
||||
default:
|
||||
assert(!"Unspecified operation for request");
|
||||
reply_ = manager_->get(request_);
|
||||
break;
|
||||
}
|
||||
timedReplies_.add(reply_);
|
||||
connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onRequestError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(finished()), this, SLOT(onRequestFinished()), Qt::QueuedConnection);
|
||||
connect(reply_, SIGNAL(uploadProgress(qint64,qint64)), this, SLOT(onUploadProgress(qint64,qint64)));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user