Ref T121, check if Internet is accessible

* in case the internet provider is down, this is not detected
* extended test to detect if access is possible
* in case of downtime this indicated in status component
This commit is contained in:
Klaus Basan
2017-08-05 20:05:07 +02:00
committed by Mathew Sutcliffe
parent b70fb70d60
commit f3847bd33c
20 changed files with 176 additions and 92 deletions

View File

@@ -140,21 +140,24 @@ namespace BlackCore
// Init network
Q_ASSERT_X(m_accessManager, Q_FUNC_INFO, "Need QAM");
m_internetAccessTimer.setObjectName("Application::m_internetAccessTimer");
this->m_cookieManager.setParent(this->m_accessManager);
this->m_accessManager->setCookieJar(&this->m_cookieManager);
connect(this->m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, this, &CApplication::ps_networkAccessibleChanged);
connect(this->m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, this, &CApplication::networkAccessibleChanged, Qt::QueuedConnection);
connect(&this->m_internetAccessTimer, &QTimer::timeout, this, [this] { this->checkInternetAccessible(true); });
CLogMessage::preformatted(CNetworkUtils::createNetworkReport(this->m_accessManager));
this->checkInternetAccessible();
// global setup
sApp = this;
this->m_setupReader.reset(new CSetupReader(this));
connect(this->m_setupReader.data(), &CSetupReader::setupHandlingCompleted, this, &CApplication::ps_setupHandlingCompleted);
connect(this->m_setupReader.data(), &CSetupReader::setupHandlingCompleted, this, &CApplication::setupHandlingIsCompleted);
connect(this->m_setupReader.data(), &CSetupReader::distributionInfoAvailable, this, &CApplication::distributionInfoAvailable);
this->m_parser.addOptions(this->m_setupReader->getCmdLineOptions()); // add options from reader
// startup done
connect(this, &CApplication::startUpCompleted, this, &CApplication::ps_startupCompleted);
connect(this, &CApplication::startUpCompleted, this, &CApplication::startupCompleted);
// notify when app goes down
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &CApplication::gracefulShutdown);
@@ -336,11 +339,11 @@ namespace BlackCore
{
QTimer::singleShot(10 * 1000, [ = ]
{
#ifdef BLACK_USE_CRASHPAD
#ifdef BLACK_USE_CRASHPAD
CRASHPAD_SIMULATE_CRASH();
#else
#else
CLogMessage(this).warning("This compiler or platform does not support crashpad. Cannot simulate crash dump!");
#endif
#endif
});
}
@@ -494,6 +497,40 @@ namespace BlackCore
return false;
}
void CApplication::checkInternetAccessible(bool logWarning)
{
if (this->isShuttingDown()) { return; }
bool access = false;
if (this->isNetworkAccessible())
{
QString message1;
static const QString testHost1("www.google.com"); // what else?
access = CNetworkUtils::canConnect(testHost1, 443, message1);
if (!access)
{
QString message2;
static const QString testHost2("www.microsoft.com"); // secondary test
access = CNetworkUtils::canConnect(testHost2, 80, message2);
if (!access && logWarning) { CLogMessage(this).warning("Internet access problems: %1 based on testing '%2'") << message1 << testHost1; }
}
}
else
{
if (logWarning) { CLogMessage(this).warning("No network access"); }
}
if (m_internetAccessible != access)
{
m_internetAccessible = access;
emit this->internetAccessibleChanged(access);
}
constexpr int checkAgainSuccess = 60 * 1000;
constexpr int checkAgainFailure = 30 * 1000;
m_internetAccessTimer.start(access ? checkAgainSuccess : checkAgainFailure);
}
void CApplication::setSignalStartupAutomatically(bool enabled)
{
this->m_signalStartup = enabled;
@@ -630,10 +667,15 @@ namespace BlackCore
const QNetworkAccessManager::NetworkAccessibility a = this->m_accessManager->networkAccessible();
if (a == QNetworkAccessManager::Accessible) { return true; }
// currently I also accept unknown
// currently I also accept unknown because of that issue with Network Manager
return a == QNetworkAccessManager::UnknownAccessibility;
}
bool CApplication::isInternetAccessible() const
{
return this->isNetworkAccessible() && m_internetAccessible;
}
bool CApplication::hasSetupReader() const
{
// m_startSetupReader set to false, if something wrong with parsing
@@ -855,7 +897,7 @@ namespace BlackCore
this->m_fileLogger->close();
}
void CApplication::ps_setupHandlingCompleted(bool available)
void CApplication::setupHandlingIsCompleted(bool available)
{
if (available)
{
@@ -872,12 +914,12 @@ namespace BlackCore
}
}
void CApplication::ps_startupCompleted()
void CApplication::startupCompleted()
{
// void
}
void CApplication::ps_networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
void CApplication::networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
{
switch (accessible)
{
@@ -892,6 +934,7 @@ namespace BlackCore
CLogMessage(this).warning("Network accessibility unknown");
break;
}
this->checkInternetAccessible();
}
CStatusMessageList CApplication::asyncWebAndContextStart()

