You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Tools/News/NewsShared/ResourceManagement/QtDownloader.cpp

139 lines
4.8 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "QtDownloader.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QThread>
namespace News
{
QtDownloader::QtDownloader()
: m_thread(new QThread())
{
// make sure that everything that QObject::connects to us knows we're running in a different thread
moveToThread(m_thread);
// handle clean up of both ourselves and of our thread.
// We manage thread clean up so that it can keep running and be cleaned up later, regardless of what
// the thing that created the QtDownloader does
connect(m_thread, &QThread::finished, m_thread, [this] {
m_thread->deleteLater();
deleteLater();
});
auto abortDownloadsHandler = [this] {
auto replies = m_downloads.keys();
for (QNetworkReply* reply : replies)
{
reply->abort();
}
m_downloads.clear();
};
auto queueDownloadHandler = [this](int downloadId, QString url) {
if (m_networkManager)
{
QNetworkReply* reply = m_networkManager->get(QNetworkRequest(QUrl(url)));
m_downloads.insert(reply, downloadId);
}
};
auto createNetworkManagerHandler = [this] {
m_networkManager = new QNetworkAccessManager;
connect(m_networkManager, &QNetworkAccessManager::finished, this, &QtDownloader::downloadFinished);
};
auto deleteNetworkManagerHandler = [this] {
delete m_networkManager;
m_networkManager = nullptr;
};
auto quitHandler = [this] {
// call quit via this callback, so that it executes in the running thread.
// QThread::quit() is actually blocking and waits until everything finishes, so
// we don't want to call it in the main thread
m_thread->quit();
};
// make sure the response handlers are queued connections as the worker runs in one thread, but these triggers
// will be emitted from the main thread
connect(this, &QtDownloader::triggerAbortAll, this, abortDownloadsHandler, Qt::QueuedConnection);
connect(this, &QtDownloader::triggerDownload, this, queueDownloadHandler, Qt::QueuedConnection);
connect(this, &QtDownloader::triggerQuit, this, quitHandler, Qt::QueuedConnection);
// create/delete the QNetworkAccessManager in our thread, to ensure that any slowdowns caused by
// having to create network connectors / load drivers are done in our non-ui thread.
// make sure that these connections are direct so that network requests can't predate the network engine itself
connect(m_thread, &QThread::started, this, createNetworkManagerHandler, Qt::DirectConnection);
connect(m_thread, &QThread::finished, this, deleteNetworkManagerHandler, Qt::DirectConnection);
m_thread->start();
}
QtDownloader::~QtDownloader()
{
}
int QtDownloader::Download(const QString& url)
{
// create a unique id for this download
int downloadId = m_lastId++;
// trigger a download running in our worker thread
Q_EMIT triggerDownload(downloadId, url);
return downloadId;
}
void QtDownloader::Abort()
{
// trigger an abort in our worker thread
Q_EMIT triggerAbortAll();
}
void QtDownloader::Finish()
{
// trigger a quit in our worker thread
Q_EMIT triggerQuit();
}
void QtDownloader::downloadFinished(QNetworkReply* reply)
{
// Note: this will run in our worker thread
int downloadId = m_downloads[reply];
// emit the signal back to the main thread indicating that we're finished, either
// successfully or unsuccessfully
if (reply->error() == QNetworkReply::NoError)
{
Q_EMIT successfullyFinished(downloadId, reply->readAll());
}
else
{
Q_EMIT failed(downloadId);
}
// clean up the reply; have to do this later, according to the Qt docs
reply->deleteLater();
// make sure to remove our reference to this reply from our list of active downloads
m_downloads.remove(reply);
}
#include "NewsShared/ResourceManagement/moc_QtDownloader.cpp"
}