refs #602, threadsafe access to central QNetworkAccessManager post/get

* threadsafe (used from workers)
* added post methods
* renamed functions to better refelct post/get
* use central QNetworkAccessManager in readers, removed local readers
This commit is contained in:
Klaus Basan
2016-02-24 00:03:53 +01:00
committed by Mathew Sutcliffe
parent 65af7d87da
commit 8a7eba74d9
11 changed files with 173 additions and 83 deletions

View File

@@ -10,6 +10,7 @@
#include "application.h"
#include "blackcore/corefacade.h"
#include "blackcore/setupreader.h"
#include "blackcore/webdataservices.h"
#include "blackcore/contextapplication.h"
#include "blackcore/registermetadata.h"
#include "blackcore/cookiemanager.h"
@@ -57,7 +58,8 @@ namespace BlackCore
QCoreApplication::instance()->installTranslator(&translator);
// Global setup / bootstraping
CCookieManager::instance(); // init cookie manager if ever needed
this->m_cookieManager.setParent(&this->m_accessManager);
this->m_accessManager.setCookieJar(&this->m_cookieManager);
// trigger loading of settings
//! \todo maybe loaded twice, context initializing might trigger loading of settings a second time
@@ -152,11 +154,29 @@ namespace BlackCore
}
}
QNetworkReply *CApplication::requestNetworkResource(const QNetworkRequest &request, const BlackMisc::CSlot<void(QNetworkReply *)> &callback)
bool CApplication::hasWebDataServices() const
{
return this->m_webDataServices;
}
CWebDataServices *CApplication::getWebDataServices() const
{
Q_ASSERT_X(this->m_webDataServices, Q_FUNC_INFO, "Missing web data services");
return this->m_webDataServices.data();
}
QNetworkReply *CApplication::getFromNetwork(const CUrl &url, const BlackMisc::CSlot<void (QNetworkReply *)> &callback)
{
if (this->m_shutdown) { return nullptr; }
return getFromNetwork(url.toNetworkRequest(), callback);
}
QNetworkReply *CApplication::getFromNetwork(const QNetworkRequest &request, const BlackMisc::CSlot<void(QNetworkReply *)> &callback)
{
if (this->m_shutdown) { return nullptr; }
QNetworkRequest r(request);
CNetworkUtils::ignoreSslVerification(r);
QWriteLocker locker(&m_accessManagerLock);
QNetworkReply *reply = this->m_accessManager.get(r);
if (callback)
{
@@ -165,6 +185,39 @@ namespace BlackCore
return reply;
}
QNetworkReply *CApplication::postToNetwork(const QNetworkRequest &request, const QByteArray &data, const BlackMisc::CSlot<void (QNetworkReply *)> &callback)
{
if (this->m_shutdown) { return nullptr; }
QNetworkRequest r(request);
CNetworkUtils::ignoreSslVerification(r);
QWriteLocker locker(&m_accessManagerLock);
QNetworkReply *reply = this->m_accessManager.post(r, data);
if (callback)
{
connect(reply, &QNetworkReply::finished, callback.object(), [ = ] { callback(reply); });
}
return reply;
}
QNetworkReply *CApplication::postToNetwork(const QNetworkRequest &request, QHttpMultiPart *multiPart, const BlackMisc::CSlot<void (QNetworkReply *)> &callback)
{
if (this->m_shutdown) { return nullptr; }
QNetworkRequest r(request);
CNetworkUtils::ignoreSslVerification(r);
QWriteLocker locker(&m_accessManagerLock);
QNetworkReply *reply = this->m_accessManager.post(r, multiPart);
if (callback)
{
connect(reply, &QNetworkReply::finished, callback.object(), [ = ] { callback(reply); });
}
return reply;
}
void CApplication::deleteAllCookies()
{
this->m_cookieManager.deleteAllCookies();
}
int CApplication::exec()
{
Q_ASSERT_X(instance(), Q_FUNC_INFO, "missing application");
@@ -195,6 +248,15 @@ namespace BlackCore
return this->startCoreFacade(); // will do nothing if setup is not yet loaded
}
bool CApplication::useWebDataServices(const CWebReaderFlags::WebReader webReader, CWebReaderFlags::DbReaderHint hint)
{
Q_ASSERT_X(this->m_webDataServices.isNull(), Q_FUNC_INFO, "Services already started");
this->m_webReader = webReader;
this->m_dbReaderHint = hint;
this->m_useWebData = true;
return this->startWebDataServices();
}
bool CApplication::startCoreFacade()
{
if (!this->m_useContexts) { return true; } // we do not use context, so no need to startup
@@ -203,6 +265,9 @@ namespace BlackCore
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");
Q_ASSERT_X(this->m_useWebData, Q_FUNC_INFO, "Need web data services");
this->startWebDataServices();
CLogMessage(this).info("Will start core facade now");
this->m_coreFacade.reset(new CCoreFacade(this->m_coreFacadeConfig));
@@ -210,6 +275,23 @@ namespace BlackCore
return true;
}
bool CApplication::startWebDataServices()
{
if (!this->m_useWebData) { return true; }
if (!this->m_parsed) { return false; }
if (!this->m_setupReader || !this->m_setupReader->isSetupSyncronized()) { return false; }
Q_ASSERT_X(this->m_setupReader, Q_FUNC_INFO, "No web data services without setup possible");
if (!this->m_webDataServices)
{
CLogMessage(this).info("Will start web data services now");
this->m_webDataServices.reset(
new CWebDataServices(this->m_webReader, this->m_dbReaderHint)
);
}
return true;
}
void CApplication::initLogging()
{
CLogHandler::instance()->install(); // make sure we have a log handler!
@@ -259,11 +341,6 @@ namespace BlackCore
sApp = nullptr;
disconnect(this);
if (this->m_setupReader)
{
this->m_setupReader->gracefulShutdown();
}
if (this->supportsContexts())
{
// clean up facade
@@ -271,6 +348,17 @@ namespace BlackCore
this->m_coreFacade.reset();
}
if (this->m_webDataServices)
{
this->m_webDataServices->gracefulShutdown();
this->m_webDataServices.reset();
}
if (this->m_setupReader)
{
this->m_setupReader->gracefulShutdown();
}
this->m_fileLogger->close();
}
@@ -280,8 +368,9 @@ namespace BlackCore
{
if (!this->m_started)
{
// follow up startup
this->m_started = this->startCoreFacade();
// follow up startups
bool s = this->startWebDataServices();
this->m_started = s && this->startCoreFacade();
}
}
this->m_startUpCompleted = true;

View File

@@ -13,6 +13,9 @@
#define BLACKCORE_APPLICATION_H
#include "corefacadeconfig.h"
#include "cookiemanager.h"
#include "webreaderflags.h"
#include "blackmisc/network/url.h"
#include "blackmisc/logcategorylist.h"
#include "blackmisc/filelogger.h"
#include "blackmisc/slot.h"
@@ -21,11 +24,13 @@
#include <QScopedPointer>
#include <QNetworkAccessManager>
#include <QCommandLineParser>
#include <atomic>
namespace BlackCore
{
class CCoreFacade;
class CSetupReader;
class CWebDataServices;
class IContextApplication;
class IContextAudio;
@@ -73,8 +78,27 @@ namespace BlackCore
bool waitForStart();
//! Request to get network reply
QNetworkReply *requestNetworkResource(const QNetworkRequest &request,
const BlackMisc::CSlot<void(QNetworkReply *)> &callback);
//! \threadsafe
QNetworkReply *getFromNetwork(const BlackMisc::Network::CUrl &url,
const BlackMisc::CSlot<void(QNetworkReply *)> &callback);
//! Request to get network reply
//! \threadsafe
QNetworkReply *getFromNetwork(const QNetworkRequest &request,
const BlackMisc::CSlot<void(QNetworkReply *)> &callback);
//! Post to network
//! \threadsafe
QNetworkReply *postToNetwork(const QNetworkRequest &request, const QByteArray &data,
const BlackMisc::CSlot<void(QNetworkReply *)> &callback);
//! Post to network
//! \threadsafe
QNetworkReply *postToNetwork(const QNetworkRequest &request, QHttpMultiPart *multiPart,
const BlackMisc::CSlot<void(QNetworkReply *)> &callback);
//! Delete all cookies from cookier manager
void deleteAllCookies();
//! Setup already syncronized
bool isSetupSyncronized() const;
@@ -82,6 +106,12 @@ namespace BlackCore
//! Reload setup and version
BlackMisc::CStatusMessage requestReloadOfSetupAndVersion();
//! Web data services available?
bool hasWebDataServices() const;
//! Get the web data services
CWebDataServices *getWebDataServices() const;
//! Run event loop
static int exec();
@@ -138,6 +168,10 @@ namespace BlackCore
//! \sa coreFacadeStarted
bool useContexts(const CCoreFacadeConfig &coreConfig);
//! Init web data services and start them
//! \sa webDataServicesStarted
bool useWebDataServices(const CWebReaderFlags::WebReader webReader, CWebReaderFlags::DbReaderHint hint);
//! Get the facade
CCoreFacade *getCoreFacade() { return m_coreFacade.data(); }
@@ -167,6 +201,9 @@ namespace BlackCore
//! Facade started
void coreFacadeStarted();
//! Web data services started
void webDataServicesStarted();
protected slots:
//! Setup read/syncronized
void ps_setupSyncronized(bool success);
@@ -196,13 +233,17 @@ namespace BlackCore
//! \note does nothing when setup is not yet loaded
bool startCoreFacade();
//! Start the web data services
//! \note does nothing when setup is not yet loaded
bool startWebDataServices();
//! 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_cmdVersion {"version"}; //!< version option
QCommandLineOption m_cmdDBusAddress {"empty"}; //!< DBus address
bool m_parsed = false; //!< Parsing accomplished?
bool m_started = false; //!< started with success?
@@ -221,12 +262,18 @@ namespace BlackCore
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
QReadWriteLock m_accessManagerLock; //!< lock to make accessmanager access threadsafe
CCoreFacadeConfig m_coreFacadeConfig; //!< Core facade config if any
bool m_shutdown = false; //!< is being shut down
CWebReaderFlags::WebReader m_webReader; //!< Readers used
CWebReaderFlags::DbReaderHint m_dbReaderHint; //!< Load or used caching?
std::atomic<bool> m_shutdown { false }; //!< is being shutdown?
bool m_useContexts = false; //!< use contexts
bool m_useWebData = false; //!< use web data
};
} // namespace