View File

@@ -159,6 +159,9 @@ namespace BlackCore
//! Network accessible?
bool isNetworkAccessible() const;
//! Internet accessible?
bool isInternetAccessible() const;
//! Access to access manager
const QNetworkAccessManager *getNetworkAccessManager() const { return m_accessManager; }
@@ -408,17 +411,19 @@ namespace BlackCore
//! Web data services started
void webDataServicesStarted(bool success);
protected slots:
//! Setup read/synchronized
void ps_setupHandlingCompleted(bool available);
//! Startup completed
virtual void ps_startupCompleted();
//! Problem with network access manager
virtual void ps_networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
//! Internet accessinility changed
void internetAccessibleChanged(bool access);
protected:
//! Setup read/synchronized
void setupHandlingIsCompleted(bool available);
//! Startup completed
virtual void startupCompleted();
//! Problem with network access manager
virtual void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
//! Init class, allows to init from BlackGui::CGuiApplication as well (pseudo virtual)
void init(bool withMetadata);
@@ -480,6 +485,9 @@ namespace BlackCore
//! Dev.environment
bool initIsRunningInDeveloperEnvironment() const;
//! Check that Internet is accessible
void checkInternetAccessible(bool logWarning = true);
//! Async. start when setup is loaded
BlackMisc::CStatusMessageList asyncWebAndContextStart();
@@ -489,25 +497,27 @@ namespace BlackCore
int maxRedirects,
std::function<QNetworkReply *(QNetworkAccessManager &, const QNetworkRequest &)> requestOrPostMethod);
QNetworkAccessManager *m_accessManager = nullptr; //!< single network access manager
QNetworkAccessManager *m_accessManager = nullptr; //!< single network access manager
BlackMisc::CApplicationInfo::Application m_application = BlackMisc::CApplicationInfo::Unknown; //!< Application if specified
QScopedPointer<CCoreFacade> m_coreFacade; //!< core facade if any
QScopedPointer<CSetupReader> m_setupReader; //!< setup reader
QScopedPointer<CWebDataServices> m_webDataServices; //!< web data services
QScopedPointer<BlackMisc::CFileLogger> m_fileLogger; //!< file logger
CCookieManager m_cookieManager; //!< single cookie manager for our access manager
QString m_applicationName; //!< application name
QReadWriteLock m_accessManagerLock; //!< lock to make access manager access threadsafe
CCoreFacadeConfig m_coreFacadeConfig; //!< Core facade config if any
CWebReaderFlags::WebReader m_webReadersUsed; //!< Readers to be used
BlackCore::Db::CDatabaseReaderConfigList m_dbReaderConfig; //!< Load or used caching?
std::atomic<bool> m_shutdown { false }; //!< is being shutdown?
bool m_useContexts = false; //!< use contexts
bool m_useWebData = false; //!< use web data
bool m_signalStartup = true; //!< signal startup automatically
bool m_devEnv = false; //!< dev. environment
bool m_unitTest = false; //!< is UNIT test
bool m_autoSaveSettings = true;//!< automatically saving all settings
QScopedPointer<CCoreFacade> m_coreFacade; //!< core facade if any
QScopedPointer<CSetupReader> m_setupReader; //!< setup reader
QScopedPointer<CWebDataServices> m_webDataServices; //!< web data services
QScopedPointer<BlackMisc::CFileLogger> m_fileLogger; //!< file logger
CCookieManager m_cookieManager; //!< single cookie manager for our access manager
QString m_applicationName; //!< application name
QReadWriteLock m_accessManagerLock; //!< lock to make access manager access threadsafe
CCoreFacadeConfig m_coreFacadeConfig; //!< Core facade config if any
CWebReaderFlags::WebReader m_webReadersUsed; //!< Readers to be used
BlackCore::Db::CDatabaseReaderConfigList m_dbReaderConfig; //!< Load or used caching?
std::atomic<bool> m_shutdown { false }; //!< is being shutdown?
QTimer m_internetAccessTimer { this };
bool m_useContexts = false; //!< use contexts
bool m_useWebData = false; //!< use web data
bool m_signalStartup = true; //!< signal startup automatically
bool m_devEnv = false; //!< dev. environment
bool m_unitTest = false; //!< is UNIT test
bool m_autoSaveSettings = true; //!< automatically saving all settings
bool m_internetAccessible = true; //!< Internet accessible
// -------------- crashpad -----------------
BlackMisc::CStatusMessageList initCrashHandler();

