From 23cb5e1b950528e717d701446cb736b0e114e8a3 Mon Sep 17 00:00:00 2001 From: Gus Grubba Date: Wed, 8 Feb 2017 21:58:57 -0500 Subject: [PATCH] Dealing with lack of Internet connectivity. --- src/QtLocationPlugin/QGCMapEngine.cpp | 18 +++- src/QtLocationPlugin/QGCMapEngine.h | 4 + src/QtLocationPlugin/QGCMapEngineData.h | 13 ++- src/QtLocationPlugin/QGCMapTileSet.cpp | 11 +- src/QtLocationPlugin/QGCTileCacheWorker.cpp | 39 +++++--- src/QtLocationPlugin/QGCTileCacheWorker.h | 2 + src/QtLocationPlugin/QGeoMapReplyQGC.cpp | 105 ++++++++++++-------- src/QtLocationPlugin/QGeoMapReplyQGC.h | 9 +- src/QtLocationPlugin/QGeoTileFetcherQGC.cpp | 13 +++ src/QtLocationPlugin/QGeoTileFetcherQGC.h | 4 + 10 files changed, 161 insertions(+), 57 deletions(-) diff --git a/src/QtLocationPlugin/QGCMapEngine.cpp b/src/QtLocationPlugin/QGCMapEngine.cpp index 38edfdc74..d23351a11 100644 --- a/src/QtLocationPlugin/QGCMapEngine.cpp +++ b/src/QtLocationPlugin/QGCMapEngine.cpp @@ -130,11 +130,13 @@ QGCMapEngine::QGCMapEngine() , _maxMemCache(0) , _prunning(false) , _cacheWasReset(false) + , _isInternetActive(false) { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType>(); - connect(&_worker, &QGCCacheWorker::updateTotals, this, &QGCMapEngine::_updateTotals); + connect(&_worker, &QGCCacheWorker::updateTotals, this, &QGCMapEngine::_updateTotals); + connect(&_worker, &QGCCacheWorker::internetStatus, this, &QGCMapEngine::_internetStatus); } //----------------------------------------------------------------------------- @@ -483,5 +485,19 @@ QGCCreateTileSetTask::~QGCCreateTileSetTask() delete _tileSet; } +//----------------------------------------------------------------------------- +void +QGCMapEngine::testInternet() +{ + getQGCMapEngine()->addTask(new QGCTestInternetTask()); +} + +//----------------------------------------------------------------------------- +void +QGCMapEngine::_internetStatus(bool active) +{ + _isInternetActive = active; +} + // Resolution math: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale diff --git a/src/QtLocationPlugin/QGCMapEngine.h b/src/QtLocationPlugin/QGCMapEngine.h index 8b38d1300..8ecedd980 100644 --- a/src/QtLocationPlugin/QGCMapEngine.h +++ b/src/QtLocationPlugin/QGCMapEngine.h @@ -86,7 +86,9 @@ public: void setMaxMemCache (quint32 size); const QString getCachePath () { return _cachePath; } const QString getCacheFilename () { return _cacheFile; } + void testInternet (); bool wasCacheReset () { return _cacheWasReset; } + bool isInternetActive () { return _isInternetActive; } UrlFactory* urlFactory () { return _urlFactory; } @@ -103,6 +105,7 @@ public: private slots: void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize); void _pruned (); + void _internetStatus (bool active); signals: void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize); @@ -123,6 +126,7 @@ private: quint32 _maxMemCache; bool _prunning; bool _cacheWasReset; + bool _isInternetActive; }; extern QGCMapEngine* getQGCMapEngine(); diff --git a/src/QtLocationPlugin/QGCMapEngineData.h b/src/QtLocationPlugin/QGCMapEngineData.h index 1e70939ba..5765aa856 100644 --- a/src/QtLocationPlugin/QGCMapEngineData.h +++ b/src/QtLocationPlugin/QGCMapEngineData.h @@ -110,6 +110,7 @@ public: enum TaskType { taskInit, + taskTestInternet, taskCacheTile, taskFetchTile, taskFetchTileSets, @@ -129,7 +130,7 @@ public: virtual TaskType type () { return _type; } - void setError(QString errorString) + void setError(QString errorString = QString()) { emit error(_type, errorString); } @@ -141,6 +142,16 @@ private: TaskType _type; }; +//----------------------------------------------------------------------------- +class QGCTestInternetTask : public QGCMapTask +{ + Q_OBJECT +public: + QGCTestInternetTask() + : QGCMapTask(QGCMapTask::taskTestInternet) + {} +}; + //----------------------------------------------------------------------------- class QGCFetchTileSetTask : public QGCMapTask { diff --git a/src/QtLocationPlugin/QGCMapTileSet.cpp b/src/QtLocationPlugin/QGCMapTileSet.cpp index 71f770f3c..f5c0e1082 100644 --- a/src/QtLocationPlugin/QGCMapTileSet.cpp +++ b/src/QtLocationPlugin/QGCMapTileSet.cpp @@ -232,11 +232,20 @@ void QGCCachedTileSet::_prepareDownload() _tilesToDownload.removeFirst(); QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(tile->type(), tile->x(), tile->y(), tile->z(), _networkManager); request.setAttribute(QNetworkRequest::User, tile->hash()); +#if !defined(__mobile__) + QNetworkProxy proxy = _networkManager->proxy(); + QNetworkProxy tProxy; + tProxy.setType(QNetworkProxy::DefaultProxy); + _networkManager->setProxy(tProxy); +#endif QNetworkReply* reply = _networkManager->get(request); reply->setParent(0); connect(reply, &QNetworkReply::finished, this, &QGCCachedTileSet::_networkReplyFinished); connect(reply, static_cast(&QNetworkReply::error), this, &QGCCachedTileSet::_networkReplyError); _replies.insert(tile->hash(), reply); +#if !defined(__mobile__) + _networkManager->setProxy(proxy); +#endif delete tile; //-- Refill queue if running low if(!_batchRequested && !_noMoreTiles && _tilesToDownload.count() < (QGCMapEngine::concurrentDownloads(_type) * 10)) { @@ -309,7 +318,7 @@ QGCCachedTileSet::_networkReplyError(QNetworkReply::NetworkError error) if (!reply) { return; } - //-- Upodate error count + //-- Update error count _errorCount++; emit errorCountChanged(); //-- Get tile hash diff --git a/src/QtLocationPlugin/QGCTileCacheWorker.cpp b/src/QtLocationPlugin/QGCTileCacheWorker.cpp index 391042684..254e4c9e2 100644 --- a/src/QtLocationPlugin/QGCTileCacheWorker.cpp +++ b/src/QtLocationPlugin/QGCTileCacheWorker.cpp @@ -93,20 +93,15 @@ QGCCacheWorker::enqueueTask(QGCMapTask* task) task->deleteLater(); return false; } - if(!_taskQueue.contains(task)) - { - _mutex.lock(); - _taskQueue.enqueue(task); - _mutex.unlock(); - if(this->isRunning()) { - _waitc.wakeAll(); - } else { - this->start(QThread::NormalPriority); - } - return true; + _mutex.lock(); + _taskQueue.enqueue(task); + _mutex.unlock(); + if(this->isRunning()) { + _waitc.wakeAll(); + } else { + this->start(QThread::HighPriority); } - //-- Should never happen - return false; + return true; } //----------------------------------------------------------------------------- @@ -158,6 +153,9 @@ QGCCacheWorker::run() case QGCMapTask::taskReset: _resetCacheDatabase(task); break; + case QGCMapTask::taskTestInternet: + _testInternet(); + break; } task->deleteLater(); //-- Check for update timeout @@ -662,6 +660,7 @@ QGCCacheWorker::_init() qCritical() << "Could not find suitable cache directory."; _failed = true; } + _testInternet(); return _failed; } @@ -749,3 +748,17 @@ QGCCacheWorker::_createDB() } _failed = !_valid; } + +//----------------------------------------------------------------------------- +void +QGCCacheWorker::_testInternet() +{ + QTcpSocket socket; + socket.connectToHost("8.8.8.8", 53); + if (socket.waitForConnected(2500)) { + emit internetStatus(true); + return; + } + qWarning() << "No Internet Access"; + emit internetStatus(false); +} diff --git a/src/QtLocationPlugin/QGCTileCacheWorker.h b/src/QtLocationPlugin/QGCTileCacheWorker.h index da63535fa..1b87e1d4f 100644 --- a/src/QtLocationPlugin/QGCTileCacheWorker.h +++ b/src/QtLocationPlugin/QGCTileCacheWorker.h @@ -59,6 +59,7 @@ private: void _deleteTileSet (QGCMapTask* mtask); void _resetCacheDatabase (QGCMapTask* mtask); void _pruneCache (QGCMapTask* mtask); + void _testInternet (); quint64 _findTile (const QString hash); bool _findTileSetID (const QString name, quint64& setID); @@ -70,6 +71,7 @@ private: signals: void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize); + void internetStatus (bool active); private: QQueue _taskQueue; diff --git a/src/QtLocationPlugin/QGeoMapReplyQGC.cpp b/src/QtLocationPlugin/QGeoMapReplyQGC.cpp index 066b12356..c86252266 100644 --- a/src/QtLocationPlugin/QGeoMapReplyQGC.cpp +++ b/src/QtLocationPlugin/QGeoMapReplyQGC.cpp @@ -46,11 +46,14 @@ #include "QGCMapEngine.h" #include "QGeoMapReplyQGC.h" +#include "QGeoTileFetcherQGC.h" #include #include #include +int QGeoTiledMapReplyQGC::_requestCount = 0; + //----------------------------------------------------------------------------- QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager, const QNetworkRequest &request, const QGeoTileSpec &spec, QObject *parent) : QGeoTiledMapReply(spec, parent) @@ -59,15 +62,7 @@ QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager , _networkManager(networkManager) { if(_request.url().isEmpty()) { - if(!_badMapBox.size()) { - QFile b(":/res/notile.png"); - if(b.open(QFile::ReadOnly)) - _badMapBox = b.readAll(); - } - setMapImageData(_badMapBox); - setMapImageFormat("png"); - setFinished(true); - setCached(false); + _returnBadTile(); } else { QGCFetchTileTask* task = getQGCMapEngine()->createFetchTileTask((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom()); connect(task, &QGCFetchTileTask::tileFetched, this, &QGeoTiledMapReplyQGC::cacheReply); @@ -78,31 +73,49 @@ QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager //----------------------------------------------------------------------------- QGeoTiledMapReplyQGC::~QGeoTiledMapReplyQGC() +{ + _clearReply(); +} + +//----------------------------------------------------------------------------- +void +QGeoTiledMapReplyQGC::_clearReply() { if (_reply) { _reply->deleteLater(); _reply = 0; + _requestCount--; } } + //----------------------------------------------------------------------------- void -QGeoTiledMapReplyQGC::abort() +QGeoTiledMapReplyQGC::_returnBadTile() { - if (_reply) - _reply->abort(); + if(!_badMapBox.size()) { + QFile b(":/res/notile.png"); + if(b.open(QFile::ReadOnly)) + _badMapBox = b.readAll(); + } + setMapImageData(_badMapBox); + setMapImageFormat("png"); + setFinished(true); + setCached(false); } //----------------------------------------------------------------------------- void -QGeoTiledMapReplyQGC::replyDestroyed() +QGeoTiledMapReplyQGC::abort() { - _reply = 0; + if (_reply) + _reply->abort(); } //----------------------------------------------------------------------------- void QGeoTiledMapReplyQGC::networkReplyFinished() { + _timer.stop(); if (!_reply) { return; } @@ -117,51 +130,54 @@ QGeoTiledMapReplyQGC::networkReplyFinished() getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format); } setFinished(true); - _reply->deleteLater(); - _reply = 0; + _clearReply(); } //----------------------------------------------------------------------------- void QGeoTiledMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error) { + _timer.stop(); if (!_reply) { return; } if (error != QNetworkReply::OperationCanceledError) { qWarning() << "Fetch tile error:" << _reply->errorString(); } - _reply->deleteLater(); - _reply = 0; - if(!_badTile.size()) { - QFile b(":/res/notile.png"); - if(b.open(QFile::ReadOnly)) - _badTile = b.readAll(); - } - setMapImageData(_badTile); - setMapImageFormat("png"); - setFinished(true); - setCached(false); + _returnBadTile(); + _clearReply(); } //----------------------------------------------------------------------------- void QGeoTiledMapReplyQGC::cacheError(QGCMapTask::TaskType type, QString /*errorString*/) { - if(type != QGCMapTask::taskFetchTile) { - qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task"; + if(_networkManager->networkAccessible() < QNetworkAccessManager::Accessible || !getQGCMapEngine()->isInternetActive()) { + _returnBadTile(); + } else { + if(type != QGCMapTask::taskFetchTile) { + qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task"; + } + //-- Tile not in cache. Get it off the Internet. +#if !defined(__mobile__) + QNetworkProxy proxy = _networkManager->proxy(); + QNetworkProxy tProxy; + tProxy.setType(QNetworkProxy::DefaultProxy); + _networkManager->setProxy(tProxy); +#endif + _reply = _networkManager->get(_request); + _reply->setParent(0); + connect(_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); + connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError))); +#if !defined(__mobile__) + _networkManager->setProxy(proxy); +#endif + //- Wait for an answer up to 10 seconds + connect(&_timer, &QTimer::timeout, this, &QGeoTiledMapReplyQGC::timeout); + _timer.setSingleShot(true); + _timer.start(10000); + _requestCount++; } - //-- Tile not in cache. Get it off the Internet. - QNetworkProxy proxy = _networkManager->proxy(); - QNetworkProxy tProxy; - tProxy.setType(QNetworkProxy::DefaultProxy); - _networkManager->setProxy(tProxy); - _reply = _networkManager->get(_request); - _reply->setParent(0); - connect(_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); - connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError))); - connect(_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed())); - _networkManager->setProxy(proxy); } //----------------------------------------------------------------------------- @@ -174,3 +190,12 @@ QGeoTiledMapReplyQGC::cacheReply(QGCCacheTile* tile) setCached(true); tile->deleteLater(); } + +//----------------------------------------------------------------------------- +void +QGeoTiledMapReplyQGC::timeout() +{ + if(_reply) { + _reply->abort(); + } +} diff --git a/src/QtLocationPlugin/QGeoMapReplyQGC.h b/src/QtLocationPlugin/QGeoMapReplyQGC.h index b66791090..46c38e529 100644 --- a/src/QtLocationPlugin/QGeoMapReplyQGC.h +++ b/src/QtLocationPlugin/QGeoMapReplyQGC.h @@ -49,6 +49,7 @@ #include #include +#include #include "QGCMapEngineData.h" @@ -61,11 +62,15 @@ public: void abort(); private slots: - void replyDestroyed (); void networkReplyFinished (); void networkReplyError (QNetworkReply::NetworkError error); void cacheReply (QGCCacheTile* tile); void cacheError (QGCMapTask::TaskType type, QString errorString); + void timeout (); + +private: + void _clearReply (); + void _returnBadTile (); private: QNetworkReply* _reply; @@ -73,6 +78,8 @@ private: QNetworkAccessManager* _networkManager; QByteArray _badMapBox; QByteArray _badTile; + QTimer _timer; + static int _requestCount; }; #endif // QGEOMAPREPLYQGC_H diff --git a/src/QtLocationPlugin/QGeoTileFetcherQGC.cpp b/src/QtLocationPlugin/QGeoTileFetcherQGC.cpp index 485154716..1b38673ce 100644 --- a/src/QtLocationPlugin/QGeoTileFetcherQGC.cpp +++ b/src/QtLocationPlugin/QGeoTileFetcherQGC.cpp @@ -57,6 +57,10 @@ QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent) : QGeoTileFetcher(parent) , _networkManager(new QNetworkAccessManager(this)) { + //-- Check internet status every 30 seconds or so + connect(&_timer, &QTimer::timeout, this, &QGeoTileFetcherQGC::timeout); + _timer.setSingleShot(false); + _timer.start(30000); } //----------------------------------------------------------------------------- @@ -73,3 +77,12 @@ QGeoTileFetcherQGC::getTileImage(const QGeoTileSpec &spec) QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom(), _networkManager); return new QGeoTiledMapReplyQGC(_networkManager, request, spec); } + +//----------------------------------------------------------------------------- +void +QGeoTileFetcherQGC::timeout() +{ + if(!getQGCMapEngine()->isInternetActive()) { + getQGCMapEngine()->testInternet(); + } +} diff --git a/src/QtLocationPlugin/QGeoTileFetcherQGC.h b/src/QtLocationPlugin/QGeoTileFetcherQGC.h index 54f507a7a..9c8663324 100644 --- a/src/QtLocationPlugin/QGeoTileFetcherQGC.h +++ b/src/QtLocationPlugin/QGeoTileFetcherQGC.h @@ -48,6 +48,7 @@ #define QGEOTILEFETCHERQGC_H #include +#include #include "QGCMapUrlEngine.h" class QGeoTiledMappingManagerEngine; @@ -59,10 +60,13 @@ class QGeoTileFetcherQGC : public QGeoTileFetcher public: explicit QGeoTileFetcherQGC (QGeoTiledMappingManagerEngine *parent = 0); ~QGeoTileFetcherQGC(); +public slots: + void timeout (); private: QGeoTiledMapReply* getTileImage (const QGeoTileSpec &spec); private: QNetworkAccessManager* _networkManager; + QTimer _timer; }; #endif // QGEOTILEFETCHERQGC_H -- 2.22.0