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()
, _maxMemCache(0)
, _prunning(false)
, _cacheWasReset(false)
, _isInternetActive(false)
{
qRegisterMetaType<QGCMapTask::TaskType>();
qRegisterMetaType<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()
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
......@@ -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();
......
......@@ -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
{
......
......@@ -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<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&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
......
......@@ -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);
}
......@@ -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<QGCMapTask*> _taskQueue;
......
......@@ -46,11 +46,14 @@
#include "QGCMapEngine.h"
#include "QGeoMapReplyQGC.h"
#include "QGeoTileFetcherQGC.h"
#include <QtLocation/private/qgeotilespec_p.h>
#include <QtNetwork/QNetworkAccessManager>
#include <QFile>
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();
}
}
......@@ -49,6 +49,7 @@
#include <QtNetwork/QNetworkReply>
#include <QtLocation/private/qgeotiledmapreply_p.h>
#include <QTimer>
#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
......@@ -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();
}
}
......@@ -48,6 +48,7 @@
#define QGEOTILEFETCHERQGC_H
#include <QtLocation/private/qgeotilefetcher_p.h>
#include <QTimer>
#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
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