View File

@@ -8,7 +8,7 @@
*/
#include "databaseauthentication.h"
#include "blackcore/cookiemanager.h"
#include "blackcore/application.h"
#include "blackmisc/network/networkutils.h"
#include "blackmisc/network/url.h"
#include "blackmisc/logmessage.h"
@@ -26,11 +26,9 @@ using namespace BlackMisc::Network;
namespace BlackCore
{
CDatabaseAuthenticationService::CDatabaseAuthenticationService(QObject *parent) :
QObject(parent),
m_networkManager(new QNetworkAccessManager(this))
QObject(parent)
{
this->connect(this->m_networkManager, &QNetworkAccessManager::finished, this, &CDatabaseAuthenticationService::ps_parseServerResponse);
CCookieManager::setToAccessManager(this->m_networkManager);
// void
}
void CDatabaseAuthenticationService::gracefulShutdown()
@@ -67,8 +65,8 @@ namespace BlackCore
if (m_setup.get().dbDebugFlag()) { CNetworkUtils::addDebugFlag(params); }
QString query = params.toString();
QNetworkRequest request(CNetworkUtils::getNetworkRequest(url, CNetworkUtils::PostUrlEncoded));
QNetworkReply *r = this->m_networkManager->post(request, query.toUtf8());
const QNetworkRequest request(CNetworkUtils::getNetworkRequest(url, CNetworkUtils::PostUrlEncoded));
QNetworkReply *r = sApp->postToNetwork(request, query.toUtf8(), { this, &CDatabaseAuthenticationService::ps_parseServerResponse});
if (!r)
{
QString rm("Cannot send request to authentication server %1");
@@ -87,7 +85,7 @@ namespace BlackCore
CUrl url(this->m_setup.get().dbLoginServiceUrl());
url.setQuery("logoff=true");
QNetworkRequest request(CNetworkUtils::getNetworkRequest(url));
this->m_networkManager->get(request);
sApp->getFromNetwork(request, { this, &CDatabaseAuthenticationService::ps_parseServerResponse });
this->m_user.set(CAuthenticatedUser());
}
@@ -100,7 +98,7 @@ namespace BlackCore
QString urlString(nwReply->url().toString());
if (urlString.toLower().contains("logoff"))
{
CCookieManager::instance()->deleteAllCookies();
sApp->deleteAllCookies();
emit logoffFinished();
return;
}

View File

@@ -59,11 +59,9 @@ namespace BlackCore
void ps_userChanged();
private:
BlackMisc::CData<BlackCore::Data::GlobalSetup> m_setup {this}; //!< data cache
BlackMisc::CData<BlackCore::Data::GlobalSetup> m_setup {this}; //!< data cache
BlackMisc::CData<BlackCore::Data::AuthenticatedUser> m_user {this, &CDatabaseAuthenticationService::ps_userChanged};
QNetworkAccessManager *m_networkManager = nullptr;
bool m_shutdown = false;
bool m_shutdown = false;
};
} // namespace

