Commit d48c0084 authored by Gus Grubba's avatar Gus Grubba Committed by GitHub

Merge pull request #4531 from dogmaphobic/tileFetching

Dealing with lack of Internet connectivity.
parents e4e52536 23cb5e1b
...@@ -130,11 +130,13 @@ QGCMapEngine::QGCMapEngine() ...@@ -130,11 +130,13 @@ QGCMapEngine::QGCMapEngine()
, _maxMemCache(0) , _maxMemCache(0)
, _prunning(false) , _prunning(false)
, _cacheWasReset(false) , _cacheWasReset(false)
, _isInternetActive(false)
{ {
qRegisterMetaType<QGCMapTask::TaskType>(); qRegisterMetaType<QGCMapTask::TaskType>();
qRegisterMetaType<QGCTile>(); qRegisterMetaType<QGCTile>();
qRegisterMetaType<QList<QGCTile*>>(); qRegisterMetaType<QList<QGCTile*>>();
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() ...@@ -483,5 +485,19 @@ QGCCreateTileSetTask::~QGCCreateTileSetTask()
delete _tileSet; 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 // Resolution math: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale
...@@ -86,7 +86,9 @@ public: ...@@ -86,7 +86,9 @@ public:
void setMaxMemCache (quint32 size); void setMaxMemCache (quint32 size);
const QString getCachePath () { return _cachePath; } const QString getCachePath () { return _cachePath; }
const QString getCacheFilename () { return _cacheFile; } const QString getCacheFilename () { return _cacheFile; }
void testInternet ();
bool wasCacheReset () { return _cacheWasReset; } bool wasCacheReset () { return _cacheWasReset; }
bool isInternetActive () { return _isInternetActive; }
UrlFactory* urlFactory () { return _urlFactory; } UrlFactory* urlFactory () { return _urlFactory; }
...@@ -103,6 +105,7 @@ public: ...@@ -103,6 +105,7 @@ public:
private slots: private slots:
void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize); void _updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
void _pruned (); void _pruned ();
void _internetStatus (bool active);
signals: signals:
void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize); void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
...@@ -123,6 +126,7 @@ private: ...@@ -123,6 +126,7 @@ private:
quint32 _maxMemCache; quint32 _maxMemCache;
bool _prunning; bool _prunning;
bool _cacheWasReset; bool _cacheWasReset;
bool _isInternetActive;
}; };
extern QGCMapEngine* getQGCMapEngine(); extern QGCMapEngine* getQGCMapEngine();
......
...@@ -110,6 +110,7 @@ public: ...@@ -110,6 +110,7 @@ public:
enum TaskType { enum TaskType {
taskInit, taskInit,
taskTestInternet,
taskCacheTile, taskCacheTile,
taskFetchTile, taskFetchTile,
taskFetchTileSets, taskFetchTileSets,
...@@ -129,7 +130,7 @@ public: ...@@ -129,7 +130,7 @@ public:
virtual TaskType type () { return _type; } virtual TaskType type () { return _type; }
void setError(QString errorString) void setError(QString errorString = QString())
{ {
emit error(_type, errorString); emit error(_type, errorString);
} }
...@@ -141,6 +142,16 @@ private: ...@@ -141,6 +142,16 @@ private:
TaskType _type; TaskType _type;
}; };
//-----------------------------------------------------------------------------
class QGCTestInternetTask : public QGCMapTask
{
Q_OBJECT
public:
QGCTestInternetTask()
: QGCMapTask(QGCMapTask::taskTestInternet)
{}
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class QGCFetchTileSetTask : public QGCMapTask class QGCFetchTileSetTask : public QGCMapTask
{ {
......
...@@ -232,11 +232,20 @@ void QGCCachedTileSet::_prepareDownload() ...@@ -232,11 +232,20 @@ void QGCCachedTileSet::_prepareDownload()
_tilesToDownload.removeFirst(); _tilesToDownload.removeFirst();
QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(tile->type(), tile->x(), tile->y(), tile->z(), _networkManager); QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL(tile->type(), tile->x(), tile->y(), tile->z(), _networkManager);
request.setAttribute(QNetworkRequest::User, tile->hash()); 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); QNetworkReply* reply = _networkManager->get(request);
reply->setParent(0); reply->setParent(0);
connect(reply, &QNetworkReply::finished, this, &QGCCachedTileSet::_networkReplyFinished); connect(reply, &QNetworkReply::finished, this, &QGCCachedTileSet::_networkReplyFinished);
connect(reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &QGCCachedTileSet::_networkReplyError); connect(reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &QGCCachedTileSet::_networkReplyError);
_replies.insert(tile->hash(), reply); _replies.insert(tile->hash(), reply);
#if !defined(__mobile__)
_networkManager->setProxy(proxy);
#endif
delete tile; delete tile;
//-- Refill queue if running low //-- Refill queue if running low
if(!_batchRequested && !_noMoreTiles && _tilesToDownload.count() < (QGCMapEngine::concurrentDownloads(_type) * 10)) { if(!_batchRequested && !_noMoreTiles && _tilesToDownload.count() < (QGCMapEngine::concurrentDownloads(_type) * 10)) {
...@@ -309,7 +318,7 @@ QGCCachedTileSet::_networkReplyError(QNetworkReply::NetworkError error) ...@@ -309,7 +318,7 @@ QGCCachedTileSet::_networkReplyError(QNetworkReply::NetworkError error)
if (!reply) { if (!reply) {
return; return;
} }
//-- Upodate error count //-- Update error count
_errorCount++; _errorCount++;
emit errorCountChanged(); emit errorCountChanged();
//-- Get tile hash //-- Get tile hash
......
...@@ -93,20 +93,15 @@ QGCCacheWorker::enqueueTask(QGCMapTask* task) ...@@ -93,20 +93,15 @@ QGCCacheWorker::enqueueTask(QGCMapTask* task)
task->deleteLater(); task->deleteLater();
return false; return false;
} }
if(!_taskQueue.contains(task))
{
_mutex.lock(); _mutex.lock();
_taskQueue.enqueue(task); _taskQueue.enqueue(task);
_mutex.unlock(); _mutex.unlock();
if(this->isRunning()) { if(this->isRunning()) {
_waitc.wakeAll(); _waitc.wakeAll();
} else { } else {
this->start(QThread::NormalPriority); this->start(QThread::HighPriority);
} }
return true; return true;
}
//-- Should never happen
return false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -158,6 +153,9 @@ QGCCacheWorker::run() ...@@ -158,6 +153,9 @@ QGCCacheWorker::run()
case QGCMapTask::taskReset: case QGCMapTask::taskReset:
_resetCacheDatabase(task); _resetCacheDatabase(task);
break; break;
case QGCMapTask::taskTestInternet:
_testInternet();
break;
} }
task->deleteLater(); task->deleteLater();
//-- Check for update timeout //-- Check for update timeout
...@@ -662,6 +660,7 @@ QGCCacheWorker::_init() ...@@ -662,6 +660,7 @@ QGCCacheWorker::_init()
qCritical() << "Could not find suitable cache directory."; qCritical() << "Could not find suitable cache directory.";
_failed = true; _failed = true;
} }
_testInternet();
return _failed; return _failed;
} }
...@@ -749,3 +748,17 @@ QGCCacheWorker::_createDB() ...@@ -749,3 +748,17 @@ QGCCacheWorker::_createDB()
} }
_failed = !_valid; _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);
}
...@@ -59,6 +59,7 @@ private: ...@@ -59,6 +59,7 @@ private:
void _deleteTileSet (QGCMapTask* mtask); void _deleteTileSet (QGCMapTask* mtask);
void _resetCacheDatabase (QGCMapTask* mtask); void _resetCacheDatabase (QGCMapTask* mtask);
void _pruneCache (QGCMapTask* mtask); void _pruneCache (QGCMapTask* mtask);
void _testInternet ();
quint64 _findTile (const QString hash); quint64 _findTile (const QString hash);
bool _findTileSetID (const QString name, quint64& setID); bool _findTileSetID (const QString name, quint64& setID);
...@@ -70,6 +71,7 @@ private: ...@@ -70,6 +71,7 @@ private:
signals: signals:
void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize); void updateTotals (quint32 totaltiles, quint64 totalsize, quint32 defaulttiles, quint64 defaultsize);
void internetStatus (bool active);
private: private:
QQueue<QGCMapTask*> _taskQueue; QQueue<QGCMapTask*> _taskQueue;
......
...@@ -46,11 +46,14 @@ ...@@ -46,11 +46,14 @@
#include "QGCMapEngine.h" #include "QGCMapEngine.h"
#include "QGeoMapReplyQGC.h" #include "QGeoMapReplyQGC.h"
#include "QGeoTileFetcherQGC.h"
#include <QtLocation/private/qgeotilespec_p.h> #include <QtLocation/private/qgeotilespec_p.h>
#include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkAccessManager>
#include <QFile> #include <QFile>
int QGeoTiledMapReplyQGC::_requestCount = 0;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager, const QNetworkRequest &request, const QGeoTileSpec &spec, QObject *parent) QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager, const QNetworkRequest &request, const QGeoTileSpec &spec, QObject *parent)
: QGeoTiledMapReply(spec, parent) : QGeoTiledMapReply(spec, parent)
...@@ -59,15 +62,7 @@ QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager ...@@ -59,15 +62,7 @@ QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager
, _networkManager(networkManager) , _networkManager(networkManager)
{ {
if(_request.url().isEmpty()) { if(_request.url().isEmpty()) {
if(!_badMapBox.size()) { _returnBadTile();
QFile b(":/res/notile.png");
if(b.open(QFile::ReadOnly))
_badMapBox = b.readAll();
}
setMapImageData(_badMapBox);
setMapImageFormat("png");
setFinished(true);
setCached(false);
} else { } else {
QGCFetchTileTask* task = getQGCMapEngine()->createFetchTileTask((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom()); QGCFetchTileTask* task = getQGCMapEngine()->createFetchTileTask((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom());
connect(task, &QGCFetchTileTask::tileFetched, this, &QGeoTiledMapReplyQGC::cacheReply); connect(task, &QGCFetchTileTask::tileFetched, this, &QGeoTiledMapReplyQGC::cacheReply);
...@@ -78,31 +73,49 @@ QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager ...@@ -78,31 +73,49 @@ QGeoTiledMapReplyQGC::QGeoTiledMapReplyQGC(QNetworkAccessManager *networkManager
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
QGeoTiledMapReplyQGC::~QGeoTiledMapReplyQGC() QGeoTiledMapReplyQGC::~QGeoTiledMapReplyQGC()
{
_clearReply();
}
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::_clearReply()
{ {
if (_reply) { if (_reply) {
_reply->deleteLater(); _reply->deleteLater();
_reply = 0; _reply = 0;
_requestCount--;
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void void
QGeoTiledMapReplyQGC::abort() QGeoTiledMapReplyQGC::_returnBadTile()
{ {
if (_reply) if(!_badMapBox.size()) {
_reply->abort(); QFile b(":/res/notile.png");
if(b.open(QFile::ReadOnly))
_badMapBox = b.readAll();
}
setMapImageData(_badMapBox);
setMapImageFormat("png");
setFinished(true);
setCached(false);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void void
QGeoTiledMapReplyQGC::replyDestroyed() QGeoTiledMapReplyQGC::abort()
{ {
_reply = 0; if (_reply)
_reply->abort();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void void
QGeoTiledMapReplyQGC::networkReplyFinished() QGeoTiledMapReplyQGC::networkReplyFinished()
{ {
_timer.stop();
if (!_reply) { if (!_reply) {
return; return;
} }
...@@ -117,51 +130,54 @@ QGeoTiledMapReplyQGC::networkReplyFinished() ...@@ -117,51 +130,54 @@ QGeoTiledMapReplyQGC::networkReplyFinished()
getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format); getQGCMapEngine()->cacheTile((UrlFactory::MapType)tileSpec().mapId(), tileSpec().x(), tileSpec().y(), tileSpec().zoom(), a, format);
} }
setFinished(true); setFinished(true);
_reply->deleteLater(); _clearReply();
_reply = 0;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void void
QGeoTiledMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error) QGeoTiledMapReplyQGC::networkReplyError(QNetworkReply::NetworkError error)
{ {
_timer.stop();
if (!_reply) { if (!_reply) {
return; return;
} }
if (error != QNetworkReply::OperationCanceledError) { if (error != QNetworkReply::OperationCanceledError) {
qWarning() << "Fetch tile error:" << _reply->errorString(); qWarning() << "Fetch tile error:" << _reply->errorString();
} }
_reply->deleteLater(); _returnBadTile();
_reply = 0; _clearReply();
if(!_badTile.size()) {
QFile b(":/res/notile.png");
if(b.open(QFile::ReadOnly))
_badTile = b.readAll();
}
setMapImageData(_badTile);
setMapImageFormat("png");
setFinished(true);
setCached(false);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void void
QGeoTiledMapReplyQGC::cacheError(QGCMapTask::TaskType type, QString /*errorString*/) QGeoTiledMapReplyQGC::cacheError(QGCMapTask::TaskType type, QString /*errorString*/)
{ {
if(_networkManager->networkAccessible() < QNetworkAccessManager::Accessible || !getQGCMapEngine()->isInternetActive()) {
_returnBadTile();
} else {
if(type != QGCMapTask::taskFetchTile) { if(type != QGCMapTask::taskFetchTile) {
qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task"; qWarning() << "QGeoTiledMapReplyQGC::cacheError() for wrong task";
} }
//-- Tile not in cache. Get it off the Internet. //-- Tile not in cache. Get it off the Internet.
#if !defined(__mobile__)
QNetworkProxy proxy = _networkManager->proxy(); QNetworkProxy proxy = _networkManager->proxy();
QNetworkProxy tProxy; QNetworkProxy tProxy;
tProxy.setType(QNetworkProxy::DefaultProxy); tProxy.setType(QNetworkProxy::DefaultProxy);
_networkManager->setProxy(tProxy); _networkManager->setProxy(tProxy);
#endif
_reply = _networkManager->get(_request); _reply = _networkManager->get(_request);
_reply->setParent(0); _reply->setParent(0);
connect(_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished())); connect(_reply, SIGNAL(finished()), this, SLOT(networkReplyFinished()));
connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError))); connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(networkReplyError(QNetworkReply::NetworkError)));
connect(_reply, SIGNAL(destroyed()), this, SLOT(replyDestroyed())); #if !defined(__mobile__)
_networkManager->setProxy(proxy); _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++;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -174,3 +190,12 @@ QGeoTiledMapReplyQGC::cacheReply(QGCCacheTile* tile) ...@@ -174,3 +190,12 @@ QGeoTiledMapReplyQGC::cacheReply(QGCCacheTile* tile)
setCached(true); setCached(true);
tile->deleteLater(); tile->deleteLater();
} }
//-----------------------------------------------------------------------------
void
QGeoTiledMapReplyQGC::timeout()
{
if(_reply) {
_reply->abort();
}
}
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkReply>
#include <QtLocation/private/qgeotiledmapreply_p.h> #include <QtLocation/private/qgeotiledmapreply_p.h>
#include <QTimer>
#include "QGCMapEngineData.h" #include "QGCMapEngineData.h"
...@@ -61,11 +62,15 @@ public: ...@@ -61,11 +62,15 @@ public:
void abort(); void abort();
private slots: private slots:
void replyDestroyed ();
void networkReplyFinished (); void networkReplyFinished ();
void networkReplyError (QNetworkReply::NetworkError error); void networkReplyError (QNetworkReply::NetworkError error);
void cacheReply (QGCCacheTile* tile); void cacheReply (QGCCacheTile* tile);
void cacheError (QGCMapTask::TaskType type, QString errorString); void cacheError (QGCMapTask::TaskType type, QString errorString);
void timeout ();
private:
void _clearReply ();
void _returnBadTile ();
private: private:
QNetworkReply* _reply; QNetworkReply* _reply;
...@@ -73,6 +78,8 @@ private: ...@@ -73,6 +78,8 @@ private:
QNetworkAccessManager* _networkManager; QNetworkAccessManager* _networkManager;
QByteArray _badMapBox; QByteArray _badMapBox;
QByteArray _badTile; QByteArray _badTile;
QTimer _timer;
static int _requestCount;
}; };
#endif // QGEOMAPREPLYQGC_H #endif // QGEOMAPREPLYQGC_H
...@@ -57,6 +57,10 @@ QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent) ...@@ -57,6 +57,10 @@ QGeoTileFetcherQGC::QGeoTileFetcherQGC(QGeoTiledMappingManagerEngine *parent)
: QGeoTileFetcher(parent) : QGeoTileFetcher(parent)
, _networkManager(new QNetworkAccessManager(this)) , _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) ...@@ -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); QNetworkRequest request = getQGCMapEngine()->urlFactory()->getTileURL((UrlFactory::MapType)spec.mapId(), spec.x(), spec.y(), spec.zoom(), _networkManager);
return new QGeoTiledMapReplyQGC(_networkManager, request, spec); return new QGeoTiledMapReplyQGC(_networkManager, request, spec);
} }
//-----------------------------------------------------------------------------
void
QGeoTileFetcherQGC::timeout()
{
if(!getQGCMapEngine()->isInternetActive()) {
getQGCMapEngine()->testInternet();
}
}
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define QGEOTILEFETCHERQGC_H #define QGEOTILEFETCHERQGC_H
#include <QtLocation/private/qgeotilefetcher_p.h> #include <QtLocation/private/qgeotilefetcher_p.h>
#include <QTimer>
#include "QGCMapUrlEngine.h" #include "QGCMapUrlEngine.h"
class QGeoTiledMappingManagerEngine; class QGeoTiledMappingManagerEngine;
...@@ -59,10 +60,13 @@ class QGeoTileFetcherQGC : public QGeoTileFetcher ...@@ -59,10 +60,13 @@ class QGeoTileFetcherQGC : public QGeoTileFetcher
public: public:
explicit QGeoTileFetcherQGC (QGeoTiledMappingManagerEngine *parent = 0); explicit QGeoTileFetcherQGC (QGeoTiledMappingManagerEngine *parent = 0);
~QGeoTileFetcherQGC(); ~QGeoTileFetcherQGC();
public slots:
void timeout ();
private: private:
QGeoTiledMapReply* getTileImage (const QGeoTileSpec &spec); QGeoTiledMapReply* getTileImage (const QGeoTileSpec &spec);
private: private:
QNetworkAccessManager* _networkManager; QNetworkAccessManager* _networkManager;
QTimer _timer;
}; };
#endif // QGEOTILEFETCHERQGC_H #endif // QGEOTILEFETCHERQGC_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment