refs #853, JSON exception handling in setup reader

This commit is contained in:
Klaus Basan
2017-01-06 03:21:03 +01:00
committed by Mathew Sutcliffe
parent 3939b0166f
commit 4a28807768
2 changed files with 101 additions and 63 deletions

View File

@@ -9,6 +9,7 @@
#include "blackcore/application.h" #include "blackcore/application.h"
#include "blackcore/setupreader.h" #include "blackcore/setupreader.h"
#include "blackmisc/verify.h"
#include "blackmisc/compare.h" #include "blackmisc/compare.h"
#include "blackmisc/fileutils.h" #include "blackmisc/fileutils.h"
#include "blackmisc/json.h" #include "blackmisc/json.h"
@@ -63,11 +64,10 @@ namespace BlackCore
CStatusMessageList CSetupReader::asyncLoad() CStatusMessageList CSetupReader::asyncLoad()
{ {
CStatusMessageList msgs; CStatusMessageList msgs;
if (this->readLocalBootstrapFile(this->m_localSetupFileValue)) if (!this->m_localSetupFileValue.isEmpty())
{ {
// initialized by local file for testing msgs = this->readLocalBootstrapFile(this->m_localSetupFileValue);
msgs.push_back(CStatusMessage(this, CStatusMessage::SeverityInfo, "Using local bootstrap file: " + this->m_localSetupFileValue)); msgs.push_back(this->manageSetupAvailability(false, msgs.isSuccess()));
msgs.push_back(this->manageSetupAvailability(false, true));
return msgs; return msgs;
} }
@@ -258,18 +258,18 @@ namespace BlackCore
return url; return url;
} }
bool CSetupReader::readLocalBootstrapFile(QString &fileName) CStatusMessageList CSetupReader::readLocalBootstrapFile(QString &fileName)
{ {
if (fileName.isEmpty()) { return false; } if (fileName.isEmpty()) { return CStatusMessage(this).error("No file name for local bootstrap file"); }
QString fn; QString fn;
QFile file(fileName); QFile file(fileName);
if (!file.exists()) if (!file.exists())
{ {
// relative name? // relative name?
QString dir(sApp->getCmdSwiftPrivateSharedDir()); QString dir(sApp->getCmdSwiftPrivateSharedDir());
if (dir.isEmpty()) { return false; } if (dir.isEmpty()) { return CStatusMessage(this).error("Empty shared directory '%1' for bootstrap file") << dir; }
// no version for local files, as those come withe the current code // no version for local files, as those come with the current code
fn = CFileUtils::appendFilePaths(dir, "bootstrap/bootstrap.json"); fn = CFileUtils::appendFilePaths(dir, "bootstrap/bootstrap.json");
} }
else else
@@ -278,12 +278,20 @@ namespace BlackCore
} }
QString content(CFileUtils::readFileToString(fn)); QString content(CFileUtils::readFileToString(fn));
if (content.isEmpty()) { return false; } if (content.isEmpty()) { return CStatusMessage(this).error("File '%1' not existing or empty") << fn; }
try
{
CGlobalSetup s; CGlobalSetup s;
s.convertFromJson(content); //! \todo catch CJsonException or use convertFromJsonNoThrow s.convertFromJson(content);
s.setDevelopment(true); s.setDevelopment(true);
m_setup.set(s); m_setup.set(s);
return true; return CStatusMessage(this).info("Setup cache updated from local file '%1'") << fn;
}
catch (const CJsonException &ex)
{
return ex.toStatusMessage(this, QString("Parsing local setup file '%1'").arg(fn));
}
} }
void CSetupReader::ps_parseSetupFile(QNetworkReply *nwReplyPtr) void CSetupReader::ps_parseSetupFile(QNetworkReply *nwReplyPtr)
@@ -304,14 +312,16 @@ namespace BlackCore
nwReplyPtr->close(); nwReplyPtr->close();
if (setupJson.isEmpty()) if (setupJson.isEmpty())
{ {
CLogMessage(this).info("No bootstrap setup file at %1") << urlString; CLogMessage(this).info("No bootstrap setup file at '%1'") << urlString;
// try next URL // try next URL
} }
else else
{
try
{ {
const CGlobalSetup currentSetup = m_setup.get(); const CGlobalSetup currentSetup = m_setup.get();
CGlobalSetup loadedSetup; CGlobalSetup loadedSetup;
loadedSetup.convertFromJson(Json::jsonObjectFromString(setupJson)); //! \todo catch CJsonException or use convertFromJsonNoThrow loadedSetup.convertFromJson(Json::jsonObjectFromString(setupJson));
loadedSetup.markAsLoaded(true); loadedSetup.markAsLoaded(true);
if (lastModified > 0 && lastModified > loadedSetup.getMSecsSinceEpoch()) { loadedSetup.setMSecsSinceEpoch(lastModified); } if (lastModified > 0 && lastModified > loadedSetup.getMSecsSinceEpoch()) { loadedSetup.setMSecsSinceEpoch(lastModified); }
bool sameVersionLoaded = (loadedSetup == currentSetup); bool sameVersionLoaded = (loadedSetup == currentSetup);
@@ -331,10 +341,23 @@ namespace BlackCore
{ {
// no issue with cache // no issue with cache
this->m_updateInfoUrls = loadedSetup.getUpdateInfoFileUrls(); this->m_updateInfoUrls = loadedSetup.getUpdateInfoFileUrls();
CLogMessage(this).info("Setup: Updated data cache in %1") << this->m_setup.getFilename(); CLogMessage(this).info("Setup: Updated data cache in '%1'") << this->m_setup.getFilename();
} }
CLogMessage::preformatted(this->manageSetupAvailability(true)); CLogMessage::preformatted(this->manageSetupAvailability(true));
return; return;
}
catch (const CJsonException &ex)
{
// we downloaded an unparsable JSON file.
// as we control those files something is wrong
const QString errorMsg = QString("Setup file loaded from '%1' cannot be parsed").arg(urlString);
const CStatusMessage msg = ex.toStatusMessage(this, errorMsg);
CLogMessage::preformatted(msg);
// in dev. I get notified, in productive code I try next URL
// by falling thru
BLACK_VERIFY_X(false, Q_FUNC_INFO, errorMsg.toLocal8Bit().constData());
}
} // json empty } // json empty
} // no error } // no error
else else
@@ -381,10 +404,12 @@ namespace BlackCore
// try next URL // try next URL
} }
else else
{
try
{ {
CUpdateInfo currentUpdateInfo(m_updateInfo.get()); // from cache CUpdateInfo currentUpdateInfo(m_updateInfo.get()); // from cache
CUpdateInfo loadedUpdateInfo; CUpdateInfo loadedUpdateInfo;
loadedUpdateInfo.convertFromJson(Json::jsonObjectFromString(setupJson)); //! \todo catch CJsonException or use convertFromJsonNoThrow loadedUpdateInfo.convertFromJson(Json::jsonObjectFromString(setupJson));
if (lastModified > 0 && lastModified > loadedUpdateInfo.getMSecsSinceEpoch()) { loadedUpdateInfo.setMSecsSinceEpoch(lastModified); } if (lastModified > 0 && lastModified > loadedUpdateInfo.getMSecsSinceEpoch()) { loadedUpdateInfo.setMSecsSinceEpoch(lastModified); }
const bool sameVersionLoaded = (loadedUpdateInfo == currentUpdateInfo); const bool sameVersionLoaded = (loadedUpdateInfo == currentUpdateInfo);
if (sameVersionLoaded) if (sameVersionLoaded)
@@ -408,6 +433,19 @@ namespace BlackCore
this->manageUpdateAvailability(true); this->manageUpdateAvailability(true);
return; // success return; // success
} // cache } // cache
}
catch (const CJsonException &ex)
{
// we downloaded an unparsable JSON file.
// as we control those files something is wrong
const QString errorMsg = QString("Update file loaded from '%1' cannot be parsed").arg(urlString);
const CStatusMessage msg = ex.toStatusMessage(this, errorMsg);
CLogMessage::preformatted(msg);
// in dev. I get notified, in productive code I try next URL
// by falling thru
BLACK_VERIFY_X(false, Q_FUNC_INFO, errorMsg.toLocal8Bit().constData());
}
} // json empty } // json empty
} // no error } // no error
else else
@@ -427,7 +465,7 @@ namespace BlackCore
const CStatusMessageList msgs = this->manageSetupAvailability(false); const CStatusMessageList msgs = this->manageSetupAvailability(false);
CLogMessage::preformatted(msgs); CLogMessage::preformatted(msgs);
} }
} // function }
const CLogCategoryList &CSetupReader::getLogCategories() const CLogCategoryList &CSetupReader::getLogCategories()
{ {

View File

@@ -143,12 +143,12 @@ namespace BlackCore
BlackMisc::CData<BlackCore::Data::TUpdateInfo> m_updateInfo {this}; //!< data cache update info BlackMisc::CData<BlackCore::Data::TUpdateInfo> m_updateInfo {this}; //!< data cache update info
//! Read by local individual file and update cache from that //! Read by local individual file and update cache from that
bool readLocalBootstrapFile(QString &fileName); BlackMisc::CStatusMessageList readLocalBootstrapFile(QString &fileName);
//! Trigger reading //! Trigger reading
BlackMisc::CStatusMessageList triggerReadSetup(); BlackMisc::CStatusMessageList triggerReadSetup();
//! Emit the availability signal and state //! Emit the availability signal and state and trigger follow up actions
//! \threadsafe //! \threadsafe
BlackMisc::CStatusMessageList manageSetupAvailability(bool webRead, bool localRead = false); BlackMisc::CStatusMessageList manageSetupAvailability(bool webRead, bool localRead = false);