Marble

DownloadQueueSet.cpp
1// SPDX-FileCopyrightText: 2009 Jens-Michael Hoffmann <jmho@c-xx.com>
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4
5#include "DownloadQueueSet.h"
6
7#include "MarbleDebug.h"
8
9#include "HttpJob.h"
10
11namespace Marble
12{
13
14DownloadQueueSet::DownloadQueueSet( QObject * const parent )
15 : QObject( parent )
16{
17}
18
19DownloadQueueSet::DownloadQueueSet( DownloadPolicy const & policy, QObject * const parent )
20 : QObject( parent ),
21 m_downloadPolicy( policy )
22{
23}
24
25DownloadQueueSet::~DownloadQueueSet()
26{
27 // todo: delete HttpJobs
28}
29
30DownloadPolicy DownloadQueueSet::downloadPolicy() const
31{
32 return m_downloadPolicy;
33}
34
35void DownloadQueueSet::setDownloadPolicy( DownloadPolicy const & policy )
36{
37 m_downloadPolicy = policy;
38}
39
40bool DownloadQueueSet::canAcceptJob( const QUrl& sourceUrl,
41 const QString& destinationFileName ) const
42{
43 if ( jobIsQueued( destinationFileName )) {
44 mDebug() << "Download rejected: It's in the queue already:"
45 << destinationFileName;
46 return false;
47 }
48 if ( jobIsWaitingForRetry( destinationFileName )) {
49 mDebug() << "Download rejected: Will try to download again in some time:"
50 << destinationFileName;
51 return false;
52 }
53 if ( jobIsActive( destinationFileName )) {
54 mDebug() << "Download rejected: It's being downloaded already:"
55 << destinationFileName;
56 return false;
57 }
58 if ( jobIsBlackListed( sourceUrl )) {
59 mDebug() << "Download rejected: Blacklisted.";
60 return false;
61 }
62 return true;
63}
64
65void DownloadQueueSet::addJob( HttpJob * const job )
66{
67 m_jobs.push( job );
68 mDebug() << "addJob: new job queue size:" << m_jobs.count();
69 emit jobAdded();
70 emit progressChanged( m_activeJobs.size(), m_jobs.count() );
71 activateJobs();
72}
73
74void DownloadQueueSet::activateJobs()
75{
76 while ( !m_jobs.isEmpty()
77 && m_activeJobs.count() < m_downloadPolicy.maximumConnections() )
78 {
79 HttpJob * const job = m_jobs.pop();
80 activateJob( job );
81 }
82}
83
84void DownloadQueueSet::retryJobs()
85{
86 while ( !m_retryQueue.isEmpty() ) {
87 HttpJob * const job = m_retryQueue.dequeue();
88 mDebug() << "Requeuing" << job->destinationFileName();
89 // FIXME: addJob calls activateJobs every time
90 addJob( job );
91 }
92}
93
94void DownloadQueueSet::purgeJobs()
95{
96 // purge all waiting jobs
97 while( !m_jobs.isEmpty() ) {
98 HttpJob * const job = m_jobs.pop();
99 job->deleteLater();
100 }
101
102 // purge all retry jobs
103 qDeleteAll( m_retryQueue );
104 m_retryQueue.clear();
105
106 // cancel all current jobs
107 while( !m_activeJobs.isEmpty() ) {
108 deactivateJob( m_activeJobs.first() );
109 }
110
111 emit progressChanged( m_activeJobs.size(), m_jobs.count() );
112}
113
114void DownloadQueueSet::finishJob( HttpJob * job, const QByteArray& data )
115{
116 mDebug() << job->sourceUrl() << job->destinationFileName();
117
118 deactivateJob( job );
119 emit jobRemoved();
120 emit jobFinished( data, job->destinationFileName(), job->initiatorId() );
121 job->deleteLater();
122 activateJobs();
123}
124
125void DownloadQueueSet::redirectJob( HttpJob * job, const QUrl& newSourceUrl )
126{
127 mDebug() << job->sourceUrl() << " -> " << newSourceUrl;
128
129 deactivateJob( job );
130 emit jobRemoved();
131 emit jobRedirected( newSourceUrl, job->destinationFileName(), job->initiatorId(),
132 job->downloadUsage() );
133 job->deleteLater();
134}
135
136void DownloadQueueSet::retryOrBlacklistJob( HttpJob * job, const int errorCode )
137{
138 Q_ASSERT( errorCode != 0 );
139 Q_ASSERT( !m_retryQueue.contains( job ));
140
141 deactivateJob( job );
142 emit jobRemoved();
143
144 if ( job->tryAgain() ) {
145 mDebug() << QString( "Download of %1 to %2 failed, but trying again soon" )
146 .arg( job->sourceUrl().toString(), job->destinationFileName() );
147 m_retryQueue.enqueue( job );
148 emit jobRetry();
149 }
150 else {
151 mDebug() << "JOB-address: " << job
152 << "Blacklist-size:" << m_jobBlackList.size()
153 << "err:" << errorCode;
154 m_jobBlackList.insert( job->sourceUrl().toString() );
155 mDebug() << QString( "Download of %1 Blacklisted. "
156 "Number of blacklist items: %2" )
157 .arg( job->destinationFileName() )
158 .arg( m_jobBlackList.size() );
159
160 job->deleteLater();
161 }
162 activateJobs();
163}
164
165void DownloadQueueSet::activateJob( HttpJob * const job )
166{
167 m_activeJobs.push_back( job );
168 emit progressChanged( m_activeJobs.size(), m_jobs.count() );
169
170 connect( job, SIGNAL(jobDone(HttpJob*,int)),
171 SLOT(retryOrBlacklistJob(HttpJob*,int)));
172 connect( job, SIGNAL(redirected(HttpJob*,QUrl)),
173 SLOT(redirectJob(HttpJob*,QUrl)));
174 connect( job, SIGNAL(dataReceived(HttpJob*,QByteArray)),
175 SLOT(finishJob(HttpJob*,QByteArray)));
176
177 job->execute();
178}
179
180/**
181 pre condition: - job is in m_activeJobs
182 - job's signal are connected to our slots
183 post condition: - job is not in m_activeJobs anymore (and btw not
184 in any other queue)
185 - job's signals are disconnected from our slots
186 */
187void DownloadQueueSet::deactivateJob( HttpJob * const job )
188{
189 const bool disconnected = job->disconnect();
190 Q_ASSERT( disconnected );
191 Q_UNUSED( disconnected ); // for Q_ASSERT in release mode
192 const bool removed = m_activeJobs.removeOne( job );
193 Q_ASSERT( removed );
194 Q_UNUSED( removed ); // for Q_ASSERT in release mode
195 emit progressChanged( m_activeJobs.size(), m_jobs.count() );
196}
197
198bool DownloadQueueSet::jobIsActive( QString const & destinationFileName ) const
199{
200 QList<HttpJob*>::const_iterator pos = m_activeJobs.constBegin();
201 QList<HttpJob*>::const_iterator const end = m_activeJobs.constEnd();
202 for (; pos != end; ++pos) {
203 if ( (*pos)->destinationFileName() == destinationFileName ) {
204 return true;
205 }
206 }
207 return false;
208}
209
210inline bool DownloadQueueSet::jobIsQueued( QString const & destinationFileName ) const
211{
212 return m_jobs.contains( destinationFileName );
213}
214
215bool DownloadQueueSet::jobIsWaitingForRetry( QString const & destinationFileName ) const
216{
217 QList<HttpJob*>::const_iterator pos = m_retryQueue.constBegin();
218 QList<HttpJob*>::const_iterator const end = m_retryQueue.constEnd();
219 for (; pos != end; ++pos) {
220 if ( (*pos)->destinationFileName() == destinationFileName ) {
221 return true;
222 }
223 }
224 return false;
225}
226
227bool DownloadQueueSet::jobIsBlackListed( const QUrl& sourceUrl ) const
228{
230 m_jobBlackList.constFind( sourceUrl.toString() );
231 return pos != m_jobBlackList.constEnd();
232}
233
234
235inline bool DownloadQueueSet::JobStack::contains( const QString& destinationFileName ) const
236{
237 return m_jobsContent.contains( destinationFileName );
238}
239
240inline int DownloadQueueSet::JobStack::count() const
241{
242 return m_jobs.count();
243}
244
245inline bool DownloadQueueSet::JobStack::isEmpty() const
246{
247 return m_jobs.isEmpty();
248}
249
250inline HttpJob * DownloadQueueSet::JobStack::pop()
251{
252 HttpJob * const job = m_jobs.pop();
253 bool const removed = m_jobsContent.remove( job->destinationFileName() );
254 Q_UNUSED( removed ); // for Q_ASSERT in release mode
255 Q_ASSERT( removed );
256 return job;
257}
258
259inline void DownloadQueueSet::JobStack::push( HttpJob * const job )
260{
261 m_jobs.push( job );
262 m_jobsContent.insert( job->destinationFileName() );
263}
264
265
266}
267
268#include "moc_DownloadQueueSet.cpp"
const QList< QKeySequence > & end()
Binds a QML item to a specific geodetic location in screen coordinates.
QString arg(Args &&... args) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QString toString(FormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.