Marble

DownloadQueueSet.cpp
1 // SPDX-FileCopyrightText: 2009 Jens-Michael Hoffmann <[email protected]>
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 
11 namespace Marble
12 {
13 
14 DownloadQueueSet::DownloadQueueSet( QObject * const parent )
15  : QObject( parent )
16 {
17 }
18 
19 DownloadQueueSet::DownloadQueueSet( DownloadPolicy const & policy, QObject * const parent )
20  : QObject( parent ),
21  m_downloadPolicy( policy )
22 {
23 }
24 
25 DownloadQueueSet::~DownloadQueueSet()
26 {
27  // todo: delete HttpJobs
28 }
29 
30 DownloadPolicy DownloadQueueSet::downloadPolicy() const
31 {
32  return m_downloadPolicy;
33 }
34 
35 void DownloadQueueSet::setDownloadPolicy( DownloadPolicy const & policy )
36 {
37  m_downloadPolicy = policy;
38 }
39 
40 bool 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 
65 void 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 
74 void 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 
84 void 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 
94 void 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 
114 void DownloadQueueSet::finishJob( HttpJob * job, const QByteArray& data )
115 {
116  mDebug() << "finishJob: " << 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 
125 void DownloadQueueSet::redirectJob( HttpJob * job, const QUrl& newSourceUrl )
126 {
127  mDebug() << "jobRedirected:" << 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 
136 void 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 
165 void 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  */
187 void 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 
198 bool 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 
210 inline bool DownloadQueueSet::jobIsQueued( QString const & destinationFileName ) const
211 {
212  return m_jobs.contains( destinationFileName );
213 }
214 
215 bool 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 
227 bool DownloadQueueSet::jobIsBlackListed( const QUrl& sourceUrl ) const
228 {
230  m_jobBlackList.constFind( sourceUrl.toString() );
231  return pos != m_jobBlackList.constEnd();
232 }
233 
234 
235 inline bool DownloadQueueSet::JobStack::contains( const QString& destinationFileName ) const
236 {
237  return m_jobsContent.contains( destinationFileName );
238 }
239 
240 inline int DownloadQueueSet::JobStack::count() const
241 {
242  return m_jobs.count();
243 }
244 
245 inline bool DownloadQueueSet::JobStack::isEmpty() const
246 {
247  return m_jobs.isEmpty();
248 }
249 
250 inline 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 
259 inline 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"
T & first()
T dequeue()
int count(const T &value) const const
void push_back(const T &value)
QList::const_iterator constBegin() const const
int size() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int size() const const
QString toString(QUrl::FormattingOptions options) const const
bool removeOne(const T &value)
QSet::const_iterator constEnd() const const
bool isEmpty() const const
Binds a QML item to a specific geodetic location in screen coordinates.
QList::const_iterator constEnd() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QSet::const_iterator constFind(const T &value) const const
QSet::iterator insert(const T &value)
const QList< QKeySequence > & end()
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
void enqueue(const T &t)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 6 2023 03:58:34 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.