23 #include <QElapsedTimer> 
   24 #include <QNetworkReply> 
   29 QgsTileDownloadManagerWorker::QgsTileDownloadManagerWorker( 
QgsTileDownloadManager *manager, QObject *parent )
 
   34   connect( &mIdleTimer, &QTimer::timeout, 
this, &QgsTileDownloadManagerWorker::idleTimerTimeout );
 
   37 void QgsTileDownloadManagerWorker::startIdleTimer()
 
   39   if ( !mIdleTimer.isActive() )
 
   41     mIdleTimer.start( mManager->mIdleThreadTimeoutMs );
 
   45 void QgsTileDownloadManagerWorker::queueUpdated()
 
   47   QMutexLocker locker( &mManager->mMutex );
 
   49   if ( mManager->mShuttingDown )
 
   51     for ( 
auto it = mManager->mQueue.begin(); it != mManager->mQueue.end(); ++it )
 
   53       it->networkReply->abort();
 
   60   if ( mIdleTimer.isActive() && !mManager->mQueue.isEmpty() )
 
   66   for ( 
auto it = mManager->mQueue.begin(); it != mManager->mQueue.end(); ++it )
 
   68     if ( !it->networkReply )
 
   70       QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: starting request: " ) + it->request.url().toString(), 2 );
 
   74       connect( it->networkReply, &QNetworkReply::finished, it->objWorker, &QgsTileDownloadManagerReplyWorkerObject::replyFinished );
 
   76       ++mManager->mStats.networkRequestsStarted;
 
   81 void QgsTileDownloadManagerWorker::quitThread()
 
   83   QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: stopping worker thread" ), 2 );
 
   85   mManager->mWorker->deleteLater();
 
   86   mManager->mWorker = 
nullptr;
 
   89   mManager->mWorkerThread->quit();
 
   90   mManager->mWorkerThread = 
nullptr;
 
   91   mManager->mShuttingDown = 
false;
 
   94 void QgsTileDownloadManagerWorker::idleTimerTimeout()
 
   96   QMutexLocker locker( &mManager->mMutex );
 
   97   Q_ASSERT( mManager->mQueue.isEmpty() );
 
  105 void QgsTileDownloadManagerReplyWorkerObject::replyFinished()
 
  107   QMutexLocker locker( &mManager->mMutex );
 
  109   QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: internal reply finished: " ) + mRequest.url().toString(), 2 );
 
  111   QNetworkReply *reply = qobject_cast<QNetworkReply *>( sender() );
 
  114   if ( reply->error() == QNetworkReply::NoError )
 
  116     ++mManager->mStats.networkRequestsOk;
 
  118     data = reply->readAll();
 
  122     ++mManager->mStats.networkRequestsFailed;
 
  125   emit finished( data, reply->error(), reply->errorString() );
 
  127   reply->deleteLater();
 
  132   mManager->removeEntry( mRequest );
 
  134   if ( mManager->mQueue.isEmpty() )
 
  137     mManager->mWorker->startIdleTimer();
 
  147 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) 
  148   : mMutex( QMutex::Recursive )
 
  161   QMutexLocker locker( &mMutex );
 
  165     QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: starting worker thread" ), 2 );
 
  166     mWorkerThread = 
new QThread;
 
  168     mWorker->moveToThread( mWorkerThread );
 
  169     QObject::connect( mWorkerThread, &QThread::finished, mWorker, &QObject::deleteLater );
 
  170     mWorkerThread->start();
 
  177   QgsTileDownloadManager::QueueEntry entry = findEntryForRequest( request );
 
  178   if ( !entry.isValid() )
 
  180     QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: get (new entry): " ) + request.url().toString(), 2 );
 
  182     entry.request = request;
 
  184     entry.objWorker->moveToThread( mWorkerThread );
 
  186     QObject::connect( entry.objWorker, &QgsTileDownloadManagerReplyWorkerObject::finished, reply, &QgsTileDownloadManagerReply::requestFinished );  
 
  192     QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: get (existing entry): " ) + request.url().toString(), 2 );
 
  194     QObject::connect( entry.objWorker, &QgsTileDownloadManagerReplyWorkerObject::finished, reply, &QgsTileDownloadManagerReply::requestFinished );  
 
  199   signalQueueModified();
 
  206   QMutexLocker locker( &mMutex );
 
  208   return !mQueue.isEmpty();
 
  216   while ( msec == -1 || t.elapsed() < msec )
 
  219       QMutexLocker locker( &mMutex );
 
  220       if ( mQueue.isEmpty() )
 
  223     QThread::currentThread()->usleep( 1000 );
 
  232     QMutexLocker locker( &mMutex );
 
  233     if ( !mWorkerThread )
 
  237     mShuttingDown = 
