From c649c1b7ed16abe6be1671e53e4f36a20716280a Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sun, 13 Mar 2016 17:59:22 +0000 Subject: [PATCH] refs #597, loading changed so that it is guaranteed setup is loaded before application is actually started --- src/blackcore/application.cpp | 79 +++++++++++++++++++++++++++++++---- src/blackcore/application.h | 37 ++++++++++++---- 2 files changed, 98 insertions(+), 18 deletions(-) diff --git a/src/blackcore/application.cpp b/src/blackcore/application.cpp index e4ea5bc4a..6e27723c2 100644 --- a/src/blackcore/application.cpp +++ b/src/blackcore/application.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace BlackMisc; using namespace BlackMisc::Network; @@ -31,7 +32,8 @@ BlackCore::CApplication *sApp = nullptr; // set by constructor namespace BlackCore { CApplication::CApplication(const QString &applicationName) : - m_applicationName(applicationName) + 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"); @@ -69,6 +71,7 @@ namespace BlackCore // global setup sApp = this; this->m_setupReader.reset(new CSetupReader(this)); + connect(this->m_setupReader.data(), &CSetupReader::setupSynchronized, this, &CApplication::ps_setupSyncronized); this->m_parser.addOptions(this->m_setupReader->getCmdLineOptions()); // notify when app goes down @@ -86,7 +89,7 @@ namespace BlackCore return QCoreApplication::instance()->applicationName() + " " + CProject::version(); } - bool CApplication::start() + bool CApplication::start(bool waitForStart) { if (!this->m_parsed) { @@ -105,7 +108,27 @@ namespace BlackCore } } - this->m_started = this->startHookIn(); + bool s = this->startHookIn(); + if (waitForStart) + { + s = this->waitForStart(); + } + this->m_started = s; + return s; + } + + bool CApplication::waitForStart() + { + // process events return immediatley if nothing is to be processed + const QTime dieTime = QTime::currentTime().addMSecs(5000); + while (QTime::currentTime() < dieTime && !this->m_started && !this->m_startUpCompleted) + { + QCoreApplication::instance()->processEvents(QEventLoop::AllEvents, 250); + } + if (this->m_startUpCompleted) + { + CLogMessage(this).error("Waiting for startup timed out"); + } return this->m_started; } @@ -163,13 +186,28 @@ namespace BlackCore return QCoreApplication::arguments(); } - void CApplication::useContexts(const CCoreFacadeConfig &coreConfig) + bool CApplication::useContexts(const CCoreFacadeConfig &coreConfig) { - if (this->m_coreFacade.isNull()) - { - this->m_coreFacade.reset(new CCoreFacade(coreConfig)); - this->coreFacadeStarted(); - } + Q_ASSERT_X(this->m_parsed, Q_FUNC_INFO, "Call this after parsing"); + + this->m_useContexts = true; + this->m_coreFacadeConfig = coreConfig; + return this->startCoreFacade(); // will do nothing if setup is not yet loaded + } + + bool CApplication::startCoreFacade() + { + if (!this->m_useContexts) { return true; } // we do not use context, so no need to startup + if (!this->m_parsed) { return false; } + if (!this->m_setupReader || !this->m_setupReader->isSetupSyncronized()) { return false; } + + Q_ASSERT_X(this->m_coreFacade.isNull(), Q_FUNC_INFO, "Cannot alter facade"); + Q_ASSERT_X(this->m_setupReader, Q_FUNC_INFO, "No facade without setup possible"); + + CLogMessage(this).info("Will start core facade now"); + this->m_coreFacade.reset(new CCoreFacade(this->m_coreFacadeConfig)); + emit this->coreFacadeStarted(); + return true; } void CApplication::initLogging() @@ -236,6 +274,29 @@ namespace BlackCore this->m_fileLogger->close(); } + void CApplication::ps_setupSyncronized(bool success) + { + if (success) + { + if (!this->m_started) + { + // follow up startup + this->m_started = this->startCoreFacade(); + } + } + this->m_startUpCompleted = true; + } + + void CApplication::severeStartupProblem(const CStatusMessage &message) + { + CLogMessage(this).preformatted(message); + this->errorMessage(message.getMessage()); + this->exit(EXIT_FAILURE); + + // if I get here the event loop was not yet running + std::exit(EXIT_FAILURE); + } + CApplication *BlackCore::CApplication::instance() { return sApp; diff --git a/src/blackcore/application.h b/src/blackcore/application.h index c8024352a..738a7c560 100644 --- a/src/blackcore/application.h +++ b/src/blackcore/application.h @@ -54,6 +54,9 @@ namespace BlackCore //! Similar to \sa QCoreApplication::instance() returns the single instance static CApplication *instance(); + //! Own log categories + static const BlackMisc::CLogCategoryList &getLogCategories(); + //! Constructor CApplication(const QString &applicationName = executable()); @@ -64,7 +67,10 @@ namespace BlackCore QString getApplicationNameAndVersion() const; //! Start services, if not yet parsed call CApplication::parse - virtual bool start(); + virtual bool start(bool waitForStart = true); + + //! Wait for stert by calling the event loop and waiting until everything is ready + bool waitForStart(); //! Request to get network reply QNetworkReply *requestNetworkResource(const QNetworkRequest &request, @@ -130,7 +136,7 @@ namespace BlackCore //! Init the contexts part and start core facade //! \sa coreFacadeStarted - void useContexts(const CCoreFacadeConfig &coreConfig); + bool useContexts(const CCoreFacadeConfig &coreConfig); //! Get the facade CCoreFacade *getCoreFacade() { return m_coreFacade.data(); } @@ -161,16 +167,14 @@ namespace BlackCore //! Facade started void coreFacadeStarted(); + protected slots: + //! Setup read/syncronized + void ps_setupSyncronized(bool success); + protected: //! Constructor CApplication(const QString &applicationName, QCoreApplication *app); - //! executable name - static const QString &executable(); - - //! Own log categories - static const BlackMisc::CLogCategoryList &cats(); - //! Display help message virtual void helpMessage(); @@ -183,13 +187,26 @@ namespace BlackCore //! Can be used to start special services virtual bool startHookIn() { return true; } + //! Severe issue during startup, most likely it does not make sense to continue + //! \note call this here if the parsing stage is over and reaction to a runtime issue + //! is needed + void severeStartupProblem(const BlackMisc::CStatusMessage &message); + + //! Start the core facade + //! \note does nothing when setup is not yet loaded + bool startCoreFacade(); + + //! executable name + static const QString &executable(); + // cmd parsing QCommandLineParser m_parser; //!< cmd parser QCommandLineOption m_cmdHelp {"help"}; //!< help option QCommandLineOption m_cmdVersion { "version" }; //!< version option QCommandLineOption m_cmdDBusAddress {"empty"}; //!< DBus address bool m_parsed = false; //!< Parsing accomplished? - bool m_started = false; //!< started? + bool m_started = false; //!< started with success? + bool m_startUpCompleted = false; //!< startup phase completed? Can mean startup failed bool m_startSetupReader = false; //!< start the setup reader private: @@ -207,7 +224,9 @@ namespace BlackCore QScopedPointer m_fileLogger; //!< file logger QNetworkAccessManager m_accessManager { this }; //!< single network access manager QString m_applicationName; //!< application name + CCoreFacadeConfig m_coreFacadeConfig; //!< Core facade config if any bool m_shutdown = false; //!< is being shut down + bool m_useContexts = false; //!< use contexts }; } // namespace