From d59d0cee3e6b2c2fe4723f84435826ce838398ff Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Wed, 20 Aug 2014 17:52:44 +0200 Subject: [PATCH] Improve data downloading. --- src/core/feedsmodelfeed.cpp | 21 +++--- src/miscellaneous/systemfactory.cpp | 2 +- src/network-web/downloader.cpp | 22 +++--- src/network-web/downloader.h | 9 ++- src/network-web/networkfactory.cpp | 108 ++++------------------------ src/network-web/networkfactory.h | 2 +- 6 files changed, 47 insertions(+), 117 deletions(-) diff --git a/src/core/feedsmodelfeed.cpp b/src/core/feedsmodelfeed.cpp index fd657cba4..938990141 100755 --- a/src/core/feedsmodelfeed.cpp +++ b/src/core/feedsmodelfeed.cpp @@ -145,12 +145,12 @@ QPair FeedsModelFeed::guessFeed(co } QByteArray feed_contents; - if ((result.second = NetworkFactory::downloadFeedFile(url, - qApp->settings()->value(APP_CFG_FEEDS, "feed_update_timeout", DOWNLOAD_TIMEOUT).toInt(), - feed_contents, - !username.isEmpty(), - username, - password)) == QNetworkReply::NoError) { + if ((result.second = NetworkFactory::downloadFile(url, + qApp->settings()->value(APP_CFG_FEEDS, "feed_update_timeout", DOWNLOAD_TIMEOUT).toInt(), + feed_contents, + !username.isEmpty(), + username, + password)) == QNetworkReply::NoError) { // Feed XML was obtained, now we need to try to guess // its encoding before we can read further data. QString xml_schema_encoding; @@ -349,12 +349,9 @@ QVariant FeedsModelFeed::data(int column, int role) const { void FeedsModelFeed::update() { QByteArray feed_contents; int download_timeout = qApp->settings()->value(APP_CFG_FEEDS, "feed_update_timeout", DOWNLOAD_TIMEOUT).toInt(); - QNetworkReply::NetworkError download_result = NetworkFactory::downloadFeedFile(url(), - download_timeout, - feed_contents, - passwordProtected(), - username(), - password()); + QNetworkReply::NetworkError download_result = NetworkFactory::downloadFile(url(), download_timeout, + feed_contents, passwordProtected(), + username(), password()); if (download_result != QNetworkReply::NoError) { qWarning("Error during fetching of new messages for feed '%s' (id %d).", diff --git a/src/miscellaneous/systemfactory.cpp b/src/miscellaneous/systemfactory.cpp index 5839b992f..ebae24734 100644 --- a/src/miscellaneous/systemfactory.cpp +++ b/src/miscellaneous/systemfactory.cpp @@ -152,7 +152,7 @@ QPair SystemFactory::checkForUpdates() QPair result; QByteArray releases_xml; - result.second = NetworkFactory::downloadFeedFile(RELEASES_LIST, DOWNLOAD_TIMEOUT, releases_xml); + result.second = NetworkFactory::downloadFile(RELEASES_LIST, DOWNLOAD_TIMEOUT, releases_xml); if (result.second == QNetworkReply::NoError) { result.first = parseUpdatesFile(releases_xml); diff --git a/src/network-web/downloader.cpp b/src/network-web/downloader.cpp index 0ba87b4bd..645cda9e1 100755 --- a/src/network-web/downloader.cpp +++ b/src/network-web/downloader.cpp @@ -23,10 +23,8 @@ Downloader::Downloader(QObject *parent) - : QObject(parent), - m_activeReply(NULL), - m_downloadManager(new SilentNetworkAccessManager(this)), - m_timer(new QTimer(this)) { + : QObject(parent), m_activeReply(NULL), m_downloadManager(new SilentNetworkAccessManager(this)), + m_timer(new QTimer(this)), m_lastOutputData(QByteArray()), m_lastOutputError(QNetworkReply::NoError) { m_timer->setInterval(DOWNLOAD_TIMEOUT); m_timer->setSingleShot(true); @@ -39,7 +37,7 @@ Downloader::~Downloader() { m_downloadManager->deleteLater(); } -void Downloader::downloadFile(const QString &url, bool protected_contents, +void Downloader::downloadFile(const QString &url, int timeout, bool protected_contents, const QString &username, const QString &password) { QNetworkRequest request; QObject originatingObject; @@ -75,13 +73,13 @@ void Downloader::finished(QNetworkReply *reply) { else { // No redirection is indicated. Final file is obtained in our "reply" object. // Read the data into output buffer. - QByteArray output = reply->readAll(); - QNetworkReply::NetworkError reply_error = reply->error(); + m_lastOutputData = reply->readAll(); + m_lastOutputError = reply->error(); m_activeReply->deleteLater(); m_activeReply = NULL; - emit completed(reply_error, output); + emit completed(m_lastOutputError, m_lastOutputData); } } @@ -107,3 +105,11 @@ void Downloader::runGetRequest(const QNetworkRequest &request) { connect(m_activeReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(progressInternal(qint64,qint64))); } + +QNetworkReply::NetworkError Downloader::lastOutputError() const { + return m_lastOutputError; +} + +QByteArray Downloader::lastOutputData() const { + return m_lastOutputData; +} diff --git a/src/network-web/downloader.h b/src/network-web/downloader.h index d347baa9e..ecc7c1a20 100755 --- a/src/network-web/downloader.h +++ b/src/network-web/downloader.h @@ -37,9 +37,13 @@ class Downloader : public QObject { explicit Downloader(QObject *parent = 0); virtual ~Downloader(); + // Access to last received full output data/error. + QByteArray lastOutputData() const; + QNetworkReply::NetworkError lastOutputError() const; + public slots: // Performs asynchronous download of given file. Redirections are handled. - void downloadFile(const QString &url, bool protected_contents = false, + void downloadFile(const QString &url, int timeout = DOWNLOAD_TIMEOUT, bool protected_contents = false, const QString &username = QString(), const QString &password = QString()); signals: @@ -64,6 +68,9 @@ class Downloader : public QObject { QNetworkReply *m_activeReply; SilentNetworkAccessManager *m_downloadManager; QTimer *m_timer; + + QByteArray m_lastOutputData; + QNetworkReply::NetworkError m_lastOutputError; }; #endif // DOWNLOADER_H diff --git a/src/network-web/networkfactory.cpp b/src/network-web/networkfactory.cpp index 794a1a77f..8a79b817e 100755 --- a/src/network-web/networkfactory.cpp +++ b/src/network-web/networkfactory.cpp @@ -20,6 +20,7 @@ #include "definitions/definitions.h" #include "miscellaneous/settings.h" #include "network-web/silentnetworkaccessmanager.h" +#include "network-web/downloader.h" #include #include @@ -104,7 +105,7 @@ QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QString &url, QString google_s2_with_url = QString("http://www.google.com/s2/favicons?domain=%1").arg(Qt::escape(url)); #endif QByteArray icon_data; - QNetworkReply::NetworkError network_result = downloadFeedFile(google_s2_with_url, timeout, icon_data); + QNetworkReply::NetworkError network_result = downloadFile(google_s2_with_url, timeout, icon_data); if (network_result == QNetworkReply::NoError) { QPixmap icon_pixmap; @@ -115,101 +116,20 @@ QNetworkReply::NetworkError NetworkFactory::downloadIcon(const QString &url, return network_result; } -QNetworkReply::NetworkError NetworkFactory::downloadFeedFile(const QString &url, - int timeout, - QByteArray &output, - bool protected_contents, - const QString &username, - const QString &password) { - // Original asynchronous behavior of QNetworkAccessManager - // is replaced by synchronous behavior in order to make - // process of downloading of a file easier to understand. - - // Make necessary variables. - SilentNetworkAccessManager manager; +QNetworkReply::NetworkError NetworkFactory::downloadFile(const QString &url, int timeout, + QByteArray &output, bool protected_contents, + const QString &username, const QString &password) { + // Here, we want to achieve "synchronous" approach because we want synchronout download API for + // some use-cases too. + Downloader downloader; QEventLoop loop; - QTimer timer; - QNetworkRequest request; - QNetworkReply *reply; - QObject originatingObject; - // Set credential information as originating object. - originatingObject.setProperty("protected", protected_contents); - originatingObject.setProperty("username", username); - originatingObject.setProperty("password", password); - request.setOriginatingObject(&originatingObject); + // We need to quit event loop when the download finishes. + QObject::connect(&downloader, SIGNAL(completed(QNetworkReply::NetworkError)), &loop, SLOT(quit())); - // Set url for this reques. - request.setUrl(url); + downloader.downloadFile(url, timeout, protected_contents, username, password); + loop.exec(); + output = downloader.lastOutputData(); - // Create necessary connections. - QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit())); - - forever { - // This timer fires just ONCE. - timer.setSingleShot(true); - - // Try to open communication channel. - reply = manager.get(request); - - // Start the timeout timer. - timer.start(timeout); - - // Enter the event loop. - loop.exec(); - - // At this point one of two things happened: - // a) file download was completed, - // b) communication timed-out. - - if (timer.isActive()) { - // Download is complete because timer is still running. - timer.stop(); - } - else { - if (reply != NULL) { - delete reply; - reply = NULL; - } - - // Timer already fired. Download is NOT successful. - return QNetworkReply::TimeoutError; - } - - // In this phase, some part of downloading process is completed. - QUrl redirection_url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); - - if (redirection_url.isValid()) { - // Communication indicates that HTTP redirection is needed. - // Setup redirection URL and download again. - request.setUrl(redirection_url); - - delete reply; - reply = NULL; - } - else { - // No redirection is indicated. Final file is obtained - // in our "reply" object. - break; - } - } - - // Read the data into output buffer. - output = reply->readAll(); - - QNetworkReply::NetworkError reply_error = reply->error(); - - qDebug("File '%s' fetched with status '%s' (code %d).", - qPrintable(url), - qPrintable(networkErrorText(reply_error)), - reply_error); - - // Delete needed stuff and exit. - if (reply != NULL) { - delete reply; - reply = NULL; - } - - return reply_error; + return downloader.lastOutputError(); } diff --git a/src/network-web/networkfactory.h b/src/network-web/networkfactory.h index d45c50b47..ea05023f0 100644 --- a/src/network-web/networkfactory.h +++ b/src/network-web/networkfactory.h @@ -41,7 +41,7 @@ class NetworkFactory { // Performs SYNCHRONOUS download of file with given URL // and given timeout. - static QNetworkReply::NetworkError downloadFeedFile(const QString &url, + static QNetworkReply::NetworkError downloadFile(const QString &url, int timeout, QByteArray &output, bool protected_contents = false,