refactor: NetworkPrivate (#5063)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix
2024-01-09 00:37:15 +01:00
committed by GitHub
parent f42ae07408
commit fa5648fd9a
11 changed files with 465 additions and 421 deletions
+189
View File
@@ -0,0 +1,189 @@
#include "common/network/NetworkTask.hpp"
#include "common/NetworkManager.hpp"
#include "common/NetworkPrivate.hpp"
#include "common/NetworkResult.hpp"
#include "common/QLogging.hpp"
#include "singletons/Paths.hpp"
#include "util/AbandonObject.hpp"
#include "util/DebugCount.hpp"
#include <QFile>
#include <QNetworkReply>
#include <QtConcurrent>
namespace chatterino::network::detail {
NetworkTask::NetworkTask(std::shared_ptr<NetworkData> &&data)
: data_(std::move(data))
{
}
NetworkTask::~NetworkTask()
{
if (this->reply_)
{
this->reply_->deleteLater();
}
}
void NetworkTask::run()
{
const auto &timeout = this->data_->timeout;
if (timeout.has_value())
{
this->timer_ = new QTimer(this);
this->timer_->setSingleShot(true);
this->timer_->start(timeout.value());
QObject::connect(this->timer_, &QTimer::timeout, this,
&NetworkTask::timeout);
}
this->reply_ = this->createReply();
if (!this->reply_)
{
this->deleteLater();
return;
}
QObject::connect(this->reply_, &QNetworkReply::finished, this,
&NetworkTask::finished);
}
QNetworkReply *NetworkTask::createReply()
{
const auto &data = this->data_;
const auto &request = this->data_->request;
auto &accessManager = NetworkManager::accessManager;
switch (this->data_->requestType)
{
case NetworkRequestType::Get:
return accessManager.get(request);
case NetworkRequestType::Put:
return accessManager.put(request, data->payload);
case NetworkRequestType::Delete:
return accessManager.deleteResource(data->request);
case NetworkRequestType::Post:
if (data->multiPartPayload)
{
assert(data->payload.isNull());
return accessManager.post(request,
data->multiPartPayload.get());
}
else
{
return accessManager.post(request, data->payload);
}
case NetworkRequestType::Patch:
if (data->multiPartPayload)
{
assert(data->payload.isNull());
return accessManager.sendCustomRequest(
request, "PATCH", data->multiPartPayload.get());
}
else
{
return NetworkManager::accessManager.sendCustomRequest(
request, "PATCH", data->payload);
}
}
return nullptr;
}
void NetworkTask::logReply()
{
auto status =
this->reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute)
.toInt();
if (this->data_->requestType == NetworkRequestType::Get)
{
qCDebug(chatterinoHTTP).noquote()
<< this->data_->typeString() << status
<< this->data_->request.url().toString();
}
else
{
qCDebug(chatterinoHTTP).noquote()
<< this->data_->typeString()
<< this->data_->request.url().toString() << status
<< QString(this->data_->payload);
}
}
void NetworkTask::writeToCache(const QByteArray &bytes) const
{
std::ignore = QtConcurrent::run([data = this->data_, bytes] {
QFile cachedFile(getPaths()->cacheDirectory() + "/" + data->getHash());
if (cachedFile.open(QIODevice::WriteOnly))
{
cachedFile.write(bytes);
}
});
}
void NetworkTask::timeout()
{
AbandonObject guard(this);
// prevent abort() from calling finished()
QObject::disconnect(this->reply_, &QNetworkReply::finished, this,
&NetworkTask::finished);
this->reply_->abort();
qCDebug(chatterinoHTTP).noquote()
<< this->data_->typeString() << "[timed out]"
<< this->data_->request.url().toString();
this->data_->emitError({NetworkResult::NetworkError::TimeoutError, {}, {}});
this->data_->emitFinally();
}
void NetworkTask::finished()
{
AbandonObject guard(this);
if (this->timer_)
{
this->timer_->stop();
}
auto *reply = this->reply_;
auto status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
if (reply->error() == QNetworkReply::OperationCanceledError)
{
// Operation cancelled, most likely timed out
qCDebug(chatterinoHTTP).noquote()
<< this->data_->typeString() << "[cancelled]"
<< this->data_->request.url().toString();
return;
}
if (reply->error() != QNetworkReply::NoError)
{
this->logReply();
this->data_->emitError({reply->error(), status, reply->readAll()});
this->data_->emitFinally();
return;
}
QByteArray bytes = reply->readAll();
if (this->data_->cache)
{
this->writeToCache(bytes);
}
DebugCount::increase("http request success");
this->logReply();
this->data_->emitSuccess({reply->error(), status, bytes});
this->data_->emitFinally();
}
} // namespace chatterino::network::detail
+51
View File
@@ -0,0 +1,51 @@
#pragma once
#include <QObject>
#include <QTimer>
#include <memory>
class QNetworkReply;
namespace chatterino {
class NetworkData;
} // namespace chatterino
namespace chatterino::network::detail {
class NetworkTask : public QObject
{
Q_OBJECT
public:
NetworkTask(std::shared_ptr<NetworkData> &&data);
~NetworkTask() override;
NetworkTask(const NetworkTask &) = delete;
NetworkTask(NetworkTask &&) = delete;
NetworkTask &operator=(const NetworkTask &) = delete;
NetworkTask &operator=(NetworkTask &&) = delete;
// NOLINTNEXTLINE(readability-redundant-access-specifiers)
public slots:
void run();
private:
QNetworkReply *createReply();
void logReply();
void writeToCache(const QByteArray &bytes) const;
std::shared_ptr<NetworkData> data_;
QNetworkReply *reply_{}; // parent: default (accessManager)
QTimer *timer_{}; // parent: this
// NOLINTNEXTLINE(readability-redundant-access-specifiers)
private slots:
void timeout();
void finished();
};
} // namespace chatterino::network::detail