View File

@@ -8,7 +8,7 @@
*/
#include "databasewriter.h"
#include "blackcore/cookiemanager.h"
#include "blackcore/application.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/datastoreutility.h"
#include "blackmisc/network/networkutils.h"
@@ -28,9 +28,7 @@ namespace BlackCore
QObject(parent),
m_modelPublishUrl(getModelPublishUrl(baseUrl))
{
this->m_networkManager = new QNetworkAccessManager(this);
CCookieManager::setToAccessManager(this->m_networkManager);
this->connect(this->m_networkManager, &QNetworkAccessManager::finished, this, &CDatabaseWriter::ps_postResponse);
// void
}
CStatusMessageList CDatabaseWriter::asyncPublishModels(const CAircraftModelList &models)
@@ -58,7 +56,7 @@ namespace BlackCore
multiPart->append(CNetworkUtils::getMultipartWithDebugFlag());
}
m_pendingReply = this->m_networkManager->post(request, multiPart);
m_pendingReply = sApp->postToNetwork(request, multiPart, { this, &CDatabaseWriter::ps_postResponse});
multiPart->setParent(m_pendingReply);
return msgs;
}

View File

@@ -49,7 +49,6 @@ namespace BlackCore
private:
BlackMisc::CData<BlackCore::Data::GlobalSetup> m_setup {this}; //!< data cache
BlackMisc::Network::CUrl m_modelPublishUrl;
QNetworkAccessManager *m_networkManager = nullptr;
QNetworkReply *m_pendingReply = nullptr;
bool m_shutdown = false;