View File

@@ -203,7 +203,7 @@ namespace BlackCore
this->threadAssertCheck();
if (!this->doWorkCheck()) { return; }
entity &= CEntityFlags::AirportEntity;
if (!this->isNetworkAccessible())
if (!this->isInternetAccessible())
{
emit this->dataRead(entity, CEntityFlags::ReadSkipped, 0);
return;

View File

@@ -198,7 +198,7 @@ namespace BlackCore
// ps_read is implemented in the derived classes
if (entities == CEntityFlags::NoEntity) { return; }
if (!this->isNetworkAccessible(QString("No network, will not read %1").arg(CEntityFlags::flagToString(entities)))) { return; }
if (!this->isInternetAccessible(QString("No network/internet access, will not read %1").arg(CEntityFlags::flagToString(entities)))) { return; }
const bool s = QMetaObject::invokeMethod(this, "ps_read",
Q_ARG(BlackMisc::Network::CEntityFlags::Entity, entities),
@@ -370,7 +370,7 @@ namespace BlackCore
bool CDatabaseReader::requestHeadersOfSharedFiles(CEntityFlags::Entity entities)
{
if (!this->isNetworkAccessible(QString("No network, will not read shared file headers for %1").arg(CEntityFlags::flagToString(entities)))) { return false; }
if (!this->isInternetAccessible(QString("No network/internet access, will not read shared file headers for %1").arg(CEntityFlags::flagToString(entities)))) { return false; }
CEntityFlags::Entity allEntities(this->maskBySupportedEntities(entities));
CEntityFlags::Entity currentEntity = CEntityFlags::iterateDbEntities(allEntities);

View File

@@ -134,7 +134,7 @@ namespace BlackCore
this->threadAssertCheck(); // runs in background thread
if (!this->doWorkCheck()) { return; }
entities &= CEntityFlags::AllIcaoAndCountries;
if (!this->isNetworkAccessible())
if (!this->isInternetAccessible())
{
emit this->dataRead(entities, CEntityFlags::ReadSkipped, 0);
return;

View File

@@ -95,6 +95,7 @@ namespace BlackCore
void CInfoDataReader::read()
{
if (!this->doWorkCheck()) { return; }
const CUrl url(this->getInfoObjectsUrl());
if (!url.isEmpty())
{

View File

@@ -154,7 +154,7 @@ namespace BlackCore
this->threadAssertCheck();
if (!this->doWorkCheck()) { return; }
entities &= CEntityFlags::DistributorLiveryModel;
if (!this->isNetworkAccessible())
if (!this->isInternetAccessible())
{
emit this->dataRead(entities, CEntityFlags::ReadSkipped, 0);
return;

View File

@@ -208,9 +208,9 @@ namespace BlackCore
CStatusMessageList CSetupReader::triggerReadSetup()
{
if (this->m_shutdown) { return CStatusMessage(this, CStatusMessage::SeverityError, "shutdown"); }
if (!sApp->isNetworkAccessible())
if (!sApp->isInternetAccessible())
{
const CStatusMessage m(this, CStatusMessage::SeverityInfo, "No network, will try to recover");
const CStatusMessage m(this, CStatusMessage::SeverityInfo, "No network/internet, will try to recover");
CStatusMessageList msgs(m);
msgs.push_back(this->manageSetupAvailability(false, false));
this->setLastSetupReadErrorMessages(msgs);

View File

@@ -68,9 +68,9 @@ namespace BlackCore
return delta <= timeLastMs;
}
bool CThreadedReader::isNetworkAccessible(const QString &logWarningMessage) const
bool CThreadedReader::isInternetAccessible(const QString &logWarningMessage) const
{
const bool a = sApp->isNetworkAccessible();
const bool a = sApp->isInternetAccessible();
if (!a && !logWarningMessage.isEmpty())
{
CLogMessage(this).warning(logWarningMessage);
@@ -148,6 +148,7 @@ namespace BlackCore
{
if (!m_unitTest && (!sApp || !sApp->hasWebDataServices())) { return false; }
if (!isEnabled()) { return false; }
if (isAbandoned()) { return false; }
return true;
}

View File

@@ -54,7 +54,7 @@ namespace BlackCore
//! Network accessible?
//! \param logWarningMessage optional warning if not accessible
bool isNetworkAccessible(const QString &logWarningMessage = {}) const;
bool isInternetAccessible(const QString &logWarningMessage = {}) const;
//! Is marked as read failed
//! \threadsafe

View File

@@ -64,7 +64,7 @@ namespace BlackCore
{
this->threadAssertCheck();
if (!this->doWorkCheck()) { return; }
if (!this->isNetworkAccessible("No network, cannot read VATSIM bookings")) { return; }
if (!this->isInternetAccessible("No network/internet access, cannot read VATSIM bookings")) { return; }
Q_ASSERT_X(sApp, Q_FUNC_INFO, "No application");
const QUrl url(sApp->getGlobalSetup().getVatsimBookingsUrl());

View File

@@ -183,7 +183,7 @@ namespace BlackCore
{
this->threadAssertCheck();
if (!this->doWorkCheck()) { return; }
if (!this->isNetworkAccessible("No network, cannot read VATSIM data file")) { return; }
if (!this->isInternetAccessible("No network/internet access, cannot read VATSIM data file")) { return; }
// round robin for load balancing
// remark: Don't use QThread to run network operations in the background

View File

@@ -76,7 +76,7 @@ namespace BlackCore
{
this->threadAssertCheck();
if (!this->doWorkCheck()) { return; }
if (!this->isNetworkAccessible("No network, cannot read METARs")) { return; }
if (!this->isInternetAccessible("No network/internet access, cannot read METARs")) { return; }
CFailoverUrlList urls(sApp->getVatsimMetarUrls());
const CUrl url(urls.obtainNextWorkingUrl(true));

View File

@@ -66,7 +66,7 @@ namespace BlackCore
{
this->threadAssertCheck();
if (!this->doWorkCheck()) { return; }
if (!this->isNetworkAccessible("No network, cannot read VATSIM status file")) { return; }
if (!this->isInternetAccessible("No network/internet access, cannot read VATSIM status file")) { return; }
Q_ASSERT_X(sApp, Q_FUNC_INFO, "Missing application");
CFailoverUrlList urls(sApp->getGlobalSetup().getVatsimStatusFileUrls());

View File

@@ -928,7 +928,14 @@ namespace BlackCore
}
// and trigger read
QTimer::singleShot(0, m_dbInfoDataReader, [this]() { this->m_dbInfoDataReader->read(); });
if (sApp->isInternetAccessible())
{
QTimer::singleShot(0, m_dbInfoDataReader, [this]() { this->m_dbInfoDataReader->read(); });
}
else
{
CLogMessage(this).warning("No network/internet access, skipping read of info objects");
}
}
void CWebDataServices::initSharedInfoObjectReaderAndTriggerRead()
@@ -956,7 +963,14 @@ namespace BlackCore
}
// and trigger read
QTimer::singleShot(0, m_sharedInfoDataReader, [this]() { this->m_sharedInfoDataReader->read(); });
if (sApp->isInternetAccessible())
{
QTimer::singleShot(0, m_sharedInfoDataReader, [this]() { this->m_sharedInfoDataReader->read(); });
}
else
{
CLogMessage(this).warning("No network/internet access, skipping read of shared data");
}
}
CDatabaseReader *CWebDataServices::getDbReader(CEntityFlags::Entity entity) const