true;
 
  238     signalQueueModified();
 
  245       QMutexLocker locker( &mMutex );
 
  246       if ( !mWorkerThread )
 
  250     QThread::currentThread()->usleep( 1000 );
 
  256   return mWorkerThread && mWorkerThread->isRunning();
 
  261   QMutexLocker locker( &mMutex );
 
  265 QgsTileDownloadManager::QueueEntry QgsTileDownloadManager::findEntryForRequest( 
const QNetworkRequest &request )
 
  267   for ( 
auto it = mQueue.constBegin(); it != mQueue.constEnd(); ++it )
 
  269     if ( it->request.url() == request.url() )
 
  272   return QgsTileDownloadManager::QueueEntry();
 
  275 void QgsTileDownloadManager::addEntry( 
const QgsTileDownloadManager::QueueEntry &entry )
 
  277   for ( 
auto it = mQueue.constBegin(); it != mQueue.constEnd(); ++it )
 
  279     Q_ASSERT( entry.request.url() != it->request.url() );
 
  282   mQueue.append( entry );
 
  285 void QgsTileDownloadManager::updateEntry( 
const QgsTileDownloadManager::QueueEntry &entry )
 
  287   for ( 
auto it = mQueue.begin(); it != mQueue.end(); ++it )
 
  289     if ( entry.request.url() == it->request.url() )
 
  298 void QgsTileDownloadManager::removeEntry( 
const QNetworkRequest &request )
 
  301   for ( 
auto it = mQueue.constBegin(); it != mQueue.constEnd(); ++it, ++i )
 
  303     if ( it->request.url() == request.url() )
 
  305       mQueue.removeAt( i );
 
  312 void QgsTileDownloadManager::signalQueueModified()
 
  314   QMetaObject::invokeMethod( mWorker, &QgsTileDownloadManagerWorker::queueUpdated, Qt::QueuedConnection );
 
  321 QgsTileDownloadManagerReply::QgsTileDownloadManagerReply( 
QgsTileDownloadManager *manager, 
const QNetworkRequest &request )
 
  322   : mManager( manager )
 
  323   , mRequest( request )
 
  329   QMutexLocker locker( &mManager->mMutex );
 
  333     QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: reply deleted before finished: " ) + mRequest.url().toString(), 2 );
 
  339 void QgsTileDownloadManagerReply::requestFinished( QByteArray data, QNetworkReply::NetworkError error, 
const QString &errorString )
 
  341   QgsDebugMsgLevel( QStringLiteral( 
"Tile download manager: reply finished: " ) + mRequest.url().toString(), 2 );
 
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Reply object for tile download manager requests returned from calls to QgsTileDownloadManager::get().
QString errorString() const
Returns error string (only valid when already finished)
~QgsTileDownloadManagerReply()
QByteArray data() const
Returns binary data returned in the reply (only valid when already finished)
QNetworkReply::NetworkError error() const
Returns error code (only valid when already finished)
void finished()
Emitted when the reply has finished (either with a success or with a failure)
Encapsulates any statistics we would like to keep about requests.
int requestsMerged
How many requests were same as some other pending request and got "merged".
int requestsEarlyDeleted
How many requests were deleted early by the client (i.e. lost interest)
int requestsTotal
How many requests were done through the download manager.
Tile download manager handles downloads of map tiles for the purpose of map rendering.
bool hasWorkerThreadRunning() const
Returns whether the worker thread is running currently (it may be stopped if there were no requests r...
friend class QgsTileDownloadManagerReplyWorkerObject
bool waitForPendingRequests(int msec=-1)
Blocks the current thread until the queue is empty.
QgsTileDownloadManagerReply * get(const QNetworkRequest &request)
Starts a request.
friend class QgsTileDownloadManagerReply
bool hasPendingRequests() const
Returns whether there are any pending requests in the queue.
void resetStatistics()
Resets statistics of numbers of queries handled by this class.
friend class QgsTileDownloadManagerWorker
~QgsTileDownloadManager()
void shutdown()
Asks the worker thread to stop and blocks until it is not stopped.
#define QgsDebugMsgLevel(str, level)