File indexing completed on 2024-04-28 11:30:56
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org> 0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org> 0005 // SPDX-FileCopyrightText: 2008, 2009 Jens-Michael Hoffmann <jensmh@gmx.de> 0006 // 0007 0008 #include "HttpDownloadManager.h" 0009 0010 #include <QList> 0011 #include <QMap> 0012 #include <QTimer> 0013 #include <QNetworkAccessManager> 0014 #include <QCoreApplication> 0015 0016 #include "DownloadPolicy.h" 0017 #include "DownloadQueueSet.h" 0018 #include "HttpJob.h" 0019 #include "MarbleDebug.h" 0020 #include "StoragePolicy.h" 0021 0022 using namespace Marble; 0023 0024 // Time before a failed download job is requeued in ms 0025 const quint32 requeueTime = 60000; 0026 0027 class Q_DECL_HIDDEN HttpDownloadManager::Private 0028 { 0029 public: 0030 Private( HttpDownloadManager* parent, StoragePolicy *policy ); 0031 ~Private(); 0032 0033 void connectDefaultQueueSets(); 0034 void connectQueueSet( DownloadQueueSet * ); 0035 bool hasDownloadPolicy( const DownloadPolicy& policy ) const; 0036 void finishJob( const QByteArray&, const QString&, const QString& id ); 0037 void requeue(); 0038 void startRetryTimer(); 0039 0040 DownloadQueueSet *findQueues( const QString& hostName, const DownloadUsage usage ); 0041 0042 HttpDownloadManager* m_downloadManager; 0043 QTimer m_requeueTimer; 0044 /** 0045 * Contains per download policy a queue set containing of 0046 * - a queue where jobs are waiting for being activated (=downloaded) 0047 * - a queue containing currently being downloaded 0048 * - a queue for retries of failed downloads */ 0049 QList<QPair<DownloadPolicyKey, DownloadQueueSet *> > m_queueSets; 0050 QMap<DownloadUsage, DownloadQueueSet *> m_defaultQueueSets; 0051 StoragePolicy *const m_storagePolicy; 0052 QNetworkAccessManager m_networkAccessManager; 0053 bool m_acceptJobs; 0054 0055 }; 0056 0057 HttpDownloadManager::Private::Private(HttpDownloadManager *parent, StoragePolicy *policy ) 0058 : m_downloadManager( parent ), 0059 m_requeueTimer(), 0060 m_storagePolicy( policy ), 0061 m_networkAccessManager(), 0062 m_acceptJobs( true ) 0063 { 0064 // setup default download policy and associated queue set 0065 DownloadPolicy defaultBrowsePolicy; 0066 defaultBrowsePolicy.setMaximumConnections( 20 ); 0067 m_defaultQueueSets[ DownloadBrowse ] = new DownloadQueueSet( defaultBrowsePolicy ); 0068 DownloadPolicy defaultBulkDownloadPolicy; 0069 defaultBulkDownloadPolicy.setMaximumConnections( 2 ); 0070 m_defaultQueueSets[ DownloadBulk ] = new DownloadQueueSet( defaultBulkDownloadPolicy ); 0071 } 0072 0073 HttpDownloadManager::Private::~Private() 0074 { 0075 QMap<DownloadUsage, DownloadQueueSet *>::iterator pos = m_defaultQueueSets.begin(); 0076 QMap<DownloadUsage, DownloadQueueSet *>::iterator const end = m_defaultQueueSets.end(); 0077 for (; pos != end; ++pos ) 0078 delete pos.value(); 0079 } 0080 0081 DownloadQueueSet *HttpDownloadManager::Private::findQueues( const QString& hostName, 0082 const DownloadUsage usage ) 0083 { 0084 DownloadQueueSet * result = nullptr; 0085 QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator pos = m_queueSets.begin(); 0086 QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::iterator const end = m_queueSets.end(); 0087 for (; pos != end; ++pos ) { 0088 if ( (*pos).first.matches( hostName, usage )) { 0089 result = (*pos).second; 0090 break; 0091 } 0092 } 0093 if ( !result ) { 0094 mDebug() << "No download policy found for" << hostName << usage 0095 << ", using default policy."; 0096 result = m_defaultQueueSets[ usage ]; 0097 } 0098 return result; 0099 } 0100 0101 0102 HttpDownloadManager::HttpDownloadManager( StoragePolicy *policy ) 0103 : d( new Private( this, policy ) ) 0104 { 0105 d->m_requeueTimer.setInterval( requeueTime ); 0106 connect( &d->m_requeueTimer, SIGNAL(timeout()), this, SLOT(requeue()) ); 0107 d->connectDefaultQueueSets(); 0108 } 0109 0110 HttpDownloadManager::~HttpDownloadManager() 0111 { 0112 delete d; 0113 } 0114 0115 void HttpDownloadManager::setDownloadEnabled( const bool enable ) 0116 { 0117 d->m_networkAccessManager.setNetworkAccessible( enable ? QNetworkAccessManager::Accessible : QNetworkAccessManager::NotAccessible ); 0118 d->m_acceptJobs = enable; 0119 QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator pos = d->m_queueSets.begin(); 0120 QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator const end = d->m_queueSets.end(); 0121 for (; pos != end; ++pos ) { 0122 pos->second->purgeJobs(); 0123 } 0124 0125 } 0126 0127 void HttpDownloadManager::addDownloadPolicy( const DownloadPolicy& policy ) 0128 { 0129 if ( d->hasDownloadPolicy( policy )) 0130 return; 0131 DownloadQueueSet * const queueSet = new DownloadQueueSet( policy, this ); 0132 d->connectQueueSet( queueSet ); 0133 d->m_queueSets.append( QPair<DownloadPolicyKey, DownloadQueueSet *> 0134 ( queueSet->downloadPolicy().key(), queueSet )); 0135 } 0136 0137 void HttpDownloadManager::addJob( const QUrl& sourceUrl, const QString& destFileName, 0138 const QString &id, const DownloadUsage usage ) 0139 { 0140 if ( !d->m_acceptJobs ) { 0141 mDebug() << "Working offline, not adding job"; 0142 return; 0143 } 0144 0145 DownloadQueueSet * const queueSet = d->findQueues( sourceUrl.host(), usage ); 0146 if ( queueSet->canAcceptJob( sourceUrl, destFileName )) { 0147 HttpJob * const job = new HttpJob( sourceUrl, destFileName, id, &d->m_networkAccessManager ); 0148 job->setUserAgentPluginId( "QNamNetworkPlugin" ); 0149 job->setDownloadUsage( usage ); 0150 mDebug() << "adding job " << sourceUrl; 0151 queueSet->addJob( job ); 0152 } 0153 } 0154 0155 void HttpDownloadManager::Private::finishJob( const QByteArray& data, const QString& destinationFileName, 0156 const QString& id ) 0157 { 0158 mDebug() << "emitting downloadComplete( QByteArray, " << id << ")"; 0159 emit m_downloadManager->downloadComplete( data, id ); 0160 if ( m_storagePolicy ) { 0161 const bool saved = m_storagePolicy->updateFile( destinationFileName, data ); 0162 if ( saved ) { 0163 mDebug() << "emitting downloadComplete( " << destinationFileName << ", " << id << ")"; 0164 emit m_downloadManager->downloadComplete( destinationFileName, id ); 0165 } else { 0166 qWarning() << "Could not save:" << destinationFileName; 0167 } 0168 } 0169 } 0170 0171 void HttpDownloadManager::Private::requeue() 0172 { 0173 m_requeueTimer.stop(); 0174 0175 QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator pos = m_queueSets.begin(); 0176 QList<QPair<DownloadPolicyKey, DownloadQueueSet *> >::iterator const end = m_queueSets.end(); 0177 for (; pos != end; ++pos ) { 0178 (*pos).second->retryJobs(); 0179 } 0180 } 0181 0182 void HttpDownloadManager::Private::startRetryTimer() 0183 { 0184 if ( !m_requeueTimer.isActive() ) 0185 m_requeueTimer.start(); 0186 } 0187 0188 void HttpDownloadManager::Private::connectDefaultQueueSets() 0189 { 0190 QMap<DownloadUsage, DownloadQueueSet *>::iterator pos = m_defaultQueueSets.begin(); 0191 QMap<DownloadUsage, DownloadQueueSet *>::iterator const end = m_defaultQueueSets.end(); 0192 for (; pos != end; ++pos ) 0193 connectQueueSet( pos.value() ); 0194 } 0195 0196 void HttpDownloadManager::Private::connectQueueSet( DownloadQueueSet * queueSet ) 0197 { 0198 connect( queueSet, SIGNAL(jobFinished(QByteArray,QString,QString)), 0199 m_downloadManager, SLOT(finishJob(QByteArray,QString,QString))); 0200 connect( queueSet, SIGNAL(jobRetry()), m_downloadManager, SLOT(startRetryTimer())); 0201 connect( queueSet, SIGNAL(jobRedirected(QUrl,QString,QString,DownloadUsage)), 0202 m_downloadManager, SLOT(addJob(QUrl,QString,QString,DownloadUsage))); 0203 // relay jobAdded/jobRemoved signals (interesting for progress bar) 0204 connect( queueSet, SIGNAL(jobAdded()), m_downloadManager, SIGNAL(jobAdded())); 0205 connect( queueSet, SIGNAL(jobRemoved()), m_downloadManager, SIGNAL(jobRemoved())); 0206 connect( queueSet, SIGNAL(progressChanged(int,int)), m_downloadManager, SIGNAL(progressChanged(int,int)) ); 0207 } 0208 0209 bool HttpDownloadManager::Private::hasDownloadPolicy( const DownloadPolicy& policy ) const 0210 { 0211 bool found = false; 0212 QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::const_iterator pos = m_queueSets.constBegin(); 0213 QList<QPair<DownloadPolicyKey, DownloadQueueSet*> >::const_iterator const end = m_queueSets.constEnd(); 0214 for (; pos != end; ++pos ) { 0215 if ( (*pos).second->downloadPolicy() == policy ) { 0216 found = true; 0217 break; 0218 } 0219 } 0220 return found; 0221 } 0222 0223 QByteArray HttpDownloadManager::userAgent(const QString &platform, const QString &component) 0224 { 0225 QString result( "Mozilla/5.0 (compatible; Marble/%1; %2; %3; %4; %5)" ); 0226 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; 0227 QString const device = smallScreen ? "MobileDevice" : "DesktopDevice"; 0228 QString const app = QCoreApplication::applicationName(); 0229 result = result.arg( MARBLE_VERSION_STRING, device, platform, component, app); 0230 return result.toLatin1(); 0231 } 0232 0233 #include "moc_HttpDownloadManager.cpp"