Ref T42, application classes

* GUI classes allow retry
* longer timeouts
* accept unknow accessibility (QAM)
* QAM now as pointer, which would allow to replace QAM

When QAM becomes disconnected, then connect again it is in unknown state
This commit is contained in:
Klaus Basan
2017-04-28 02:42:50 +02:00
committed by Mathew Sutcliffe
parent 212bb6b485
commit 74e0bf397f
5 changed files with 90 additions and 66 deletions

View File

@@ -96,7 +96,8 @@ namespace BlackCore
{ }
CApplication::CApplication(const QString &applicationName, CApplicationInfo::Application application, bool init) :
m_cookieManager( {}, this), m_applicationName(applicationName), m_application(application), m_coreFacadeConfig(CCoreFacadeConfig::allEmpty())
m_accessManager(new QNetworkAccessManager(this)),
m_application(application), m_cookieManager( {}, this), m_applicationName(applicationName), m_coreFacadeConfig(CCoreFacadeConfig::allEmpty())
{
Q_ASSERT_X(!sApp, Q_FUNC_INFO, "already initialized");
Q_ASSERT_X(QCoreApplication::instance(), Q_FUNC_INFO, "no application object");
@@ -139,9 +140,11 @@ namespace BlackCore
QCoreApplication::instance()->installTranslator(&translator);
// Init network
this->m_cookieManager.setParent(&this->m_accessManager);
this->m_accessManager.setCookieJar(&this->m_cookieManager);
connect(&this->m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, this, &CApplication::ps_networkAccessibleChanged);
Q_ASSERT_X(m_accessManager, Q_FUNC_INFO, "Need QAM");
this->m_cookieManager.setParent(this->m_accessManager);
this->m_accessManager->setCookieJar(&this->m_cookieManager);
connect(this->m_accessManager, &QNetworkAccessManager::networkAccessibleChanged, this, &CApplication::ps_networkAccessibleChanged);
CLogMessage::preformatted(CNetworkUtils::createNetworkReport(this->m_accessManager));
// global setup
sApp = this;
@@ -149,7 +152,7 @@ namespace BlackCore
connect(this->m_setupReader.data(), &CSetupReader::setupHandlingCompleted, this, &CApplication::ps_setupHandlingCompleted);
connect(this->m_setupReader.data(), &CSetupReader::distributionInfoAvailable, this, &CApplication::distributionInfoAvailable);
this->m_parser.addOptions(this->m_setupReader->getCmdLineOptions());
this->m_parser.addOptions(this->m_setupReader->getCmdLineOptions()); // add options from reader
// startup done
connect(this, &CApplication::startUpCompleted, this, &CApplication::ps_startupCompleted);
@@ -176,6 +179,15 @@ namespace BlackCore
return QCoreApplication::exec();
}
void CApplication::restartApplication()
{
this->gracefulShutdown();
const QString prg = QCoreApplication::applicationFilePath();
const QStringList args = CApplication::arguments();
QProcess::startDetached(prg, args);
this->exit(0);
}
CApplication::~CApplication()
{
this->gracefulShutdown();
@@ -380,7 +392,7 @@ namespace BlackCore
CStatusMessageList CApplication::waitForSetup()
{
if (!this->m_setupReader) { return CStatusMessage(this).error("No setup reader"); }
CEventLoop::processEventsUntil(this, &CApplication::setupHandlingCompleted, 5000, [this]
CEventLoop::processEventsUntil(this, &CApplication::setupHandlingCompleted, CNetworkUtils::getLongTimeoutMs(), [this]
{
return this->m_setupReader->isSetupAvailable();
});
@@ -567,9 +579,9 @@ namespace BlackCore
QNetworkReply *CApplication::postToNetwork(const QNetworkRequest &request, QHttpMultiPart *multiPart, const CSlot<void(QNetworkReply *)> &callback)
{
if (!this->isNetworkAccessible()) { return nullptr; }
if (QThread::currentThread() != this->m_accessManager.thread())
if (QThread::currentThread() != this->m_accessManager->thread())
{
multiPart->moveToThread(this->m_accessManager.thread());
multiPart->moveToThread(this->m_accessManager->thread());
}
return httpRequestImpl(request, callback, -1, [ this, multiPart ](QNetworkAccessManager & nam, const QNetworkRequest & request)
@@ -598,7 +610,12 @@ namespace BlackCore
bool CApplication::isNetworkAccessible() const
{
return this->m_accessManager.networkAccessible() == QNetworkAccessManager::Accessible;
if (!this->m_accessManager) return false;
const QNetworkAccessManager::NetworkAccessibility a = this->m_accessManager->networkAccessible();
if (a == QNetworkAccessManager::Accessible) return true;
// currently I also accept unknown
return a == QNetworkAccessManager::UnknownAccessibility;
}
bool CApplication::hasSetupReader() const
@@ -847,6 +864,7 @@ namespace BlackCore
switch (accessible)
{
case QNetworkAccessManager::Accessible:
this->m_accessManager->setNetworkAccessible(accessible); // for some reasons the queried value still is unknown
CLogMessage(this).info("Network is accessible");
break;
case QNetworkAccessManager::NotAccessible:
@@ -947,6 +965,11 @@ namespace BlackCore
return this->m_parser.isSet(option);
}
bool CApplication::isInstallerOptionSet() const
{
return this->isParserOptionSet("installer");
}
bool CApplication::isParserOptionSet(const QCommandLineOption &option) const
{
return this->m_parser.isSet(option);
@@ -1011,20 +1034,24 @@ namespace BlackCore
return true;
}
void CApplication::cmdLineErrorMessage(const QString &errorMessage) const
bool CApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{
Q_UNUSED(retry); // onyl works with UI version
fputs(qPrintable(errorMessage), stderr);
fputs("\n\n", stderr);
fputs(qPrintable(this->m_parser.helpText()), stderr);
return false;
}
void CApplication::cmdLineErrorMessage(const CStatusMessageList &msgs) const
bool CApplication::cmdLineErrorMessage(const CStatusMessageList &msgs, bool retry) const
{
if (msgs.isEmpty()) { return; }
if (!msgs.hasErrorMessages()) { return; }
Q_UNUSED(retry); // onyl works with UI version
if (msgs.isEmpty()) { return false; }
if (!msgs.hasErrorMessages()) { return false; }
CApplication::cmdLineErrorMessage(
msgs.toFormattedQString(true)
);
return false;
}
void CApplication::cmdLineHelpMessage()
@@ -1206,14 +1233,14 @@ namespace BlackCore
if (this->m_shutdown) { return nullptr; }
if (!this->isNetworkAccessible()) { return nullptr; }
QWriteLocker locker(&m_accessManagerLock);
Q_ASSERT_X(QCoreApplication::instance()->thread() == m_accessManager.thread(), Q_FUNC_INFO, "Network manager supposed to be in main thread");
if (QThread::currentThread() != this->m_accessManager.thread())
Q_ASSERT_X(QCoreApplication::instance()->thread() == m_accessManager->thread(), Q_FUNC_INFO, "Network manager supposed to be in main thread");
if (QThread::currentThread() != this->m_accessManager->thread())
{
QTimer::singleShot(0, this, std::bind(&CApplication::httpRequestImpl, this, request, callback, maxRedirects, requestOrPostMethod));
return nullptr; // not yet started
}
Q_ASSERT_X(QThread::currentThread() == m_accessManager.thread(), Q_FUNC_INFO, "Network manager thread mismatch");
Q_ASSERT_X(QThread::currentThread() == m_accessManager->thread(), Q_FUNC_INFO, "Network manager thread mismatch");
QNetworkRequest copiedRequest(request); // no QObject
CNetworkUtils::ignoreSslVerification(copiedRequest);
CNetworkUtils::setSwiftUserAgent(copiedRequest);
@@ -1221,7 +1248,7 @@ namespace BlackCore
// If URL is one of the shared urls, add swift client SSL certificate
CNetworkUtils::setSwiftClientSslCertificate(copiedRequest, getGlobalSetup().getSwiftSharedUrls());
QNetworkReply *reply = requestOrPostMethod(this->m_accessManager, copiedRequest);
QNetworkReply *reply = requestOrPostMethod(*this->m_accessManager, copiedRequest);
reply->setProperty("started", QVariant(QDateTime::currentMSecsSinceEpoch()));
if (callback)
{

View File

@@ -12,19 +12,6 @@
#ifndef BLACKCORE_APPLICATION_H
#define BLACKCORE_APPLICATION_H
#include <QByteArray>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QList>
#include <QNetworkAccessManager>
#include <QObject>
#include <QReadWriteLock>
#include <QScopedPointer>
#include <QString>
#include <QStringList>
#include <atomic>
#include <functional>
#include "blackcore/blackcoreexport.h"
#include "blackcore/cookiemanager.h"
#include "blackcore/corefacadeconfig.h"
@@ -38,6 +25,19 @@
#include "blackmisc/applicationinfolist.h"
#include "blackmisc/statusmessagelist.h"
#include <QByteArray>
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QList>
#include <QNetworkAccessManager>
#include <QObject>
#include <QReadWriteLock>
#include <QScopedPointer>
#include <QString>
#include <QStringList>
#include <atomic>
#include <functional>
#if defined(Q_CC_MSVC) || defined(Q_OS_OSX) // Crashpad only supported on MSVC and MacOS/X
#define BLACK_USE_CRASHPAD
#endif
@@ -159,6 +159,9 @@ namespace BlackCore
//! Network accessible?
bool isNetworkAccessible() const;
//! Access to access manager
const QNetworkAccessManager *getNetworkAccessManager() const { return m_accessManager; }
//! Setup reader?
bool hasSetupReader() const;
@@ -221,6 +224,9 @@ namespace BlackCore
//! Directory for temporary files
QString getTemporaryDirectory() const;
//! Stop and restart application
void restartApplication();
//! Register as running
//! \note Normally done automatically when CApplication::exec is called
static bool registerAsRunning();
@@ -268,6 +274,9 @@ namespace BlackCore
//! Delegates to QCommandLineParser::isSet
bool isParserOptionSet(const QString &option) const;
//! Installer called?
bool isInstallerOptionSet() const;
//! Delegates to QCommandLineParser::isSet
bool isParserOptionSet(const QCommandLineOption &option) const;
@@ -285,10 +294,10 @@ namespace BlackCore
//! @}
//! Display error message
virtual void cmdLineErrorMessage(const QString &cmdLineErrorMessage) const;
virtual bool cmdLineErrorMessage(const QString &cmdLineErrorMessage, bool retry = false) const;
//! Display error message
virtual void cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs) const;
virtual bool cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs, bool retry = false) const;
// ----------------------- contexts ----------------------------------------
@@ -479,14 +488,14 @@ namespace BlackCore
int maxRedirects,
std::function<QNetworkReply *(QNetworkAccessManager &, const QNetworkRequest &)> requestOrPostMethod);
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
QNetworkAccessManager m_accessManager { this }; //!< single network access manager
CCookieManager m_cookieManager; //!< single cookie manager for our access manager
QString m_applicationName; //!< application name
BlackMisc::CApplicationInfo::Application m_application = BlackMisc::CApplicationInfo::Unknown; //!< Application if specified
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

View File

@@ -259,39 +259,27 @@ namespace BlackGui
return html;
}
void CGuiApplication::cmdLineErrorMessage(const QString &errorMessage) const
bool CGuiApplication::cmdLineErrorMessage(const QString &errorMessage, bool retry) const
{
if (CBuildConfig::isRunningOnWindowsNtPlatform())
{
const QString helpText(beautifyHelpMessage(this->m_parser.helpText()));
QMessageBox::warning(nullptr,
QGuiApplication::applicationDisplayName(),
"<html><head/><body><h2>" + errorMessage + "</h2><br>" + helpText + "</body></html>");
}
else
{
CApplication::cmdLineErrorMessage(errorMessage);
}
const QString helpText(beautifyHelpMessage(this->m_parser.helpText()));
const int r = QMessageBox::warning(nullptr,
QGuiApplication::applicationDisplayName(),
"<html><head/><body><h2>" + errorMessage + "</h2><br>" + helpText + "</body></html>", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
return (r == QMessageBox::Retry);
}
void CGuiApplication::cmdLineErrorMessage(const CStatusMessageList &msgs) const
bool CGuiApplication::cmdLineErrorMessage(const CStatusMessageList &msgs, bool retry) const
{
if (msgs.isEmpty()) { return; }
if (!msgs.hasErrorMessages()) { return; }
if (CBuildConfig::isRunningOnWindowsNtPlatform())
{
static const CPropertyIndexList propertiesSingle({ CStatusMessage::IndexMessage });
static const CPropertyIndexList propertiesMulti({ CStatusMessage::IndexSeverityAsString, CStatusMessage::IndexMessage });
const QString helpText(CGuiApplication::beautifyHelpMessage(this->m_parser.helpText()));
const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle);
QMessageBox::critical(nullptr,
QGuiApplication::applicationDisplayName(),
"<html><head/><body>" + msgsHtml + "<br><br>" + helpText + "</body></html>");
}
else
{
CApplication::cmdLineErrorMessage(msgs);
}
if (msgs.isEmpty()) { return false; }
if (!msgs.hasErrorMessages()) { return false; }
static const CPropertyIndexList propertiesSingle({ CStatusMessage::IndexMessage });
static const CPropertyIndexList propertiesMulti({ CStatusMessage::IndexSeverityAsString, CStatusMessage::IndexMessage });
const QString helpText(CGuiApplication::beautifyHelpMessage(this->m_parser.helpText()));
const QString msgsHtml = msgs.toHtml(msgs.size() > 1 ? propertiesMulti : propertiesSingle);
const int r = QMessageBox::critical(nullptr,
QGuiApplication::applicationDisplayName(),
"<html><head/><body>" + msgsHtml + "<br><br>" + helpText + "</body></html>", QMessageBox::Abort, retry ? QMessageBox::Retry : QMessageBox::NoButton);
return (r == QMessageBox::Retry);
}
bool CGuiApplication::displayInStatusBar(const CStatusMessage &message)

View File

@@ -111,8 +111,8 @@ namespace BlackGui
//! \name print messages generated during parsing / cmd handling
//! @{
virtual void cmdLineErrorMessage(const QString &cmdLineErrorMessage) const override;
virtual void cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs) const override;
virtual bool cmdLineErrorMessage(const QString &cmdLineErrorMessage, bool retry = false) const override;
virtual bool cmdLineErrorMessage(const BlackMisc::CStatusMessageList &msgs, bool retry = false) const override;
//! @}
//! \name direct access to main application window

View File

@@ -70,7 +70,7 @@ CSwiftLauncher::CSwiftLauncher(QWidget *parent) :
m_checkTimer.start();
// auto launch wizard
if (sGui->isParserOptionSet("installer"))
if (sGui->isInstallerOptionSet())
{
QTimer::singleShot(2500, this, &CSwiftLauncher::ps_startWizard);
}