mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-24 07:55:35 +08:00
refs #470, read and update URLs from server
This commit is contained in:
committed by
Mathew Sutcliffe
parent
cba40a8ca4
commit
54ed4140d3
201
src/blackcore/setupreader.cpp
Normal file
201
src/blackcore/setupreader.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackmisc/network/networkutils.h"
|
||||
#include "blackmisc/sequence.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "blackmisc/json.h"
|
||||
#include "blackmisc/project.h"
|
||||
#include "blackmisc/fileutilities.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "setupreader.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QDateTime>
|
||||
|
||||
using namespace BlackMisc;
|
||||
using namespace BlackMisc::Network;
|
||||
using namespace BlackCore;
|
||||
using namespace BlackCore::Data;
|
||||
|
||||
namespace BlackCore
|
||||
{
|
||||
CSetupReader::CSetupReader(QObject *owner) :
|
||||
CThreadedReader(owner, "CSetupReader")
|
||||
{
|
||||
QString localFileName;
|
||||
if (localFile(localFileName))
|
||||
{
|
||||
// initialized by local file for testing
|
||||
// I do not even need to start in background here
|
||||
CLogMessage(this).info("Using local bootstrap file: %1") << localFileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->m_networkManager = new QNetworkAccessManager(this);
|
||||
this->connect(this->m_networkManager, &QNetworkAccessManager::finished, this, &CSetupReader::ps_parseSetupFile);
|
||||
this->start(QThread::LowPriority);
|
||||
}
|
||||
}
|
||||
|
||||
void CSetupReader::initialize()
|
||||
{
|
||||
CThreadedReader::initialize();
|
||||
QTimer::singleShot(500, this, &CSetupReader::ps_read);
|
||||
}
|
||||
|
||||
void CSetupReader::ps_read()
|
||||
{
|
||||
this->threadAssertCheck();
|
||||
Q_ASSERT_X(this->m_networkManager, Q_FUNC_INFO, "Missing network manager");
|
||||
CUrlList urls(getRemainingUrls());
|
||||
if (urls.isEmpty()) { return; }
|
||||
int urlsSize = urls.size();
|
||||
|
||||
QUrl url(urls.getNextUrl(false));
|
||||
if (urlsSize > 1)
|
||||
{
|
||||
// more than one URL one, quick check if this can be contacted
|
||||
QString m;
|
||||
if (!CNetworkUtils::canConnect(url, m))
|
||||
{
|
||||
m_failedUrls.push_back(url);
|
||||
CLogMessage(this).warning("Cannot connect to %1") << url.toString();
|
||||
url = urls.getNextUrl();
|
||||
}
|
||||
}
|
||||
|
||||
// now I have the first or second URL for reading
|
||||
if (url.isEmpty()) { return; }
|
||||
QNetworkRequest request(url);
|
||||
CNetworkUtils::ignoreSslVerification(request);
|
||||
|
||||
// request
|
||||
this->m_networkManager->get(request);
|
||||
}
|
||||
|
||||
bool CSetupReader::localFile(QString &fileName)
|
||||
{
|
||||
QString dir(CProject::getSwiftPrivateResourceDir());
|
||||
if (dir.isEmpty()) { return false; }
|
||||
|
||||
fileName = CFileUtils::appendFilePaths(dir, "bootstrap/setup.json");
|
||||
QString content(CFileUtils::readFileToString(fileName));
|
||||
if (content.isEmpty()) { return false; }
|
||||
CGlobalSetup s;
|
||||
s.convertFromJson(content);
|
||||
m_setup.set(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
CUrlList CSetupReader::getRemainingUrls() const
|
||||
{
|
||||
CUrlList urls(m_setup.get().bootstrapUrls().appendPath(appendPathAndFile()));
|
||||
urls.removeIfIn(m_failedUrls);
|
||||
return urls;
|
||||
}
|
||||
|
||||
QString CSetupReader::appendPathAndFile()
|
||||
{
|
||||
return CProject::useDevelopmentSetup() ?
|
||||
"development/bootstrap.json" :
|
||||
"productive/bootstrap.json";
|
||||
}
|
||||
|
||||
void CSetupReader::ps_parseSetupFile(QNetworkReply *nwReplyPtr)
|
||||
{
|
||||
// wrap pointer, make sure any exit cleans up reply
|
||||
// required to use delete later as object is created in a different thread
|
||||
QScopedPointer<QNetworkReply, QScopedPointerDeleteLater> nwReply(nwReplyPtr);
|
||||
QUrl url(nwReply->url());
|
||||
QString urlString(url.toString());
|
||||
QString replyMessage(nwReply->errorString());
|
||||
|
||||
this->threadAssertCheck();
|
||||
if (this->isFinished())
|
||||
{
|
||||
CLogMessage(this).debug() << Q_FUNC_INFO;
|
||||
CLogMessage(this).info("Terminated loading bootstrap files");
|
||||
nwReply->abort();
|
||||
return; // stop, terminate straight away, ending thread
|
||||
}
|
||||
|
||||
if (nwReply->error() == QNetworkReply::NoError)
|
||||
{
|
||||
qint64 lastModified = -1;
|
||||
QVariant lastModifiedQv = nwReply->header(QNetworkRequest::LastModifiedHeader);
|
||||
if (lastModifiedQv.isValid() && lastModifiedQv.canConvert<QDateTime>())
|
||||
{
|
||||
lastModified = lastModifiedQv.value<QDateTime>().toMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
QString setupJson(nwReplyPtr->readAll());
|
||||
nwReplyPtr->close();
|
||||
if (setupJson.isEmpty())
|
||||
{
|
||||
CLogMessage(this).info("No bootstrap setup file");
|
||||
m_failedUrls.push_back(url);
|
||||
// try next URL
|
||||
}
|
||||
else
|
||||
{
|
||||
CGlobalSetup gs;
|
||||
gs.convertFromJson(Json::jsonObjectFromString(setupJson));
|
||||
if (gs.getMSecsSinceEpoch() == 0 && lastModified > 0) { gs.setMSecsSinceEpoch(lastModified); }
|
||||
qint64 currentVersionTimestamp = m_setup.get().getMSecsSinceEpoch();
|
||||
qint64 newVersionTimestamp = gs.getMSecsSinceEpoch();
|
||||
bool newVersionLoaded = (newVersionTimestamp - currentVersionTimestamp) > 0;
|
||||
bool sameVersionLoaded = newVersionTimestamp == currentVersionTimestamp;
|
||||
if (sameVersionLoaded)
|
||||
{
|
||||
CLogMessage(this).info("Same version loaded from %1 as already in data cache %2") << urlString << CDataCache::persistentStore();
|
||||
return; // success
|
||||
}
|
||||
|
||||
CStatusMessage m = m_setup.set(gs);
|
||||
if (!m.isEmpty())
|
||||
{
|
||||
CLogMessage(this).preformatted(m);
|
||||
return; // issue with cache
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newVersionLoaded)
|
||||
{
|
||||
CLogMessage(this).info("Updated data cache in %1") << CDataCache::persistentStore();
|
||||
return; // success
|
||||
}
|
||||
else
|
||||
{
|
||||
CLogMessage(this).warning("Local bootstrap file in %1 newer than URL %2") << CDataCache::persistentStore() << urlString;
|
||||
// try next URL
|
||||
}
|
||||
} // cache
|
||||
} // json empty
|
||||
} // no error
|
||||
else
|
||||
{
|
||||
// network error
|
||||
CLogMessage(this).warning("Reading setup failed %1 %2") << replyMessage << urlString;
|
||||
nwReply->abort();
|
||||
}
|
||||
|
||||
// try next one if any
|
||||
const int maxTrials = 2;
|
||||
m_failedUrls.push_back(url);
|
||||
if (m_failedUrls.size() >= maxTrials) { return; }
|
||||
|
||||
int urlsNo = getRemainingUrls().size();
|
||||
if (urlsNo >= 0)
|
||||
{
|
||||
QTimer::singleShot(500, this, &CSetupReader::ps_read);
|
||||
}
|
||||
} // method
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user