View File

@@ -7,7 +7,7 @@
* contained in the LICENSE file.
*/
#include "blackcore/cookiemanager.h"
#include "blackcore/application.h"
#include "blackmisc/sequence.h"
#include "blackmisc/network/networkutils.h"
#include "blackmisc/logmessage.h"
@@ -31,16 +31,7 @@ namespace BlackCore
CIcaoDataReader::CIcaoDataReader(QObject *owner) :
CDatabaseReader(owner, "CIcaoDataReader")
{
this->m_networkManagerAircraft = new QNetworkAccessManager(this);
CCookieManager::setToAccessManager(this->m_networkManagerAircraft);
this->m_networkManagerAirlines = new QNetworkAccessManager(this);
CCookieManager::setToAccessManager(this->m_networkManagerAirlines);
this->m_networkManagerCountries = new QNetworkAccessManager(this);
CCookieManager::setToAccessManager(this->m_networkManagerCountries);
this->connect(this->m_networkManagerAircraft, &QNetworkAccessManager::finished, this, &CIcaoDataReader::ps_parseAircraftIcaoData);
this->connect(this->m_networkManagerAirlines, &QNetworkAccessManager::finished, this, &CIcaoDataReader::ps_parseAirlineIcaoData);
this->connect(this->m_networkManagerCountries, &QNetworkAccessManager::finished, this, &CIcaoDataReader::ps_parseCountryData);
// void
}
CAircraftIcaoCodeList CIcaoDataReader::getAircraftIcaoCodes() const
@@ -131,9 +122,6 @@ namespace BlackCore
void CIcaoDataReader::ps_read(BlackMisc::Network::CEntityFlags::Entity entities, const QDateTime &newerThan)
{
this->threadAssertCheck(); // runs in background thread
Q_ASSERT(this->m_networkManagerAircraft);
Q_ASSERT(this->m_networkManagerAirlines);
Q_ASSERT(this->m_networkManagerCountries);
CEntityFlags::Entity entitiesTriggered = CEntityFlags::NoEntity;
if (entities.testFlag(CEntityFlags::AircraftIcaoEntity))
@@ -142,8 +130,7 @@ namespace BlackCore
if (!url.isEmpty())
{
if (!newerThan.isNull()) { url.appendQuery("newer=" + newerThan.toString(Qt::ISODate)); }
QNetworkRequest requestAircraft(CNetworkUtils::getNetworkRequest(url));
this->m_networkManagerAircraft->get(requestAircraft);
sApp->getFromNetwork(url, { this, &CIcaoDataReader::ps_parseAircraftIcaoData });
entitiesTriggered |= CEntityFlags::AircraftIcaoEntity;
}
else
@@ -158,8 +145,7 @@ namespace BlackCore
if (!url.isEmpty())
{
if (!newerThan.isNull()) { url.appendQuery("newer=" + newerThan.toString(Qt::ISODate)); }
QNetworkRequest requestAirline(CNetworkUtils::getNetworkRequest(url));
this->m_networkManagerAirlines->get(requestAirline);
sApp->getFromNetwork(url, { this, &CIcaoDataReader::ps_parseAirlineIcaoData });
entitiesTriggered |= CEntityFlags::AirlineIcaoEntity;
}
else
@@ -174,8 +160,7 @@ namespace BlackCore
if (!url.isEmpty())
{
if (!newerThan.isNull()) { url.appendQuery("newer=" + newerThan.toString(Qt::ISODate)); }
QNetworkRequest requestCountry(CNetworkUtils::getNetworkRequest(url));
this->m_networkManagerCountries->get(requestCountry);
sApp->getFromNetwork(url, { this, &CIcaoDataReader::ps_parseCountryData });
entitiesTriggered |= CEntityFlags::CountryEntity;
}
else

View File

@@ -123,9 +123,6 @@ namespace BlackCore
void ps_read(BlackMisc::Network::CEntityFlags::Entity entities, const QDateTime &newerThan);
private:
QNetworkAccessManager *m_networkManagerAircraft = nullptr;
QNetworkAccessManager *m_networkManagerAirlines = nullptr;
QNetworkAccessManager *m_networkManagerCountries = nullptr;
BlackMisc::Aviation::CAircraftIcaoCodeList m_aircraftIcaos;
BlackMisc::Aviation::CAirlineIcaoCodeList m_airlineIcaos;
BlackMisc::CCountryList m_countries;

View File

@@ -7,7 +7,7 @@
* contained in the LICENSE file.
*/
#include "blackcore/cookiemanager.h"
#include "blackcore/application.h"
#include "blackmisc/sequence.h"
#include "blackmisc/logmessage.h"
#include "blackmisc/network/networkutils.h"
@@ -30,16 +30,7 @@ namespace BlackCore
CModelDataReader::CModelDataReader(QObject *owner) :
CDatabaseReader(owner, "CModelDataReader")
{
this->m_networkManagerLivery = new QNetworkAccessManager(this);
CCookieManager::setToAccessManager(this->m_networkManagerLivery);
this->m_networkManagerDistributor = new QNetworkAccessManager(this);
CCookieManager::setToAccessManager(this->m_networkManagerDistributor);
this->m_networkManagerModel = new QNetworkAccessManager(this);
CCookieManager::setToAccessManager(this->m_networkManagerModel);
this->connect(this->m_networkManagerLivery, &QNetworkAccessManager::finished, this, &CModelDataReader::ps_parseLiveryData);
this->connect(this->m_networkManagerDistributor, &QNetworkAccessManager::finished, this, &CModelDataReader::ps_parseDistributorData);
this->connect(this->m_networkManagerModel, &QNetworkAccessManager::finished, this, &CModelDataReader::ps_parseModelData);
// void
}
CLiveryList CModelDataReader::getLiveries() const
@@ -148,9 +139,6 @@ namespace BlackCore
void CModelDataReader::ps_read(CEntityFlags::Entity entity, const QDateTime &newerThan)
{
this->threadAssertCheck();
Q_ASSERT(this->m_networkManagerLivery);
Q_ASSERT(this->m_networkManagerDistributor);
Q_ASSERT(this->m_networkManagerModel);
CEntityFlags::Entity triggeredRead = CEntityFlags::NoEntity;
if (entity.testFlag(CEntityFlags::LiveryEntity))
@@ -163,9 +151,7 @@ namespace BlackCore
const QString tss(newerThan.toString(Qt::ISODate));
url.appendQuery(QString(parameterLatestTimestamp() + "=" + tss));
}
QNetworkRequest requestLivery(url);
CNetworkUtils::ignoreSslVerification(requestLivery);
this->m_networkManagerLivery->get(requestLivery);
sApp->getFromNetwork(url, { this, &CModelDataReader::ps_parseLiveryData});
triggeredRead |= CEntityFlags::LiveryEntity;
}
else
@@ -184,9 +170,7 @@ namespace BlackCore
const QString tss(newerThan.toString(Qt::ISODate));
url.appendQuery(QString(parameterLatestTimestamp() + "=" + tss));
}
QNetworkRequest requestDistributor(url);
CNetworkUtils::ignoreSslVerification(requestDistributor);
this->m_networkManagerDistributor->get(requestDistributor);
sApp->getFromNetwork(url, { this, &CModelDataReader::ps_parseDistributorData});
triggeredRead |= CEntityFlags::DistributorEntity;
}
else
@@ -205,9 +189,7 @@ namespace BlackCore
const QString tss(newerThan.toString(Qt::ISODate));
url.appendQuery(QString(parameterLatestTimestamp() + "=" + tss));
}
QNetworkRequest requestModel(url);
CNetworkUtils::ignoreSslVerification(requestModel);
this->m_networkManagerModel->get(requestModel);
sApp->getFromNetwork(url, { this, &CModelDataReader::ps_parseModelData});
triggeredRead |= CEntityFlags::ModelEntity;
}
else

