NetworkController.cpp
148 lines
| 5.5 KiB
| text/x-c
|
CppLexer
r313 | #include "Network/NetworkController.h" | |||
#include <QMutex> | ||||
r356 | #include <QNetworkAccessManager> | |||
#include <QNetworkReply> | ||||
r359 | #include <QNetworkRequest> | |||
r389 | #include <QReadWriteLock> | |||
r313 | #include <QThread> | |||
r359 | #include <unordered_map> | |||
r313 | Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController") | |||
struct NetworkController::NetworkControllerPrivate { | ||||
r359 | explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {} | |||
r510 | ||||
void lockRead() { m_Lock.lockForRead(); } | ||||
void lockWrite() { m_Lock.lockForWrite(); } | ||||
void unlock() { m_Lock.unlock(); } | ||||
r313 | QMutex m_WorkingMutex; | |||
r356 | ||||
r389 | QReadWriteLock m_Lock; | |||
r698 | std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToId; | |||
r356 | std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr}; | |||
r313 | }; | |||
NetworkController::NetworkController(QObject *parent) | ||||
: QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)} | ||||
{ | ||||
r356 | } | |||
r694 | void NetworkController::onProcessRequested(std::shared_ptr<QNetworkRequest> request, | |||
QUuid identifier, | ||||
r359 | std::function<void(QNetworkReply *, QUuid)> callback) | |||
r356 | { | |||
r694 | qCDebug(LOG_NetworkController()) << tr("NetworkController onProcessRequested") | |||
<< QThread::currentThread()->objectName() << &request; | ||||
auto reply = impl->m_AccessManager->get(*request); | ||||
r359 | ||||
// Store the couple reply id | ||||
r389 | impl->lockWrite(); | |||
r698 | impl->m_NetworkReplyToId[reply] = identifier; | |||
qCDebug(LOG_NetworkController()) << tr("Store for reply: ") << identifier; | ||||
r389 | impl->unlock(); | |||
r359 | ||||
r693 | auto onReplyFinished = [request, reply, this, identifier, callback]() { | |||
r359 | ||||
r389 | qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished") | |||
r694 | << QThread::currentThread() << request.get() << reply; | |||
r389 | impl->lockRead(); | |||
r698 | auto it = impl->m_NetworkReplyToId.find(reply); | |||
if (it != impl->m_NetworkReplyToId.cend()) { | ||||
r703 | qCDebug(LOG_NetworkController()) << tr("Remove for reply: ") << it->second; | |||
impl->unlock(); | ||||
r389 | impl->lockWrite(); | |||
r698 | impl->m_NetworkReplyToId.erase(reply); | |||
r389 | impl->unlock(); | |||
// Deletes reply | ||||
r359 | callback(reply, identifier); | |||
r389 | reply->deleteLater(); | |||
r359 | } | |||
r703 | else { | |||
impl->unlock(); | ||||
} | ||||
r389 | ||||
qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished END") | ||||
<< QThread::currentThread() << reply; | ||||
r359 | }; | |||
r693 | auto onReplyProgress = [reply, request, this](qint64 bytesRead, qint64 totalBytes) { | |||
r356 | ||||
r698 | // NOTE: a totalbytes of 0 can happened when a request has been aborted | |||
if (totalBytes > 0) { | ||||
double progress = (bytesRead * 100.0) / totalBytes; | ||||
qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress") << progress | ||||
r700 | << QThread::currentThread() << request.get() << reply | |||
<< bytesRead << totalBytes; | ||||
r698 | impl->lockRead(); | |||
auto it = impl->m_NetworkReplyToId.find(reply); | ||||
if (it != impl->m_NetworkReplyToId.cend()) { | ||||
r703 | auto id = it->second; | |||
impl->unlock(); | ||||
emit this->replyDownloadProgress(id, request, progress); | ||||
} | ||||
else { | ||||
impl->unlock(); | ||||
r698 | } | |||
r703 | ||||
r698 | qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress END") | |||
<< QThread::currentThread() << reply; | ||||
r359 | } | |||
}; | ||||
r356 | ||||
r359 | ||||
connect(reply, &QNetworkReply::finished, this, onReplyFinished); | ||||
r369 | connect(reply, &QNetworkReply::downloadProgress, this, onReplyProgress); | |||
r392 | qCDebug(LOG_NetworkController()) << tr("NetworkController registered END") | |||
<< QThread::currentThread()->objectName() << reply; | ||||
r313 | } | |||
void NetworkController::initialize() | ||||
{ | ||||
qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread(); | ||||
impl->m_WorkingMutex.lock(); | ||||
r359 | impl->m_AccessManager = std::make_unique<QNetworkAccessManager>(); | |||
r392 | ||||
auto onReplyErrors = [this](QNetworkReply *reply, const QList<QSslError> &errors) { | ||||
qCCritical(LOG_NetworkController()) << tr("NetworkAcessManager errors: ") << errors; | ||||
}; | ||||
connect(impl->m_AccessManager.get(), &QNetworkAccessManager::sslErrors, this, onReplyErrors); | ||||
r313 | qCDebug(LOG_NetworkController()) << tr("NetworkController init END"); | |||
} | ||||
void NetworkController::finalize() | ||||
{ | ||||
impl->m_WorkingMutex.unlock(); | ||||
} | ||||
r359 | void NetworkController::onReplyCanceled(QUuid identifier) | |||
{ | ||||
auto findReply = [identifier](const auto &entry) { return identifier == entry.second; }; | ||||
r389 | qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled") | |||
r700 | << QThread::currentThread() << identifier; | |||
r389 | ||||
r359 | ||||
r389 | impl->lockRead(); | |||
r698 | auto end = impl->m_NetworkReplyToId.cend(); | |||
auto it = std::find_if(impl->m_NetworkReplyToId.cbegin(), end, findReply); | ||||
r389 | impl->unlock(); | |||
r359 | if (it != end) { | |||
r698 | qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled ABORT DONE") | |||
r700 | << QThread::currentThread() << identifier; | |||
r359 | it->first->abort(); | |||
} | ||||
r389 | qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled END") | |||
r700 | << QThread::currentThread(); | |||
r359 | } | |||
r313 | void NetworkController::waitForFinish() | |||
{ | ||||
QMutexLocker locker{&impl->m_WorkingMutex}; | ||||
} | ||||