refactor: NetworkPrivate (#5063)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user