View File

@@ -133,9 +133,6 @@ namespace BlackCore
void ps_read(BlackMisc::Network::CEntityFlags::Entity entity = BlackMisc::Network::CEntityFlags::DistributorLiveryModel, const QDateTime &newerThan = QDateTime());
private:
QNetworkAccessManager *m_networkManagerLivery = nullptr;
QNetworkAccessManager *m_networkManagerDistributor = nullptr;
QNetworkAccessManager *m_networkManagerModel = nullptr;
BlackMisc::Aviation::CLiveryList m_liveries;
BlackMisc::Simulation::CDistributorList m_distributors;
BlackMisc::Simulation::CAircraftModelList m_models;

View File

@@ -147,7 +147,7 @@ namespace BlackCore
return;
}
if (m_shutdown) { return; }
sApp->requestNetworkResource(url.toNetworkRequest(), { this, &CSetupReader::ps_parseSetupFile });
sApp->getFromNetwork(url.toNetworkRequest(), { this, &CSetupReader::ps_parseSetupFile });
}
void CSetupReader::ps_readUpdateInfo()
@@ -160,7 +160,7 @@ namespace BlackCore
return;
}
if (m_shutdown) { return; }
sApp->requestNetworkResource(url.toNetworkRequest(), { this, &CSetupReader::ps_parseUpdateInfoFile});
sApp->getFromNetwork(url.toNetworkRequest(), { this, &CSetupReader::ps_parseUpdateInfoFile});
}
void CSetupReader::ps_setupSyncronized(bool success)