File indexing completed on 2025-01-05 03:59:34
0001 // SPDX-FileCopyrightText: 2009 Jens-Michael Hoffmann <jmho@c-xx.com> 0002 // 0003 // SPDX-License-Identifier: LGPL-2.1-or-later 0004 0005 #include "DownloadQueueSet.h" 0006 0007 #include "HttpJob.h" 0008 0009 #include "digikam_debug.h" 0010 0011 namespace Marble 0012 { 0013 0014 DownloadQueueSet::DownloadQueueSet( QObject * const parent ) 0015 : QObject( parent ) 0016 { 0017 } 0018 0019 DownloadQueueSet::DownloadQueueSet( DownloadPolicy const & policy, QObject * const parent ) 0020 : QObject( parent ), 0021 m_downloadPolicy( policy ) 0022 { 0023 } 0024 0025 DownloadQueueSet::~DownloadQueueSet() 0026 { 0027 // todo: delete HttpJobs 0028 } 0029 0030 DownloadPolicy DownloadQueueSet::downloadPolicy() const 0031 { 0032 return m_downloadPolicy; 0033 } 0034 0035 void DownloadQueueSet::setDownloadPolicy( DownloadPolicy const & policy ) 0036 { 0037 m_downloadPolicy = policy; 0038 } 0039 0040 bool DownloadQueueSet::canAcceptJob( const QUrl& sourceUrl, 0041 const QString& destinationFileName ) const 0042 { 0043 if ( jobIsQueued( destinationFileName )) { 0044 qCDebug(DIGIKAM_MARBLE_LOG) << "Download rejected: It's in the queue already:" 0045 << destinationFileName; 0046 return false; 0047 } 0048 if ( jobIsWaitingForRetry( destinationFileName )) { 0049 qCDebug(DIGIKAM_MARBLE_LOG) << "Download rejected: Will try to download again in some time:" 0050 << destinationFileName; 0051 return false; 0052 } 0053 if ( jobIsActive( destinationFileName )) { 0054 qCDebug(DIGIKAM_MARBLE_LOG) << "Download rejected: It's being downloaded already:" 0055 << destinationFileName; 0056 return false; 0057 } 0058 if ( jobIsBlackListed( sourceUrl )) { 0059 qCDebug(DIGIKAM_MARBLE_LOG) << "Download rejected: Blacklisted."; 0060 return false; 0061 } 0062 return true; 0063 } 0064 0065 void DownloadQueueSet::addJob( HttpJob * const job ) 0066 { 0067 m_jobs.push( job ); 0068 qCDebug(DIGIKAM_MARBLE_LOG) << "addJob: new job queue size:" << m_jobs.count(); 0069 Q_EMIT jobAdded(); 0070 Q_EMIT progressChanged( m_activeJobs.size(), m_jobs.count() ); 0071 activateJobs(); 0072 } 0073 0074 void DownloadQueueSet::activateJobs() 0075 { 0076 while ( !m_jobs.isEmpty() 0077 && m_activeJobs.count() < m_downloadPolicy.maximumConnections() ) 0078 { 0079 HttpJob * const job = m_jobs.pop(); 0080 activateJob( job ); 0081 } 0082 } 0083 0084 void DownloadQueueSet::retryJobs() 0085 { 0086 while ( !m_retryQueue.isEmpty() ) { 0087 HttpJob * const job = m_retryQueue.dequeue(); 0088 qCDebug(DIGIKAM_MARBLE_LOG) << "Requeuing" << job->destinationFileName(); 0089 // FIXME: addJob calls activateJobs every time 0090 addJob( job ); 0091 } 0092 } 0093 0094 void DownloadQueueSet::purgeJobs() 0095 { 0096 // purge all waiting jobs 0097 while( !m_jobs.isEmpty() ) { 0098 HttpJob * const job = m_jobs.pop(); 0099 job->deleteLater(); 0100 } 0101 0102 // purge all retry jobs 0103 qDeleteAll( m_retryQueue ); 0104 m_retryQueue.clear(); 0105 0106 // cancel all current jobs 0107 while( !m_activeJobs.isEmpty() ) { 0108 deactivateJob( m_activeJobs.first() ); 0109 } 0110 0111 Q_EMIT progressChanged( m_activeJobs.size(), m_jobs.count() ); 0112 } 0113 0114 void DownloadQueueSet::finishJob( HttpJob * job, const QByteArray& data ) 0115 { 0116 qCDebug(DIGIKAM_MARBLE_LOG) << "finishJob: " << job->sourceUrl() << job->destinationFileName(); 0117 0118 deactivateJob( job ); 0119 Q_EMIT jobRemoved(); 0120 Q_EMIT jobFinished( data, job->destinationFileName(), job->initiatorId() ); 0121 job->deleteLater(); 0122 activateJobs(); 0123 } 0124 0125 void DownloadQueueSet::redirectJob( HttpJob * job, const QUrl& newSourceUrl ) 0126 { 0127 qCDebug(DIGIKAM_MARBLE_LOG) << "jobRedirected:" << job->sourceUrl() << " -> " << newSourceUrl; 0128 0129 deactivateJob( job ); 0130 Q_EMIT jobRemoved(); 0131 Q_EMIT jobRedirected( newSourceUrl, job->destinationFileName(), job->initiatorId(), 0132 job->downloadUsage() ); 0133 job->deleteLater(); 0134 } 0135 0136 void DownloadQueueSet::retryOrBlacklistJob( HttpJob * job, const int errorCode ) 0137 { 0138 Q_ASSERT( errorCode != 0 ); 0139 Q_ASSERT( !m_retryQueue.contains( job )); 0140 0141 deactivateJob( job ); 0142 Q_EMIT jobRemoved(); 0143 0144 if ( job->tryAgain() ) { 0145 qCDebug(DIGIKAM_MARBLE_LOG) << QString::fromUtf8( "Download of %1 to %2 failed, but trying again soon" ) 0146 .arg( job->sourceUrl().toString(), job->destinationFileName() ); 0147 m_retryQueue.enqueue( job ); 0148 Q_EMIT jobRetry(); 0149 } 0150 else { 0151 qCDebug(DIGIKAM_MARBLE_LOG) << "JOB-address: " << job 0152 << "Blacklist-size:" << m_jobBlackList.size() 0153 << "err:" << errorCode; 0154 m_jobBlackList.insert( job->sourceUrl().toString() ); 0155 qCDebug(DIGIKAM_MARBLE_LOG) << QString::fromUtf8( "Download of %1 Blacklisted. " 0156 "Number of blacklist items: %2" ) 0157 .arg( job->destinationFileName() ) 0158 .arg( m_jobBlackList.size() ); 0159 0160 job->deleteLater(); 0161 } 0162 activateJobs(); 0163 } 0164 0165 void DownloadQueueSet::activateJob( HttpJob * const job ) 0166 { 0167 m_activeJobs.push_back( job ); 0168 Q_EMIT progressChanged( m_activeJobs.size(), m_jobs.count() ); 0169 0170 connect( job, SIGNAL(jobDone(HttpJob*,int)), 0171 SLOT(retryOrBlacklistJob(HttpJob*,int))); 0172 connect( job, SIGNAL(redirected(HttpJob*,QUrl)), 0173 SLOT(redirectJob(HttpJob*,QUrl))); 0174 connect( job, SIGNAL(dataReceived(HttpJob*,QByteArray)), 0175 SLOT(finishJob(HttpJob*,QByteArray))); 0176 0177 job->execute(); 0178 } 0179 0180 /** 0181 pre condition: - job is in m_activeJobs 0182 - job's signal are connected to our slots 0183 post condition: - job is not in m_activeJobs anymore (and btw not 0184 in any other queue) 0185 - job's signals are disconnected from our slots 0186 */ 0187 void DownloadQueueSet::deactivateJob( HttpJob * const job ) 0188 { 0189 const bool disconnected = job->disconnect(); 0190 Q_ASSERT( disconnected ); 0191 Q_UNUSED( disconnected ); // for Q_ASSERT in release mode 0192 const bool removed = m_activeJobs.removeOne( job ); 0193 Q_ASSERT( removed ); 0194 Q_UNUSED( removed ); // for Q_ASSERT in release mode 0195 Q_EMIT progressChanged( m_activeJobs.size(), m_jobs.count() ); 0196 } 0197 0198 bool DownloadQueueSet::jobIsActive( QString const & destinationFileName ) const 0199 { 0200 QList<HttpJob*>::const_iterator pos = m_activeJobs.constBegin(); 0201 QList<HttpJob*>::const_iterator const end = m_activeJobs.constEnd(); 0202 for (; pos != end; ++pos) { 0203 if ( (*pos)->destinationFileName() == destinationFileName ) { 0204 return true; 0205 } 0206 } 0207 return false; 0208 } 0209 0210 inline bool DownloadQueueSet::jobIsQueued( QString const & destinationFileName ) const 0211 { 0212 return m_jobs.contains( destinationFileName ); 0213 } 0214 0215 bool DownloadQueueSet::jobIsWaitingForRetry( QString const & destinationFileName ) const 0216 { 0217 QList<HttpJob*>::const_iterator pos = m_retryQueue.constBegin(); 0218 QList<HttpJob*>::const_iterator const end = m_retryQueue.constEnd(); 0219 for (; pos != end; ++pos) { 0220 if ( (*pos)->destinationFileName() == destinationFileName ) { 0221 return true; 0222 } 0223 } 0224 return false; 0225 } 0226 0227 bool DownloadQueueSet::jobIsBlackListed( const QUrl& sourceUrl ) const 0228 { 0229 QSet<QString>::const_iterator const pos = 0230 m_jobBlackList.constFind( sourceUrl.toString() ); 0231 return pos != m_jobBlackList.constEnd(); 0232 } 0233 0234 0235 inline bool DownloadQueueSet::JobStack::contains( const QString& destinationFileName ) const 0236 { 0237 return m_jobsContent.contains( destinationFileName ); 0238 } 0239 0240 inline int DownloadQueueSet::JobStack::count() const 0241 { 0242 return m_jobs.count(); 0243 } 0244 0245 inline bool DownloadQueueSet::JobStack::isEmpty() const 0246 { 0247 return m_jobs.isEmpty(); 0248 } 0249 0250 inline HttpJob * DownloadQueueSet::JobStack::pop() 0251 { 0252 HttpJob * const job = m_jobs.pop(); 0253 bool const removed = m_jobsContent.remove( job->destinationFileName() ); 0254 Q_UNUSED( removed ); // for Q_ASSERT in release mode 0255 Q_ASSERT( removed ); 0256 return job; 0257 } 0258 0259 inline void DownloadQueueSet::JobStack::push( HttpJob * const job ) 0260 { 0261 m_jobs.push( job ); 0262 m_jobsContent.insert( job->destinationFileName() ); 0263 } 0264 0265 0266 } 0267 0268 #include "moc_DownloadQueueSet.cpp"