diff --git a/src/blackcore/setupreader.cpp b/src/blackcore/setupreader.cpp index ea5b1b75e..ce88e96c0 100644 --- a/src/blackcore/setupreader.cpp +++ b/src/blackcore/setupreader.cpp @@ -81,7 +81,7 @@ namespace BlackCore ); if (this->m_bootstrapMode == CacheOnly) { - this->m_distributionUrls = cachedSetup.getDistributionUrls(); + this->m_distributionUrls = cachedSetup.getSwiftDistributionFileUrls(); msgs.push_back(cacheAvailable ? CStatusMessage(this, CStatusMessage::SeverityInfo, "Cache only setup, using it as it is") : CStatusMessage(this, CStatusMessage::SeverityError, "Cache only setup, but cache is empty") @@ -105,7 +105,7 @@ namespace BlackCore if (this->m_bootstrapMode != Explicit) { // also use previously cached URLs - const CUrlList bootstrapCacheUrls(cachedSetup.getBootstrapFileUrls()); + const CUrlList bootstrapCacheUrls(cachedSetup.getSwiftBootstrapFileUrls()); this->m_bootstrapUrls.push_back(bootstrapCacheUrls); msgs.push_back(bootstrapCacheUrls.isEmpty() ? CStatusMessage(this, CStatusMessage::SeverityWarning, "No bootstrap URLs in cache") : @@ -144,50 +144,63 @@ namespace BlackCore bool CSetupReader::parseCmdLineArguments() { - // bootstrap file URL where we can download the bootstrap file - const QString parserValueUrl = sApp->getParserValue(this->m_cmdBootstrapUrl); - this->m_bootstrapUrlFileValue = CGlobalSetup::buildBootstrapFileUrl(parserValueUrl); - const QUrl url(this->m_bootstrapUrlFileValue); + // copy vars at beginning to simplify a threadsafe version in the future + const QString cmdLineBootstrapUrl = this->getCmdLineBootstrapUrl(); + BootstrapMode bootstrapMode = stringToEnum(sApp->getParserValue(this->m_cmdBootstrapMode)); + const bool ignoreCmdBootstrapUrl = m_ignoreCmdBootstrapUrl; + const bool checkCmdBootstrapUrl = m_checkCmdBootstrapUrl; + const QString bootstrapUrlFileValue = CGlobalSetup::buildBootstrapFileUrl(cmdLineBootstrapUrl); + QString localSetupFileValue; + const QUrl url(bootstrapUrlFileValue); const QString urlString(url.toString()); - this->m_bootstrapMode = stringToEnum(sApp->getParserValue(this->m_cmdBootstrapMode)); - if (urlString.isEmpty() && this->m_bootstrapMode == Explicit) + bool ok = false; + + if (urlString.isEmpty() && bootstrapMode == Explicit) { - this->m_bootstrapMode = Implicit; // no URL, we use implicit mode + bootstrapMode = Implicit; // no URL, we use implicit mode } - // check on local file - if (url.isLocalFile()) + do { - this->m_localSetupFileValue = url.toLocalFile(); - const QFile f(this->m_localSetupFileValue); - if (!f.exists()) + // check on local file + if (url.isLocalFile()) { - sApp->cmdLineErrorMessage(QString("File '%1' does not exist)").arg(this->m_localSetupFileValue)); - return false; - } - } - - // check on explicit URL - if (this->m_bootstrapMode == Explicit) - { - if (!url.isLocalFile()) - { - bool retry = false; - bool ok = false; - do + localSetupFileValue = url.toLocalFile(); + const QFile f(localSetupFileValue); + if (!f.exists()) { - if (CNetworkUtils::canConnect(url, CNetworkUtils::getLongTimeoutMs())) - { - ok = true; - break; - } - retry = sApp->cmdLineErrorMessage(QString("URL '%1' not reachable").arg(urlString), true); + sApp->cmdLineErrorMessage(QString("File '%1' does not exist)").arg(localSetupFileValue)); + break; + } + } + + // check on explicit URL + if (bootstrapMode == Explicit) + { + if (!url.isLocalFile()) + { + bool retry = false; + + // "retry" possible in some cases + do + { + if (ignoreCmdBootstrapUrl || !checkCmdBootstrapUrl || CNetworkUtils::canConnect(url, CNetworkUtils::getLongTimeoutMs())) + { + ok = true; + break; + } + retry = sApp->cmdLineErrorMessage(QString("URL '%1' not reachable").arg(urlString), true); + } + while (retry); } - while (retry); - if (!ok) { return false; } } } - return true; + while (false); + + m_localSetupFileValue = localSetupFileValue; + m_bootstrapUrlFileValue = bootstrapUrlFileValue; + m_bootstrapMode = bootstrapMode; + return ok; } void CSetupReader::gracefulShutdown() @@ -332,11 +345,14 @@ namespace BlackCore CGlobalSetup loadedSetup; loadedSetup.convertFromJson(setupJson); loadedSetup.markAsLoaded(true); + const CUrl sharedUrl(loadedSetup.getCorrespondingSharedUrl(url)); + if (!sharedUrl.isEmpty()) { emit this->successfullyReadSharedUrl(sharedUrl); } + if (lastModified > 0 && lastModified > loadedSetup.getMSecsSinceEpoch()) { loadedSetup.setMSecsSinceEpoch(lastModified); } bool sameVersionLoaded = (loadedSetup == currentSetup); if (sameVersionLoaded) { - this->m_distributionUrls = currentSetup.getDistributionUrls(); // defaults + this->m_distributionUrls = currentSetup.getSwiftDistributionFileUrls(); // defaults CLogMessage(this).info("Same setup version loaded from '%1' as already in data cache '%2'") << urlString << m_setup.getFilename(); CLogMessage::preformatted(this->manageSetupAvailability(true)); return; // success @@ -349,7 +365,7 @@ namespace BlackCore if (m.isSeverityInfoOrLess()) { // no issue with cache - this->m_distributionUrls = loadedSetup.getDistributionUrls(); + this->m_distributionUrls = loadedSetup.getSwiftDistributionFileUrls(); CLogMessage(this).info("Loaded setup from '%1'") << urlString; CLogMessage(this).info("Setup: Updated data cache in '%1'") << this->m_setup.getFilename(); { @@ -490,14 +506,21 @@ namespace BlackCore bool CSetupReader::hasCmdLineBootstrapUrl() const { - return !sApp->getParserValue(this->m_cmdBootstrapUrl).isEmpty(); + return !this->getCmdLineBootstrapUrl().isEmpty(); } QString CSetupReader::getCmdLineBootstrapUrl() const { + if (m_ignoreCmdBootstrapUrl) return ""; return sApp->getParserValue(this->m_cmdBootstrapUrl); } + void CSetupReader::setIgnoreCmdLineBootstrapUrl(bool ignore) + { + m_ignoreCmdBootstrapUrl = ignore; + this->parseCmdLineArguments(); // T156 this part not threadsafe, currently not a real problem as setup reader runs in main thread + } + CGlobalSetup CSetupReader::getSetup() const { return m_setup.get(); @@ -511,7 +534,7 @@ namespace BlackCore const bool cacheAvailable = cachedSetup.wasLoaded(); if (cacheAvailable) { - CLogMessage(this).info("Setup (bootstrap already cached, no prefill needed"); + CLogMessage(this).info("Setup cache prefill (bootstrap already cached, no prefill needed"); return false; } const QString fn = CDirectoryUtils::bootstrapResourceFilePath(); @@ -543,6 +566,24 @@ namespace BlackCore return this->m_setupReadErrorMsgs; } + const QString &CSetupReader::getBootstrapUrlFile() const + { + if (!m_localSetupFileValue.isEmpty()) { return m_localSetupFileValue; } + return m_bootstrapUrlFileValue; + } + + QString CSetupReader::getBootstrapModeAsString() const + { + switch (m_bootstrapMode) + { + case CacheOnly: return "cache only"; + case Explicit: return "explicit"; + case Implicit: return "implicit"; + default: break; + } + return ""; + } + void CSetupReader::setLastSetupReadErrorMessages(const CStatusMessageList &messages) { QWriteLocker l(&m_lockSetup); diff --git a/src/blackcore/setupreader.h b/src/blackcore/setupreader.h index c67d4ce08..fca3ae0e6 100644 --- a/src/blackcore/setupreader.h +++ b/src/blackcore/setupreader.h @@ -59,12 +59,20 @@ namespace BlackCore //! CMD line argument for bootstrap URL QString getCmdLineBootstrapUrl() const; + //! Ignore the bootstrap URL + //! \threadsafe + void setIgnoreCmdLineBootstrapUrl(bool ignore); + + //! Check connection of the bootstrap URL + //! \threadsafe + void setCheckCmdLineBootstrapUrl(bool check) { m_checkCmdBootstrapUrl = check; } + //! Current setup (reader URLs, DB location, crash server) //! \remarks aka "bootstrap file" //! \threadsafe BlackCore::Data::CGlobalSetup getSetup() const; - //! Load the cache file local boostrap file + //! Load the cache file local bootstrap file //! \remark can be used during installation as failover //! \threadsafe bool prefillCacheWithLocalResourceBootstrapFile(); @@ -84,6 +92,12 @@ namespace BlackCore //! Last setup parsing error messages (if any) BlackMisc::CStatusMessageList getLastSetupReadErrorMessages() const; + //! Get bootstrap URL, either m_bootstrapUrlFileValue or m_localSetupFileValue + const QString &getBootstrapUrlFile() const; + + //! Mode as string + QString getBootstrapModeAsString() const; + signals: //! Setup fetched or failed (from web, cache, or local file) void setupHandlingCompleted(bool available); @@ -91,6 +105,9 @@ namespace BlackCore //! Setup avialable (from web, cache void distributionInfoAvailable(bool available); + //! A shared URL was successfully read + void successfullyReadSharedUrl(const BlackMisc::Network::CUrl &sharedUrl); + protected: //! Constructor explicit CSetupReader(QObject *parent); @@ -143,9 +160,11 @@ namespace BlackCore std::atomic m_shutdown { false }; std::atomic m_setupAvailable { false }; std::atomic m_distributionInfoAvailable { false }; - QString m_localSetupFileValue; //! Local file for setup, passed by cmd line arguments - QString m_bootstrapUrlFileValue; //! Bootstrap URL if not local - BootstrapMode m_bootstrapMode = Explicit; //! How to bootstrap + std::atomic m_ignoreCmdBootstrapUrl { false }; //!< ignore the explicitly set bootstrap URL + std::atomic m_checkCmdBootstrapUrl { true }; //!< check connection on CMD bootstrap URL + QString m_localSetupFileValue; //!< Local file for setup, passed by cmd line arguments + QString m_bootstrapUrlFileValue; //!< Bootstrap URL if not local + BootstrapMode m_bootstrapMode = Explicit; //!< How to bootstrap BlackMisc::Network::CFailoverUrlList m_bootstrapUrls; //!< location of setup files BlackMisc::Network::CFailoverUrlList m_distributionUrls; //!< location of info files QCommandLineOption m_cmdBootstrapUrl; //!< bootstrap URL