From 07c6370819dde54230637a91334aef6e619c3318 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Wed, 23 Sep 2015 19:05:31 +0200 Subject: [PATCH] refs #452, data readers / writers for DB (via web services) * flags for readers (which reader is reading specific entities etc.) * web data services: bundling multiple readers (webdataservices) and implementing IWebDataReaderProvider * readers now able to read single entities --- src/blackcore/blackcorefreefunctions.cpp | 13 +- src/blackcore/databasereader.cpp | 62 ++-- src/blackcore/databasereader.h | 42 ++- src/blackcore/databasewriter.cpp | 135 +++++++ src/blackcore/databasewriter.h | 60 +++ src/blackcore/icaodatareader.cpp | 204 ++++++++++- src/blackcore/icaodatareader.h | 74 +++- src/blackcore/modeldatareader.cpp | 183 ++++++++-- src/blackcore/modeldatareader.h | 51 ++- src/blackcore/web_datareader.cpp | 287 --------------- src/blackcore/web_datareader.h | 188 ---------- src/blackcore/webdataservices.cpp | 447 +++++++++++++++++++++++ src/blackcore/webdataservices.h | 266 ++++++++++++++ src/blackcore/webreaderflags.cpp | 55 +++ src/blackcore/webreaderflags.h | 57 +++ 15 files changed, 1538 insertions(+), 586 deletions(-) create mode 100644 src/blackcore/databasewriter.cpp create mode 100644 src/blackcore/databasewriter.h delete mode 100644 src/blackcore/web_datareader.cpp delete mode 100644 src/blackcore/web_datareader.h create mode 100644 src/blackcore/webdataservices.cpp create mode 100644 src/blackcore/webdataservices.h create mode 100644 src/blackcore/webreaderflags.cpp create mode 100644 src/blackcore/webreaderflags.h diff --git a/src/blackcore/blackcorefreefunctions.cpp b/src/blackcore/blackcorefreefunctions.cpp index fd54cc238..47b73953c 100644 --- a/src/blackcore/blackcorefreefunctions.cpp +++ b/src/blackcore/blackcorefreefunctions.cpp @@ -4,6 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "blackcorefreefunctions.h" +#include "blackcore/webreaderflags.h" + #include "voice_channel.h" #include "network.h" #include "simulator.h" @@ -13,8 +15,15 @@ namespace BlackCore { void registerMetadata() { - qRegisterMetaType(); - qRegisterMetaType(); + int id; + id = qRegisterMetaType(); + Q_ASSERT_X(id >= 1024, Q_FUNC_INFO, "wrong id for metatype"); + id = qRegisterMetaType(); + Q_ASSERT_X(id >= 1024, Q_FUNC_INFO, "wrong id for metatype"); + id = qRegisterMetaType(); + Q_ASSERT_X(id >= 1024, Q_FUNC_INFO, "wrong id for metatype"); + id = qRegisterMetaType(); + Q_UNUSED(id); } bool isCurrentThreadObjectThread(QObject *toBeTested) diff --git a/src/blackcore/databasereader.cpp b/src/blackcore/databasereader.cpp index bbe9c094e..421554819 100644 --- a/src/blackcore/databasereader.cpp +++ b/src/blackcore/databasereader.cpp @@ -9,8 +9,11 @@ #include "databasereader.h" #include "blackmisc/logmessage.h" +#include "blackmisc/datastoreutility.h" +#include using namespace BlackMisc; +using namespace BlackMisc::Network; namespace BlackCore { @@ -18,54 +21,61 @@ namespace BlackCore BlackMisc::CThreadedReader(owner, name) { } - void CDatabaseReader::readInBackgroundThread() + void CDatabaseReader::readInBackgroundThread(CDbFlags::Entity entities) { - bool s = QMetaObject::invokeMethod(this, "ps_read"); + if (m_shutdown) { return; } + bool s = QMetaObject::invokeMethod(this, "ps_read", Q_ARG(BlackMisc::Network::CDbFlags::Entity, entities)); Q_ASSERT_X(s, Q_FUNC_INFO, "Invoke failed"); Q_UNUSED(s); } - QJsonArray CDatabaseReader::transformReplyIntoJsonArray(QNetworkReply *nwReply) const + CDatabaseReader::JsonDatastoreResponse CDatabaseReader::transformReplyIntoDatastoreResponse(QNetworkReply *nwReply) const { this->threadAssertCheck(); - QJsonArray array; - if (this->isFinished()) + JsonDatastoreResponse datastoreResponse; + if (m_shutdown || this->isFinished()) { CLogMessage(this).debug() << Q_FUNC_INFO; CLogMessage(this).info("Terminated data parsing process"); // for users - return array; // stop, terminate straight away, ending thread + nwReply->abort(); + return datastoreResponse; // stop, terminate straight away, ending thread } if (nwReply->error() == QNetworkReply::NoError) { - const QString dataFileData = nwReply->readAll(); + const QString dataFileData = nwReply->readAll().trimmed(); nwReply->close(); // close asap - if (dataFileData.isEmpty()) { return array; } + if (dataFileData.isEmpty()) { datastoreResponse.updated = QDateTime::currentDateTimeUtc(); return datastoreResponse; } QJsonDocument jsonResponse = QJsonDocument::fromJson(dataFileData.toUtf8()); - QJsonObject jsonObject = jsonResponse.object(); - QJsonArray jsonArray = jsonObject["rows"].toArray(); - return jsonArray; + if (jsonResponse.isArray()) + { + // directly an array, no further info + datastoreResponse.jsonArray = jsonResponse.array(); + datastoreResponse.updated = QDateTime::currentDateTimeUtc(); + } + else + { + QJsonObject responseObject(jsonResponse.object()); + datastoreResponse.jsonArray = responseObject["data"].toArray(); + QString ts(responseObject["latest"].toString()); + datastoreResponse.updated = ts.isEmpty() ? QDateTime::currentDateTimeUtc() : CDatastoreUtility::parseTimestamp(ts); + } + return datastoreResponse; } - CLogMessage(this).warning("Reading data failed %1 %2") << nwReply->errorString() << nwReply->url().toString(); + + // no valid response + QString error(nwReply->errorString()); + QString url(nwReply->url().toString()); + CLogMessage(this).warning("Reading data failed %1 %2") << error << url; nwReply->abort(); - return array; + return datastoreResponse; } - QString CDatabaseReader::buildUrl(const QString &protocol, const QString &server, const QString &baseUrl, const QString &serviceUrl) + bool CDatabaseReader::canConnect() const { - Q_ASSERT_X(protocol.length() > 3, Q_FUNC_INFO, "worng protocol"); - Q_ASSERT_X(!server.isEmpty(), Q_FUNC_INFO, "missing server"); - Q_ASSERT_X(!serviceUrl.isEmpty(), Q_FUNC_INFO, "missing service URL"); - - QString url(server); - if (!baseUrl.isEmpty()) - { - url.append("/").append(baseUrl); - } - url.append("/").append(serviceUrl); - url.replace("//", "/"); - return protocol + "://" + url; + QString m; + return canConnect(m); } } // namespace diff --git a/src/blackcore/databasereader.h b/src/blackcore/databasereader.h index be36620b3..365d8e393 100644 --- a/src/blackcore/databasereader.h +++ b/src/blackcore/databasereader.h @@ -14,8 +14,10 @@ #include "blackcore/blackcoreexport.h" #include "blackmisc/threadedreader.h" +#include "blackmisc/network/dbflags.h" #include #include +#include namespace BlackCore { @@ -26,19 +28,47 @@ namespace BlackCore Q_OBJECT public: + //! Response from our database + struct JsonDatastoreResponse + { + QJsonArray jsonArray; //!< JSON array data + QDateTime updated; //!< when updated + + //! Any data? + bool isEmpty() const { return jsonArray.isEmpty(); } + + //! Number of elements + int size() const { return jsonArray.size(); } + + //! Any timestamp? + bool hasTimestamp() const { return updated.isValid(); } + + //! Is response newer? + bool isNewer(const QDateTime &ts) const { return updated.toMSecsSinceEpoch() > ts.toMSecsSinceEpoch(); } + + //! Is response newer? + bool isNewer(qint64 mSecsSinceEpoch) const { return updated.toMSecsSinceEpoch() > mSecsSinceEpoch; } + + //! Implicit conversion + operator QJsonArray() const { return jsonArray; } + }; + //! Start reading in own thread - void readInBackgroundThread(); + void readInBackgroundThread(BlackMisc::Network::CDbFlags::Entity entities); + + //! Can connect to DB + bool canConnect() const; + + //! Can connect to server? + //! \return message why connect failed + virtual bool canConnect(QString &message) const = 0; protected: //! Constructor CDatabaseReader(QObject *owner, const QString &name); //! Check if terminated or error, otherwise split into array of objects - QJsonArray transformReplyIntoJsonArray(QNetworkReply *nwReply) const; - - //! Build service URL - static QString buildUrl(const QString &protocol, const QString &server, const QString &baseUrl, const QString &serviceUrl); - + JsonDatastoreResponse transformReplyIntoDatastoreResponse(QNetworkReply *nwReply) const; }; } // namespace diff --git a/src/blackcore/databasewriter.cpp b/src/blackcore/databasewriter.cpp new file mode 100644 index 000000000..517867dc8 --- /dev/null +++ b/src/blackcore/databasewriter.cpp @@ -0,0 +1,135 @@ +/* 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 "databasewriter.h" +#include "blackmisc/logmessage.h" +#include "blackmisc/datastoreutility.h" +#include "blackmisc/networkutils.h" +#include +#include +#include +#include + +using namespace BlackMisc; +using namespace BlackMisc::Simulation; + +namespace BlackCore +{ + CDatabaseWriter::CDatabaseWriter(const QString &protocol, const QString &server, const QString &baseUrl, QObject *parent) : + QObject(parent), + m_modelUrl(getModelWriteUrl(protocol, server, baseUrl)) + { + this->m_networkManager = new QNetworkAccessManager(this); + this->connect(this->m_networkManager, &QNetworkAccessManager::finished, this, &CDatabaseWriter::ps_postResponse); + } + + CStatusMessageList CDatabaseWriter::asyncWriteModel(const CAircraftModel &model) + { + CStatusMessageList msg; + if (m_shutdown) + { + msg.push_back(CStatusMessage(CStatusMessage::SeverityWarning, "Database writer shuts down")); + return msg; + } + + if (m_pendingReply) + { + msg.push_back(CStatusMessage(CStatusMessage::SeverityWarning, "Another write operation in progress")); + return msg; + } + + QUrl url(m_modelUrl); + QNetworkRequest request(url); + const QByteArray jsonData(QJsonDocument(model.toJson()).toJson(QJsonDocument::Compact)); + QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + QHttpPart textPart; + QString name("form-data; name=\"swiftjson\""); + textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(name)); + textPart.setBody(jsonData); + multiPart->append(textPart); + + if (m_phpDebug) + { + QHttpPart textPartDebug; + textPartDebug.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"XDEBUG_SESSION_START\"")); + textPartDebug.setBody(QString("ECLIPSE_DBGP").toUtf8()); + multiPart->append(textPartDebug); + } + + m_pendingReply = this->m_networkManager->post(request, multiPart); + multiPart->setParent(m_pendingReply); + return msg; + } + + void CDatabaseWriter::gracefulShutdown() + { + m_shutdown = true; + if (m_pendingReply) + { + m_pendingReply->abort(); + m_pendingReply = nullptr; + } + } + + void CDatabaseWriter::ps_postResponse(QNetworkReply *nwReplyPtr) + { + QScopedPointer nwReply(nwReplyPtr); + m_pendingReply = nullptr; + + if (m_shutdown) + { + nwReply->abort(); + return; + } + + if (nwReply->error() == QNetworkReply::NoError) + { + const QString dataFileData(nwReply->readAll().trimmed()); + nwReply->close(); // close asap + + if (dataFileData.isEmpty()) + { + CLogMessage(this).error("No response data"); + return; + } + + CStatusMessageList msgs; + CVariant id; + bool success = CDatastoreUtility::parseSwiftWriteResponse(dataFileData, msgs, id); + CLogMessage(this).preformatted(msgs); + Q_UNUSED(success); + } + else + { + QString error = nwReply->errorString(); + nwReply->close(); // close asap + CLogMessage(this).error(error); + } + } + + QString CDatabaseWriter::getModelWriteUrl(const QString &protocol, const QString &server, const QString &baseUrl) + { + return CNetworkUtils::buildUrl(protocol, server, baseUrl, "service/swiftwritemodel.php"); + } + + QList CDatabaseWriter::splitData(const QByteArray &data, int size) + { + if (data.size() <= size) { return QList({data}); } + int pos = 0, arrsize = data.size(); + QList arrays; + while (pos < arrsize) + { + QByteArray arr = data.mid(pos, size); + arrays << arr; + pos += arr.size(); + } + return arrays; + } + +} // namespace diff --git a/src/blackcore/databasewriter.h b/src/blackcore/databasewriter.h new file mode 100644 index 000000000..7b6fc6176 --- /dev/null +++ b/src/blackcore/databasewriter.h @@ -0,0 +1,60 @@ +/* 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. + */ + +#ifndef BLACKCORE_DATABASE_WRITER_H +#define BLACKCORE_DATABASE_WRITER_H + +//! \file + +#include "blackcore/blackcoreexport.h" +#include "blackmisc/threadedreader.h" +#include "blackmisc/simulation/aircraftmodel.h" + +#include +#include +#include + +namespace BlackCore +{ + //! Write to the swift DB + class BLACKCORE_EXPORT CDatabaseWriter : public QObject + { + Q_OBJECT + + public: + //! Constructor + CDatabaseWriter(const QString &protocol, const QString &server, const QString &baseUrl, QObject *parent); + + //! Write model to DB + BlackMisc::CStatusMessageList asyncWriteModel(const BlackMisc::Simulation::CAircraftModel &model); + + //! Shutdown + void gracefulShutdown(); + + private slots: + //! Post response + void ps_postResponse(QNetworkReply *nwReplyPtr); + + private: + QString m_modelUrl; + QNetworkAccessManager *m_networkManager = nullptr; + QNetworkReply *m_pendingReply = nullptr; + bool m_shutdown = false; + bool m_phpDebug = true; + + //! URL model web service + static QString getModelWriteUrl(const QString &protocol, const QString &server, const QString &baseUrl); + + //! Split data array + static QList splitData(const QByteArray &data, int size); + + }; +} // namespace + +#endif // guard diff --git a/src/blackcore/icaodatareader.cpp b/src/blackcore/icaodatareader.cpp index d1fc3f862..f6720a3d8 100644 --- a/src/blackcore/icaodatareader.cpp +++ b/src/blackcore/icaodatareader.cpp @@ -9,24 +9,30 @@ #include "blackmisc/sequence.h" #include "blackmisc/logmessage.h" +#include "blackmisc/networkutils.h" #include "icaodatareader.h" #include using namespace BlackMisc; using namespace BlackMisc::Aviation; +using namespace BlackMisc::Network; namespace BlackCore { CIcaoDataReader::CIcaoDataReader(QObject *owner, const QString &protocol, const QString &server, const QString &baseUrl) : CDatabaseReader(owner, "CIcaoDataReader"), - m_urlAircraftIcao(getAircraftIcaoUrl(protocol, server, baseUrl)), m_urlAirlineIcao(getAirlineIcaoUrl(protocol, server, baseUrl)) + m_urlAircraftIcao(getAircraftIcaoUrl(protocol, server, baseUrl)), + m_urlAirlineIcao(getAirlineIcaoUrl(protocol, server, baseUrl)), + m_urlCountry(getCountryUrl(protocol, server, baseUrl)) { this->m_networkManagerAircraft = new QNetworkAccessManager(this); this->m_networkManagerAirlines = new QNetworkAccessManager(this); + this->m_networkManagerCountries = new QNetworkAccessManager(this); 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); } CAircraftIcaoCodeList CIcaoDataReader::getAircraftIcaoCodes() const @@ -35,12 +41,99 @@ namespace BlackCore return m_aircraftIcaos; } + CAircraftIcaoCode CIcaoDataReader::getAircraftIcaoCodeForDesignator(const QString &designator) const + { + return getAircraftIcaoCodes().findFirstByDesignatorAndRank(designator); + } + + CAircraftIcaoCode CIcaoDataReader::getAircraftIcaoCodeForDbKey(int key) const + { + return getAircraftIcaoCodes().findByKey(key); + } + CAirlineIcaoCodeList CIcaoDataReader::getAirlineIcaoCodes() const { QReadLocker l(&m_lockAirline); return m_airlineIcaos; } + CAircraftIcaoCode CIcaoDataReader::smartAircraftIcaoSelector(const CAircraftIcaoCode &icao) const + { + CAircraftIcaoCodeList codes(getAircraftIcaoCodes()); // thread safe copy + if (icao.hasValidDbKey()) + { + int k = icao.getDbKey(); + CAircraftIcaoCode c(codes.findByKey(k)); + if (c.hasCompleteData()) { return c; } + } + + if (icao.hasKnownDesignator()) + { + const QString d(icao.getDesignator()); + codes = codes.findByDesignator(d); + if (codes.size() == 1) { return codes.front(); } + if (codes.isEmpty()) { return icao; } + codes.sortByRank(); + + // intentionally continue here + } + + // further reduce by manufacturer + if (icao.hasManufacturer()) + { + const QString m(icao.getManufacturer()); + codes = codes.findByManufacturer(m); + if (codes.size() == 1) { return codes.front(); } + if (codes.isEmpty()) { return icao; } + + // intentionally continue here + } + + // lucky punch on description? + if (icao.hasModelDescription()) + { + // do not affect codes here, it might return no results + const QString d(icao.getModelDescription()); + CAircraftIcaoCodeList cm(codes.findByDescription(d)); + if (cm.size() == 1) { return cm.front(); } + if (cm.size() > 1 && cm.size() < codes.size()) { return codes.front(); } + } + return codes.frontOrDefault(); // sorted by rank + } + + CCountryList CIcaoDataReader::getCountries() const + { + QReadLocker l(&m_lockCountry); + return m_countries; + } + + CCountry CIcaoDataReader::getCountryForIsoCode(const QString &isoCode) const + { + QReadLocker l(&m_lockCountry); + return m_countries.findByIsoCode(isoCode); + } + + CCountry CIcaoDataReader::getCountryForName(const QString &name) const + { + QReadLocker l(&m_lockCountry); + return m_countries.findBestMatchByCountryName(name); + } + + CAirlineIcaoCode CIcaoDataReader::getAirlineIcaoCodeForDesignator(const QString &designator) const + { + return getAirlineIcaoCodes().findByVDesignator(designator); + } + + CAirlineIcaoCode CIcaoDataReader::getAirlineIcaoCodeForDbKey(int key) const + { + return getAirlineIcaoCodes().findByKey(key); + } + + CAirlineIcaoCode CIcaoDataReader::smartAirlineIcaoSelector(const CAirlineIcaoCode &icao) const + { + return icao; + } + int CIcaoDataReader::getAircraftIcaoCodesCount() const { QReadLocker l(&m_lockAircraft); @@ -53,27 +146,50 @@ namespace BlackCore return m_airlineIcaos.size(); } - QString CIcaoDataReader::getAircraftIcaoUrl(const QString &protocol, const QString &server, const QString &baseUrl) + bool CIcaoDataReader::areAllDataRead() const { - return buildUrl(protocol, server, baseUrl, "service/allaircrafticao.php?rows=20000&sord=asc"); + return getCountriesCount() > 0 && getAirlineIcaoCodesCount() > 0 && getAircraftIcaoCodesCount() > 0; } - QString CIcaoDataReader::getAirlineIcaoUrl(const QString &protocol, const QString &server, const QString &baseUrl) + int CIcaoDataReader::getCountriesCount() const { - return buildUrl(protocol, server, baseUrl, "service/allairlineicao.php?rows=20000&sord=asc"); + QReadLocker l(&m_lockCountry); + return m_countries.size(); } - void CIcaoDataReader::ps_read() + void CIcaoDataReader::ps_read(BlackMisc::Network::CDbFlags::Entity entities) { this->threadAssertCheck(); Q_ASSERT(this->m_networkManagerAircraft); Q_ASSERT(this->m_networkManagerAirlines); + Q_ASSERT(this->m_networkManagerCountries); Q_ASSERT(!m_urlAircraftIcao.isEmpty()); Q_ASSERT(!m_urlAirlineIcao.isEmpty()); - QNetworkRequest requestAircraft(m_urlAircraftIcao); - QNetworkRequest requestAirline(m_urlAirlineIcao); - this->m_networkManagerAircraft->get(requestAircraft); - this->m_networkManagerAirlines->get(requestAirline); + Q_ASSERT(!m_urlCountry.isEmpty()); + + CDbFlags::Entity entitiesTriggered = CDbFlags::NoEntity; + if (entities.testFlag(CDbFlags::AircraftIcaoEntity)) + { + QNetworkRequest requestAircraft(m_urlAircraftIcao); + this->m_networkManagerAircraft->get(requestAircraft); + entitiesTriggered |= CDbFlags::AircraftIcaoEntity; + } + + if (entities.testFlag(CDbFlags::AirlineIcaoEntity)) + { + QNetworkRequest requestAirline(m_urlAirlineIcao); + this->m_networkManagerAirlines->get(requestAirline); + entitiesTriggered |= CDbFlags::AirlineIcaoEntity; + } + + if (entities.testFlag(CDbFlags::CountryEntity)) + { + QNetworkRequest requestCountry(m_urlCountry); + this->m_networkManagerCountries->get(requestCountry); + entitiesTriggered |= CDbFlags::CountryEntity; + } + + emit readData(entitiesTriggered, CDbFlags::StartRead, 0); } void CIcaoDataReader::ps_parseAircraftIcaoData(QNetworkReply *nwReplyPtr) @@ -81,8 +197,12 @@ namespace BlackCore // wrap pointer, make sure any exit cleans up reply // required to use delete later as object is created in a different thread QScopedPointer nwReply(nwReplyPtr); - QJsonArray array = this->transformReplyIntoJsonArray(nwReply.data()); - if (array.isEmpty()) { return; } + QJsonArray array = this->transformReplyIntoDatastoreResponse(nwReply.data()); + if (array.isEmpty()) + { + emit readData(CDbFlags::AircraftIcaoEntity, CDbFlags::ReadFailed, 0); + return; + } CAircraftIcaoCodeList codes = CAircraftIcaoCodeList::fromDatabaseJson(array); // this part needs to be synchronized @@ -92,15 +212,18 @@ namespace BlackCore this->m_aircraftIcaos = codes; n = codes.size(); } - emit readAircraftIcaoCodes(n); - if (this->getAirlineIcaoCodesCount() > 0) { emit readAll(); } + emit readData(CDbFlags::AircraftIcaoEntity, CDbFlags::ReadFinished, n); } void CIcaoDataReader::ps_parseAirlineIcaoData(QNetworkReply *nwReplyPtr) { QScopedPointer nwReply(nwReplyPtr); - QJsonArray array = this->transformReplyIntoJsonArray(nwReply.data()); - if (array.isEmpty()) { return; } + QJsonArray array = this->transformReplyIntoDatastoreResponse(nwReply.data()); + if (array.isEmpty()) + { + emit readData(CDbFlags::AirlineIcaoEntity, CDbFlags::ReadFailed, 0); + return; + } CAirlineIcaoCodeList codes = CAirlineIcaoCodeList::fromDatabaseJson(array); // this part needs to be synchronized @@ -110,7 +233,52 @@ namespace BlackCore this->m_airlineIcaos = codes; n = codes.size(); } - emit readAirlinesIcaoCodes(n); - if (this->getAircraftIcaoCodesCount() > 0) { emit readAll(); } + emit readData(CDbFlags::AirlineIcaoEntity, CDbFlags::ReadFinished, n); } + + void CIcaoDataReader::ps_parseCountryData(QNetworkReply *nwReplyPtr) + { + QScopedPointer nwReply(nwReplyPtr); + QJsonArray array = this->transformReplyIntoDatastoreResponse(nwReply.data()); + if (array.isEmpty()) + { + emit readData(CDbFlags::CountryEntity, CDbFlags::ReadFailed, 0); + return; + } + CCountryList countries = CCountryList::fromDatabaseJson(array); + + // this part needs to be synchronized + int n; + { + QWriteLocker wl(&this->m_lockCountry); + this->m_countries = countries; + n = m_countries.size(); + } + emit readData(CDbFlags::CountryEntity, CDbFlags::ReadFinished, n); + } + + bool CIcaoDataReader::canConnect(QString &message) const + { + if (m_urlAircraftIcao.isEmpty() || m_urlAirlineIcao.isEmpty()) { return false; } + bool cm = CNetworkUtils::canConnect(m_urlAircraftIcao, message); + + // currently only testing one URL, might be changed in the future + return cm; + } + + QString CIcaoDataReader::getAircraftIcaoUrl(const QString &protocol, const QString &server, const QString &baseUrl) + { + return CNetworkUtils::buildUrl(protocol, server, baseUrl, "service/jsonaircrafticao.php"); + } + + QString CIcaoDataReader::getAirlineIcaoUrl(const QString &protocol, const QString &server, const QString &baseUrl) + { + return CNetworkUtils::buildUrl(protocol, server, baseUrl, "service/jsonairlineicao.php"); + } + + QString CIcaoDataReader::getCountryUrl(const QString &protocol, const QString &server, const QString &baseUrl) + { + return CNetworkUtils::buildUrl(protocol, server, baseUrl, "service/jsoncountry.php"); + } + } // namespace diff --git a/src/blackcore/icaodatareader.h b/src/blackcore/icaodatareader.h index f30d6a5b1..b67a9cc5d 100644 --- a/src/blackcore/icaodatareader.h +++ b/src/blackcore/icaodatareader.h @@ -14,8 +14,10 @@ #include "blackcore/blackcoreexport.h" #include "blackcore/databasereader.h" +#include "blackmisc/countrylist.h" #include "blackmisc/aviation/aircrafticaocodelist.h" #include "blackmisc/aviation/airlineicaocodelist.h" +#include "blackmisc/network/dbflags.h" #include #include @@ -37,10 +39,50 @@ namespace BlackCore //! \threadsafe BlackMisc::Aviation::CAircraftIcaoCodeList getAircraftIcaoCodes() const; + //! Get aircraft ICAO information for designator + //! \threadsafe + BlackMisc::Aviation::CAircraftIcaoCode getAircraftIcaoCodeForDesignator(const QString &designator) const; + + //! Get aircraft ICAO information for key + //! \threadsafe + BlackMisc::Aviation::CAircraftIcaoCode getAircraftIcaoCodeForDbKey(int key) const; + //! Get airline ICAO information //! \threadsafe BlackMisc::Aviation::CAirlineIcaoCodeList getAirlineIcaoCodes() const; + //! Get best match for incomplete aircraft ICAO code + //! \threadsafe + BlackMisc::Aviation::CAircraftIcaoCode smartAircraftIcaoSelector(const BlackMisc::Aviation::CAircraftIcaoCode &icao) const; + + //! Get countries + //! \threadsafe + BlackMisc::CCountryList getCountries() const; + + //! Get countries count + //! \threadsafe + int getCountriesCount() const; + + //! Get country for ISO code + //! \threadsafe + BlackMisc::CCountry getCountryForIsoCode(const QString &isoCode) const; + + //! Get country for ISO name + //! \threadsafe + BlackMisc::CCountry getCountryForName(const QString &name) const; + + //! Get airline ICAO information for designator + //! \threadsafe + BlackMisc::Aviation::CAirlineIcaoCode getAirlineIcaoCodeForDesignator(const QString &designator) const; + + //! Get airline ICAO information for key + //! \threadsafe + BlackMisc::Aviation::CAirlineIcaoCode getAirlineIcaoCodeForDbKey(int key) const; + + //! Get best match for incomplete airline ICAO code + //! \threadsafe + BlackMisc::Aviation::CAirlineIcaoCode smartAirlineIcaoSelector(const BlackMisc::Aviation::CAirlineIcaoCode &icao) const; + //! Get aircraft ICAO information count //! \threadsafe int getAircraftIcaoCodesCount() const; @@ -49,15 +91,19 @@ namespace BlackCore //! \threadsafe int getAirlineIcaoCodesCount() const; + //! All data read? + //! \threadsafe + bool areAllDataRead() const; + + //! Can connect to server? + virtual bool canConnect(QString &message) const override; + + //! \copydoc CDatabaseReader::canConnect() + using CDatabaseReader::canConnect; + signals: - //! Codes have been read - void readAircraftIcaoCodes(int number); - - //! Codes have been read - void readAirlinesIcaoCodes(int number); - - //! Everything has been read - void readAll(); + //! Combined read signal + void readData(BlackMisc::Network::CDbFlags::Entity entity, BlackMisc::Network::CDbFlags::ReadState state, int number); private slots: //! Aircraft have been read @@ -66,25 +112,35 @@ namespace BlackCore //! Airlines have been read void ps_parseAirlineIcaoData(QNetworkReply *nwReply); + //! Airlines have been read + void ps_parseCountryData(QNetworkReply *nwReply); + //! Read / re-read data file - void ps_read(); + void ps_read(BlackMisc::Network::CDbFlags::Entity entities); 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; QString m_urlAircraftIcao; QString m_urlAirlineIcao; + QString m_urlCountry; mutable QReadWriteLock m_lockAirline; mutable QReadWriteLock m_lockAircraft; + mutable QReadWriteLock m_lockCountry; //! URL static QString getAircraftIcaoUrl(const QString &protocol, const QString &server, const QString &baseUrl); //! URL static QString getAirlineIcaoUrl(const QString &protocol, const QString &server, const QString &baseUrl); + + //! URL + static QString getCountryUrl(const QString &protocol, const QString &server, const QString &baseUrl); }; } diff --git a/src/blackcore/modeldatareader.cpp b/src/blackcore/modeldatareader.cpp index 38318b89d..b444bb0f1 100644 --- a/src/blackcore/modeldatareader.cpp +++ b/src/blackcore/modeldatareader.cpp @@ -9,6 +9,7 @@ #include "blackmisc/sequence.h" #include "blackmisc/logmessage.h" +#include "blackmisc/networkutils.h" #include "modeldatareader.h" #include @@ -16,6 +17,7 @@ using namespace BlackMisc; using namespace BlackMisc::Aviation; using namespace BlackMisc::Simulation; +using namespace BlackMisc::Network; namespace BlackCore { @@ -40,6 +42,50 @@ namespace BlackCore return m_liveries; } + CLivery CModelDataReader::getLiveryForCombinedCode(const QString &combinedCode) const + { + if (!CLivery::isValidCombinedCode(combinedCode)) { return CLivery(); } + CLiveryList liveries(getLiveries()); + return liveries.findByCombinedCode(combinedCode); + } + + CLivery CModelDataReader::getLiveryForDbKey(int id) const + { + if (id < 0) { return CLivery(); } + CLiveryList liveries(getLiveries()); + return liveries.findByKey(id); + } + + CLivery CModelDataReader::smartLiverySelector(const CLivery &livery) const + { + CLiveryList liveries(getLiveries()); // thread safe copy + + // first try on id, that would be perfect + if (livery.hasValidDbKey()) + { + int k = livery.getDbKey(); + CLivery l(liveries.findByKey(k)); + if (l.hasCompleteData()) { return l; } + } + + // by combined code + if (livery.hasCombinedCode()) + { + QString cc(livery.getCombinedCode()); + CLivery l(liveries.findByCombinedCode(cc)); + if (l.hasCompleteData()) { return l; } + } + + if (livery.hasValidAirlineDesignator()) + { + QString icao(livery.getAirlineIcaoCodeDesignator()); + CLivery l(liveries.findByAirlineIcaoDesignatorStdLivery(icao)); + if (l.hasCompleteData()) { return l; } + } + + return CLivery(); + } + CDistributorList CModelDataReader::getDistributors() const { QReadLocker l(&m_lockDistributor); @@ -52,6 +98,20 @@ namespace BlackCore return m_models; } + CAircraftModel CModelDataReader::getModelForModelString(const QString &modelString) const + { + if (modelString.isEmpty()) { return CAircraftModel(); } + CAircraftModelList models(getModels()); + return models.findFirstByModelString(modelString); + } + + CAircraftModelList CModelDataReader::getModelsForAircraftDesignatorAndLiveryCombinedCode(const QString &aircraftDesignator, const QString &combinedCode) + { + if (aircraftDesignator.isEmpty()) { return CAircraftModelList(); } + CAircraftModelList models(getModels()); + return models.findByAircraftDesignatorAndLiveryCombinedCode(aircraftDesignator, combinedCode); + } + int CModelDataReader::getLiveriesCount() const { QReadLocker l(&m_lockLivery); @@ -64,21 +124,45 @@ namespace BlackCore return m_distributors.size(); } + CDistributor CModelDataReader::smartDistributorSelector(const CDistributor &distributor) const + { + CDistributorList distributors(getDistributors()); // thread safe copy + if (distributor.hasValidDbKey()) + { + QString k(distributor.getDbKey()); + CDistributor d(distributors.findByKey(k)); + if (d.hasCompleteData()) { return d; } + + // more lenient search + return distributors.findByIdOrAlias(k); + } + return CDistributor(); + } + int CModelDataReader::getModelsCount() const { QReadLocker l(&m_lockModels); return m_models.size(); } - bool CModelDataReader::allRead() const + bool CModelDataReader::areAllDataRead() const { return getLiveriesCount() > 0 && getModelsCount() > 0 && - getDistributorsCount(); + getDistributorsCount() > 0; } - void CModelDataReader::ps_read() + bool CModelDataReader::canConnect(QString &message) const + { + if (m_urlDistributors.isEmpty() || m_urlLiveries.isEmpty() || m_urlModels.isEmpty()) { return false; } + bool cm = CNetworkUtils::canConnect(m_urlModels, message); + + // currently only testing one URL, might be changed in the future + return cm; + } + + void CModelDataReader::ps_read(CDbFlags::Entity entity) { this->threadAssertCheck(); Q_ASSERT(this->m_networkManagerLivery); @@ -86,27 +170,30 @@ namespace BlackCore Q_ASSERT(this->m_networkManagerModel); Q_ASSERT(!m_urlLiveries.isEmpty()); Q_ASSERT(!m_urlDistributors.isEmpty()); - QNetworkRequest requestLivery(m_urlLiveries); - QNetworkRequest requestDistributor(m_urlDistributors); - QNetworkRequest requestModel(m_urlModels); - this->m_networkManagerLivery->get(requestLivery); - this->m_networkManagerDistributor->get(requestDistributor); - this->m_networkManagerModel->get(requestModel); - } - QString CModelDataReader::getLiveryUrl(const QString &protocol, const QString &server, const QString &baseUrl) - { - return buildUrl(protocol, server, baseUrl, "service/alllivery.php?rows=20000&sord=asc"); - } + CDbFlags::Entity triggeredRead = CDbFlags::NoEntity; + if (entity.testFlag(CDbFlags::LiveryEntity)) + { + QNetworkRequest requestLivery(m_urlLiveries); + this->m_networkManagerLivery->get(requestLivery); + triggeredRead |= CDbFlags::LiveryEntity; + } - QString CModelDataReader::getDistributorUrl(const QString &protocol, const QString &server, const QString &baseUrl) - { - return buildUrl(protocol, server, baseUrl, "service/alldistributor.php?rows=20000&sord=asc"); - } + if (entity.testFlag(CDbFlags::DistributorEntity)) + { + QNetworkRequest requestDistributor(m_urlDistributors); + this->m_networkManagerDistributor->get(requestDistributor); + triggeredRead |= CDbFlags::DistributorEntity; + } - QString CModelDataReader::getModelUrl(const QString &protocol, const QString &server, const QString &baseUrl) - { - return buildUrl(protocol, server, baseUrl, "service/allaircraftmodel.php?rows=20000&sord=asc"); + if (entity.testFlag(CDbFlags::ModelEntity)) + { + QNetworkRequest requestModel(m_urlModels); + this->m_networkManagerModel->get(requestModel); + triggeredRead |= CDbFlags::ModelEntity; + } + + emit readData(triggeredRead, CDbFlags::StartRead, 0); } void CModelDataReader::ps_parseLiveryData(QNetworkReply *nwReplyPtr) @@ -114,55 +201,79 @@ namespace BlackCore // wrap pointer, make sure any exit cleans up reply // required to use delete later as object is created in a different thread QScopedPointer nwReply(nwReplyPtr); - QJsonArray array = this->transformReplyIntoJsonArray(nwReply.data()); - if (array.isEmpty()) { return; } + QJsonArray array = this->transformReplyIntoDatastoreResponse(nwReply.data()); + if (array.isEmpty()) + { + emit readData(CDbFlags::LiveryEntity, CDbFlags::ReadFailed, 0); + return; + } CLiveryList liveries = CLiveryList::fromDatabaseJson(array); // this part needs to be synchronized - int n; + int n = 0; { QWriteLocker wl(&this->m_lockLivery); this->m_liveries = liveries; n = liveries.size(); } - emit readLiveries(n); - if (allRead()) { emit readAll(); } + emit readData(CDbFlags::LiveryEntity, CDbFlags::ReadFinished, n); } void CModelDataReader::ps_parseDistributorData(QNetworkReply *nwReplyPtr) { QScopedPointer nwReply(nwReplyPtr); - QJsonArray array = this->transformReplyIntoJsonArray(nwReply.data()); - if (array.isEmpty()) { return; } + QJsonArray array = this->transformReplyIntoDatastoreResponse(nwReply.data()); + if (array.isEmpty()) + { + emit readData(CDbFlags::DistributorEntity, CDbFlags::ReadFailed, 0); + return; + } CDistributorList distributors = CDistributorList::fromDatabaseJson(array); // this part needs to be synchronized - int n; + int n = 0; { QWriteLocker wl(&this->m_lockDistributor); this->m_distributors = distributors; n = distributors.size(); } - emit readDistributors(n); - if (allRead()) { emit readAll(); } + emit readData(CDbFlags::DistributorEntity, CDbFlags::ReadFinished, n); } void CModelDataReader::ps_parseModelData(QNetworkReply *nwReplyPtr) { QScopedPointer nwReply(nwReplyPtr); - QJsonArray array = this->transformReplyIntoJsonArray(nwReply.data()); - if (array.isEmpty()) { return; } + QJsonArray array = this->transformReplyIntoDatastoreResponse(nwReply.data()); + if (array.isEmpty()) + { + emit readData(CDbFlags::ModelEntity, CDbFlags::ReadFailed, 0); + return; + } CAircraftModelList models = CAircraftModelList::fromDatabaseJson(array); // this part needs to be synchronized - int n; + int n = 0; { QWriteLocker wl(&this->m_lockModels); this->m_models = models; n = models.size(); } - emit readModels(n); - if (allRead()) { emit readAll(); } + emit readData(CDbFlags::ModelEntity, CDbFlags::ReadFinished, n); + } + + QString CModelDataReader::getLiveryUrl(const QString &protocol, const QString &server, const QString &baseUrl) + { + return CNetworkUtils::buildUrl(protocol, server, baseUrl, "service/jsonlivery.php"); + } + + QString CModelDataReader::getDistributorUrl(const QString &protocol, const QString &server, const QString &baseUrl) + { + return CNetworkUtils::buildUrl(protocol, server, baseUrl, "service/jsondistributor.php"); + } + + QString CModelDataReader::getModelUrl(const QString &protocol, const QString &server, const QString &baseUrl) + { + return CNetworkUtils::buildUrl(protocol, server, baseUrl, "service/jsonaircraftmodel.php"); } } // namespace diff --git a/src/blackcore/modeldatareader.h b/src/blackcore/modeldatareader.h index 01ec1a0df..6831906c0 100644 --- a/src/blackcore/modeldatareader.h +++ b/src/blackcore/modeldatareader.h @@ -14,6 +14,7 @@ #include "blackcore/blackcoreexport.h" #include "blackcore/databasereader.h" +#include "blackmisc/network/webdataservicesprovider.h" #include "blackmisc/aviation/liverylist.h" #include "blackmisc/simulation/distributorlist.h" #include "blackmisc/simulation/aircraftmodellist.h" @@ -38,6 +39,18 @@ namespace BlackCore //! \threadsafe BlackMisc::Aviation::CLiveryList getLiveries() const; + //! Get aircraft livery for code + //! \threadsafe + BlackMisc::Aviation::CLivery getLiveryForCombinedCode(const QString &combinedCode) const; + + //! Get aircraft livery for id + //! \threadsafe + BlackMisc::Aviation::CLivery getLiveryForDbKey(int id) const; + + //! Best match specified by livery + //! \threadsafe + BlackMisc::Aviation::CLivery smartLiverySelector(const BlackMisc::Aviation::CLivery &livery) const; + //! Get distributors (of models) //! \threadsafe BlackMisc::Simulation::CDistributorList getDistributors() const; @@ -46,6 +59,14 @@ namespace BlackCore //! \threadsafe BlackMisc::Simulation::CAircraftModelList getModels() const; + //! Get model for string + //! \threadsafe + BlackMisc::Simulation::CAircraftModel getModelForModelString(const QString &modelString) const; + + //! Get model for designator/combined code + //! \threadsafe + BlackMisc::Simulation::CAircraftModelList getModelsForAircraftDesignatorAndLiveryCombinedCode(const QString &aircraftDesignator, const QString &combinedCode); + //! Get aircraft liveries count //! \threadsafe int getLiveriesCount() const; @@ -54,25 +75,27 @@ namespace BlackCore //! \threadsafe int getDistributorsCount() const; + //! Best match specified by distributor + //! \threadsafe + BlackMisc::Simulation::CDistributor smartDistributorSelector(const BlackMisc::Simulation::CDistributor &distributor) const; + //! Get models count //! \threadsafe int getModelsCount() const; - //! All data read - bool allRead() const; + //! All data read? + //! \threadsafe + bool areAllDataRead() const; + + //! Can connect? + virtual bool canConnect(QString &message) const override; + + //! \copydoc CDatabaseReader::canConnect() + using CDatabaseReader::canConnect; signals: - //! Liveries have been read - void readLiveries(int number); - - //! Distributors have been read - void readDistributors(int number); - - //! Models have been read - void readModels(int number); - - //! All data read - void readAll(); + //! Combined read signal + void readData(BlackMisc::Network::CDbFlags::Entity entity, BlackMisc::Network::CDbFlags::ReadState state, int number); private slots: //! Liveries have been read @@ -85,7 +108,7 @@ namespace BlackCore void ps_parseModelData(QNetworkReply *nwReply); //! Read / re-read data file - void ps_read(); + void ps_read(BlackMisc::Network::CDbFlags::Entity entity = BlackMisc::Network::CDbFlags::DistributorLiveryModel); private: QNetworkAccessManager *m_networkManagerLivery = nullptr; diff --git a/src/blackcore/web_datareader.cpp b/src/blackcore/web_datareader.cpp deleted file mode 100644 index 9a7c1da54..000000000 --- a/src/blackcore/web_datareader.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* 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 "blackcore/web_datareader.h" -#include "vatsimbookingreader.h" -#include "vatsimdatafilereader.h" -#include "vatsim_metar_reader.h" -#include "icaodatareader.h" -#include "modeldatareader.h" -#include "global_reader_settings.h" -#include "blackmisc/logmessage.h" -#include "blackmisc/worker.h" - -using namespace BlackMisc; -using namespace BlackMisc::Simulation; -using namespace BlackMisc::Network; -using namespace BlackMisc::Aviation; -using namespace BlackMisc::PhysicalQuantities; - -namespace BlackCore -{ - - CWebDataReader::CWebDataReader(WebReader readerFlags, QObject *parent) : - QObject(parent), m_readerFlags(readerFlags) - { - this->setObjectName("CWebDataReader"); - this->initReaders(readerFlags); - } - - QList CWebDataReader::connectVatsimDataSignals(std::function bookingsRead, - std::function dataFileRead, - std::function metarRead) - { - // bind does not allow to define connection type - // so anything in its own thread will be sent with this thread affinity - QList cl; - - if (m_readerFlags.testFlag(VatsimBookingReader)) - { - QMetaObject::Connection c1 = connect(this, &CWebDataReader::vatsimBookingsRead, bookingsRead); - Q_ASSERT_X(c1, Q_FUNC_INFO, "connect failed"); - cl.append(c1); - } - - if (m_readerFlags.testFlag(VatsimDataReader)) - { - QMetaObject::Connection c2 = connect(this, &CWebDataReader::vatsimDataFileRead, dataFileRead); - Q_ASSERT_X(c2, Q_FUNC_INFO, "connect failed"); - cl.append(c2); - } - - if (m_readerFlags.testFlag(VatsimMetarReader)) - { - QMetaObject::Connection c3 = connect(this, &CWebDataReader::vatsimMetarRead, metarRead); - Q_ASSERT_X(c3, Q_FUNC_INFO, "connect failed"); - cl.append(c3); - } - return cl; - } - - QList CWebDataReader::connectSwiftDatabaseSignals( - QObject *receiver, - std::function aircraftIcaoCodeRead, std::function airlineIcaoCodeRead, - std::function liveriesRead, std::function distributorsRead, - std::function modelsRead) - { - Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver"); - - // bind does not allow to define connection type - // so anything in its own thread will be sent with this thread affinity - QList cl; - - if (m_readerFlags.testFlag(IcaoDataReader)) - { - QMetaObject::Connection c1 = connect(this, &CWebDataReader::aircraftIcaoCodeRead, receiver, aircraftIcaoCodeRead); - Q_ASSERT_X(c1, Q_FUNC_INFO, "connect failed"); - cl.append(c1); - QMetaObject::Connection c2 = connect(this, &CWebDataReader::airlineIcaoCodeRead, receiver, airlineIcaoCodeRead); - Q_ASSERT_X(c2, Q_FUNC_INFO, "connect failed"); - cl.append(c2); - } - - if (m_readerFlags.testFlag(ModelReader)) - { - QMetaObject::Connection c1 = connect(this, &CWebDataReader::liveriesRead, receiver, liveriesRead); - Q_ASSERT_X(c1, Q_FUNC_INFO, "connect failed"); - cl.append(c1); - QMetaObject::Connection c2 = connect(this, &CWebDataReader::distributorsRead, receiver, distributorsRead); - Q_ASSERT_X(c2, Q_FUNC_INFO, "connect failed"); - cl.append(c2); - QMetaObject::Connection c3 = connect(this, &CWebDataReader::modelsRead, receiver, modelsRead); - Q_ASSERT_X(c3, Q_FUNC_INFO, "connect failed"); - cl.append(c3); - } - return cl; - } - - CServerList CWebDataReader::getVatsimFsdServers() const - { - if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getFsdServers(); } - return CServerList(); - } - - CServerList CWebDataReader::getVatsimVoiceServers() const - { - if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getVoiceServers(); } - return CServerList(); - } - - CDistributorList CWebDataReader::getDistributors() const - { - if (m_modelDataReader) { return m_modelDataReader->getDistributors(); } - return CDistributorList(); - } - - CLiveryList CWebDataReader::getLiveries() const - { - if (m_modelDataReader) { return m_modelDataReader->getLiveries(); } - return CLiveryList(); - } - - CAircraftModelList CWebDataReader::getModels() const - { - if (m_modelDataReader) { return m_modelDataReader->getModels(); } - return CAircraftModelList(); - } - - CAircraftIcaoCodeList CWebDataReader::getAircraftIcaoCodes() const - { - if (m_icaoDataReader) { return m_icaoDataReader->getAircraftIcaoCodes(); } - return CAircraftIcaoCodeList(); - } - - CAirlineIcaoCodeList CWebDataReader::getAirlineIcaoCodes() const - { - if (m_icaoDataReader) { return m_icaoDataReader->getAirlineIcaoCodes(); } - return CAirlineIcaoCodeList(); - } - - void CWebDataReader::gracefulShutdown() - { - this->disconnect(); // all signals - if (this->m_vatsimBookingReader) { this->m_vatsimBookingReader->requestStop(); this->m_vatsimBookingReader->quit(); } - if (this->m_vatsimDataFileReader) { this->m_vatsimDataFileReader->requestStop(); this->m_vatsimDataFileReader->quit(); } - if (this->m_vatsimMetarReader) { this->m_vatsimMetarReader->requestStop(); this->m_vatsimMetarReader->quit(); } - } - - const CLogCategoryList &CWebDataReader::getLogCategories() - { - static const BlackMisc::CLogCategoryList cats { CLogCategory("swift.datareader") }; - return cats; - } - - void CWebDataReader::initReaders(WebReader flags) - { - // 1. VATSIM bookings - if (flags.testFlag(VatsimBookingReader)) - { - this->m_vatsimBookingReader = new CVatsimBookingReader(this, CGlobalReaderSettings::instance().bookingsUrl()); - connect(this->m_vatsimBookingReader, &CVatsimBookingReader::dataRead, this, &CWebDataReader::ps_receivedBookings); - this->m_vatsimBookingReader->start(); - this->m_vatsimBookingReader->setInterval(3 * 60 * 1000); - } - - // 2. VATSIM data file - if (flags.testFlag(VatsimDataReader)) - { - this->m_vatsimDataFileReader = new CVatsimDataFileReader(this, CGlobalReaderSettings::instance().vatsimDataFileUrls()); - connect(this->m_vatsimDataFileReader, &CVatsimDataFileReader::dataRead, this, &CWebDataReader::ps_dataFileRead); - this->m_vatsimDataFileReader->start(); - this->m_vatsimDataFileReader->setInterval(90 * 1000); - } - - // 3. VATSIM metar - if (flags.testFlag(VatsimMetarReader)) - { - this->m_vatsimMetarReader = new CVatsimMetarReader(this, CGlobalReaderSettings::instance().vatsimMetarUrl()); - connect(this->m_vatsimMetarReader, &CVatsimMetarReader::metarUpdated, this, &CWebDataReader::ps_metarRead); - this->m_vatsimMetarReader->start(); - this->m_vatsimMetarReader->setInterval(5 * 60 * 1000); - } - - // 4. ICAO data reader - if (flags.testFlag(IcaoDataReader)) - { - this->m_icaoDataReader = new CIcaoDataReader(this, CGlobalReaderSettings::instance().protocolIcaoReader(), CGlobalReaderSettings::instance().serverIcaoReader(), CGlobalReaderSettings::instance().baseUrlIcaoReader()); - connect(this->m_icaoDataReader, &CIcaoDataReader::readAircraftIcaoCodes, this, &CWebDataReader::ps_readAircraftIcaoCodes); - connect(this->m_icaoDataReader, &CIcaoDataReader::readAirlinesIcaoCodes, this, &CWebDataReader::ps_readAirlinesIcaoCodes); - this->m_icaoDataReader->start(); - } - - // 5. Model reader - if (flags.testFlag(ModelReader)) - { - this->m_modelDataReader = new CModelDataReader(this, CGlobalReaderSettings::instance().protocolModelReader(), CGlobalReaderSettings::instance().serverModelReader(), CGlobalReaderSettings::instance().baseUrlModelReader()); - connect(this->m_modelDataReader, &CModelDataReader::readLiveries, this, &CWebDataReader::ps_readLiveries); - connect(this->m_modelDataReader, &CModelDataReader::readDistributors, this, &CWebDataReader::ps_readDistributors); - connect(this->m_modelDataReader, &CModelDataReader::readModels, this, &CWebDataReader::ps_readModels); - this->m_modelDataReader->start(); - } - } - - void CWebDataReader::ps_receivedBookings(const CAtcStationList &stations) - { - CLogMessage(this).info("Read bookings from network"); - emit vatsimBookingsRead(stations.size()); - } - - void CWebDataReader::ps_dataFileRead(int lines) - { - CLogMessage(this).info("Read VATSIM data file, %1 lines") << lines; - emit vatsimDataFileRead(lines); - } - - void CWebDataReader::ps_metarRead(const BlackMisc::Weather::CMetarSet &metars) - { - CLogMessage(this).info("Read %1 VATSIM metar stations") << metars.size(); - emit vatsimMetarRead(metars.size()); - } - - void CWebDataReader::ps_readAircraftIcaoCodes(int number) - { - CLogMessage(this).info("Read %1 aircraft ICAO codes") << number; - emit aircraftIcaoCodeRead(number); - } - - void CWebDataReader::ps_readAirlinesIcaoCodes(int number) - { - CLogMessage(this).info("Read %1 airline ICAO codes") << number; - emit airlineIcaoCodeRead(number); - } - - void CWebDataReader::ps_readLiveries(int number) - { - CLogMessage(this).info("Read %1 liveries") << number; - emit liveriesRead(number); - } - - void CWebDataReader::ps_readDistributors(int number) - { - CLogMessage(this).info("Read %1 distributors") << number; - emit distributorsRead(number); - } - - void CWebDataReader::ps_readModels(int number) - { - CLogMessage(this).info("Read %1 models") << number; - emit modelsRead(number); - } - - void CWebDataReader::readAllInBackground(int delayMs) - { - if (delayMs > 100) - { - BlackMisc::singleShot(delayMs, QThread::currentThread(), [ = ]() - { - this->readAllInBackground(0); - }); - return; - } - - if (this->m_vatsimBookingReader) {this->m_vatsimBookingReader->readInBackgroundThread(); } - if (this->m_vatsimDataFileReader) this->m_vatsimDataFileReader->readInBackgroundThread(); - if (this->m_vatsimMetarReader) this->m_vatsimMetarReader->readInBackgroundThread(); - if (this->m_icaoDataReader) { this->m_icaoDataReader->readInBackgroundThread(); } - if (this->m_modelDataReader) { this->m_modelDataReader->readInBackgroundThread(); } - } - - void CWebDataReader::readAtcBookingsInBackground() const - { - if (!this->m_vatsimBookingReader) { return; } - this->m_vatsimBookingReader->readInBackgroundThread(); - } - - void CWebDataReader::readModelDataInBackground() const - { - if (!this->m_modelDataReader) { return; } - this->m_modelDataReader->readInBackgroundThread(); - } - -} // ns diff --git a/src/blackcore/web_datareader.h b/src/blackcore/web_datareader.h deleted file mode 100644 index d2760cbe5..000000000 --- a/src/blackcore/web_datareader.h +++ /dev/null @@ -1,188 +0,0 @@ -/* 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. - */ - -//! \file - -#ifndef BLACKCORE_WEB_DATAREADER_H -#define BLACKCORE_WEB_DATAREADER_H - -#include "blackcore/blackcoreexport.h" -#include "blackmisc/logcategorylist.h" -#include "blackmisc/aviation/atcstationlist.h" -#include "blackmisc/aviation/liverylist.h" -#include "blackmisc/aviation/airlineicaocodelist.h" -#include "blackmisc/aviation/aircrafticaocodelist.h" -#include "blackmisc/network/serverlist.h" -#include "blackmisc/simulation/distributorlist.h" -#include "blackmisc/weather/metarset.h" -#include - -namespace BlackCore -{ - class CVatsimBookingReader; - class CVatsimDataFileReader; - class CIcaoDataReader; - class CModelDataReader; - class CVatsimMetarReader; - - /** - * Encapsulates reading data from web sources - */ - class BLACKCORE_EXPORT CWebDataReader : public QObject - { - Q_OBJECT - - public: - //! \todo Qt5.5: Make use of QFlags - enum WebReaderFlags - { - None = 0, - VatsimBookingReader = 1 << 0, - VatsimDataReader = 1 << 1, - VatsimMetarReader = 1 << 2, - IcaoDataReader = 1 << 3, - ModelReader = 1 << 4, - AllVatsimReaders = VatsimBookingReader | VatsimDataReader | VatsimMetarReader, - AllSwiftDbReaders = IcaoDataReader | ModelReader, - AllReaders = 0xFFFF - }; - Q_DECLARE_FLAGS(WebReader, WebReaderFlags) - - //! Constructor - CWebDataReader(WebReader readerFlags, QObject *parent = nullptr); - - //! Shutdown - void gracefulShutdown(); - - //! Relay signals for VATSIM data - QList connectVatsimDataSignals(std::function bookingsRead, - std::function dataFileRead, - std::function metarRead); - - //! Relay signals for swift data - QList connectSwiftDatabaseSignals( - QObject *receiver, - std::function aircraftIcaoCodeRead, std::function airlineIcaoCodeRead, - std::function liveriesRead, std::function distributorsRead, - std::function modelsRead); - - //! \copydoc CVatsimDataFileReader::getVatsimFsdServers - BlackMisc::Network::CServerList getVatsimFsdServers() const; - - //! \copydoc CVatsimDataFileReader::getVatsimVoiceServers - BlackMisc::Network::CServerList getVatsimVoiceServers() const; - - //! \copydoc CModelDataReader::getDistributors - BlackMisc::Simulation::CDistributorList getDistributors() const; - - //! \copydoc CModelDataReader::getLiveries - BlackMisc::Aviation::CLiveryList getLiveries() const; - - //! \copydoc CModelDataReader::getModels - BlackMisc::Simulation::CAircraftModelList getModels() const; - - //! \copydoc CIcaoDataReader::getAircraftIcaoCodes - BlackMisc::Aviation::CAircraftIcaoCodeList getAircraftIcaoCodes() const; - - //! \copydoc CIcaoDataReader::getAirlineIcaoCodes - BlackMisc::Aviation::CAirlineIcaoCodeList getAirlineIcaoCodes() const; - - //! Read ATC bookings - void readAtcBookingsInBackground() const; - - //! Read liveries - void readModelDataInBackground() const; - - //! Booking reader - CVatsimBookingReader *getBookingReader() const { return m_vatsimBookingReader; } - - //! Data file reader - CVatsimDataFileReader *getDataFileReader() const { return m_vatsimDataFileReader; } - - //! Metar reader - CVatsimMetarReader *getMetarReader() const { return m_vatsimMetarReader; } - - //! Reader flags - WebReader getReaderFlags() const { return m_readerFlags; } - - //! Log categories - static const BlackMisc::CLogCategoryList &getLogCategories(); - - public slots: - //! First read (allows to immediately read in background) - void readAllInBackground(int delayMs); - - signals: - //! Data file read - void vatsimDataFileRead(int lines); - - //! Bookings read - void vatsimBookingsRead(int number); - - //! Metars read - void vatsimMetarRead(int number); - - //! ICAO codes read - void aircraftIcaoCodeRead(int number); - - //! ICAO codes read - void airlineIcaoCodeRead(int number); - - //! Liveries read - void liveriesRead(int number); - - //! Distributors read - void distributorsRead(int number); - - //! Models read - void modelsRead(int number); - - private slots: - //! ATC bookings received - void ps_receivedBookings(const BlackMisc::Aviation::CAtcStationList &bookedStations); - - //! Data file has been read - void ps_dataFileRead(int lines); - - //! Metars have been read - void ps_metarRead(const BlackMisc::Weather::CMetarSet &metars); - - //! Read ICAO codes - void ps_readAircraftIcaoCodes(int number); - - //! Read ICAO codes - void ps_readAirlinesIcaoCodes(int number); - - //! Read liveries - void ps_readLiveries(int number); - - //! Read distributors - void ps_readDistributors(int number); - - //! Read models - void ps_readModels(int number); - - private: - //! Init the readers - void initReaders(WebReader flags); - - WebReader m_readerFlags = None; //!< which readers are available - - // for reading XML and VATSIM data files - CVatsimBookingReader *m_vatsimBookingReader = nullptr; - CVatsimDataFileReader *m_vatsimDataFileReader = nullptr; - CVatsimMetarReader *m_vatsimMetarReader = nullptr; - CIcaoDataReader *m_icaoDataReader = nullptr; - CModelDataReader *m_modelDataReader = nullptr; - }; -} // namespace - -Q_DECLARE_OPERATORS_FOR_FLAGS(BlackCore::CWebDataReader::WebReader) - -#endif diff --git a/src/blackcore/webdataservices.cpp b/src/blackcore/webdataservices.cpp new file mode 100644 index 000000000..b6879aa61 --- /dev/null +++ b/src/blackcore/webdataservices.cpp @@ -0,0 +1,447 @@ +/* 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 "blackcore/webdataservices.h" +#include "blackcore/modeldatareader.h" +#include "blackcore/databasewriter.h" +#include "vatsimbookingreader.h" +#include "vatsimdatafilereader.h" +#include "icaodatareader.h" +#include "settings/global_reader_settings.h" +#include "blackmisc/logmessage.h" +#include "blackmisc/worker.h" + +using namespace BlackCore::Settings; +using namespace BlackMisc; +using namespace BlackMisc::Simulation; +using namespace BlackMisc::Network; +using namespace BlackMisc::Aviation; + +namespace BlackCore +{ + CWebDataServices::CWebDataServices(CWebReaderFlags::WebReader readerFlags, QObject *parent) : + QObject(parent), m_readerFlags(readerFlags) + { + this->setObjectName("CWebDataReader"); + this->initReaders(readerFlags); + this->initWriters(); + } + + QList CWebDataServices::connectVatsimDataSignals(QObject *receiver, std::function bookingsRead, std::function dataFileRead) + { + // bind does not allow to define connection type + // so anything in its own thread will be sent with this thread affinity + Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver"); + QList cl; + + if (m_readerFlags.testFlag(CWebReaderFlags::WebReaderFlags::VatsimBookingReader)) + { + QMetaObject::Connection c1 = connect(this, &CWebDataServices::vatsimBookingsRead, receiver, bookingsRead); + Q_ASSERT_X(c1, Q_FUNC_INFO, "connect failed"); + cl.append(c1); + } + + if (m_readerFlags.testFlag(CWebReaderFlags::WebReaderFlags::VatsimDataReader)) + { + QMetaObject::Connection c2 = connect(this, &CWebDataServices::vatsimDataFileRead, receiver, dataFileRead); + Q_ASSERT_X(c2, Q_FUNC_INFO, "connect failed"); + cl.append(c2); + } + return cl; + } + + QList CWebDataServices::connectSwiftDatabaseSignals(QObject *receiver, std::function dataRead) + { + Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver"); + + // bind does not allow to define connection type + // so anything in its own thread will be sent with this thread affinity + QList cl; + + if (m_readerFlags.testFlag(CWebReaderFlags::WebReaderFlags::IcaoDataReader)) + { + Q_ASSERT_X(this->m_icaoDataReader, Q_FUNC_INFO, "Missing reader"); + QMetaObject::Connection con = connect(this->m_icaoDataReader, &CIcaoDataReader::readData, receiver, dataRead); + Q_ASSERT_X(con, Q_FUNC_INFO, "connect failed"); + cl.append(con); + } + + if (m_readerFlags.testFlag(CWebReaderFlags::WebReaderFlags::ModelReader)) + { + Q_ASSERT_X(this->m_modelDataReader, Q_FUNC_INFO, "Missing reader"); + QMetaObject::Connection con = connect(this->m_modelDataReader, &CModelDataReader::readData, receiver, dataRead); + Q_ASSERT_X(con, Q_FUNC_INFO, "connect failed"); + cl.append(con); + } + return cl; + } + + CServerList CWebDataServices::getVatsimFsdServers() const + { + if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getFsdServers(); } + return CServerList(); + } + + CServerList CWebDataServices::getVatsimVoiceServers() const + { + if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getVoiceServers(); } + return CServerList(); + } + + CUserList CWebDataServices::getUsersForCallsign(const CCallsign &callsign) const + { + if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getUsersForCallsign(callsign); } + return CUserList(); + } + + CAtcStationList CWebDataServices::getAtcStationsForCallsign(const CCallsign &callsign) const + { + if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getAtcStationsForCallsign(callsign); } + return CAtcStationList(); + } + + CVoiceCapabilities CWebDataServices::getVoiceCapabilityForCallsign(const CCallsign &callsign) const + { + if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getVoiceCapabilityForCallsign(callsign); } + return CVoiceCapabilities(); + } + + void CWebDataServices::updateWithVatsimDataFileData(CSimulatedAircraft &aircraftToBeUdpated) const + { + if (m_vatsimDataFileReader) { m_vatsimDataFileReader->updateWithVatsimDataFileData(aircraftToBeUdpated); } + } + + CStatusMessageList CWebDataServices::asyncWriteModel(CAircraftModel &model) const + { + if (m_databaseWriter) { return m_databaseWriter->asyncWriteModel(model);} + return CStatusMessageList(); + } + + bool CWebDataServices::canConnectSwiftDb() const + { + if (!m_icaoDataReader && !m_modelDataReader) { return false; } + if (m_icaoDataReader) + { + if (!m_icaoDataReader->canConnect()) { return false; } + } + if (m_modelDataReader) + { + if (!m_modelDataReader->canConnect()) { return false; } + } + return true; + } + + CDbFlags::Entity CWebDataServices::triggerRead(CDbFlags::Entity whatToRead) + { + CDbFlags::Entity triggeredRead = CDbFlags::NoEntity; + if (m_vatsimDataFileReader) + { + if (whatToRead.testFlag(CDbFlags::VatsimDataFile)) + { + m_vatsimDataFileReader->readInBackgroundThread(); + triggeredRead |= CDbFlags::VatsimDataFile; + } + } + + if (m_vatsimBookingReader) + { + if (whatToRead.testFlag(CDbFlags::VatsimBookings)) + { + m_vatsimBookingReader->readInBackgroundThread(); + triggeredRead |= CDbFlags::VatsimBookings; + } + } + + if (m_icaoDataReader) + { + if (whatToRead.testFlag(CDbFlags::AircraftIcaoEntity) || whatToRead.testFlag(CDbFlags::AirlineIcaoEntity) || whatToRead.testFlag(CDbFlags::CountryEntity)) + { + CDbFlags::Entity icaoEntities = whatToRead & CDbFlags::AllIcaoAndCountries; + m_icaoDataReader->readInBackgroundThread(icaoEntities); + triggeredRead |= icaoEntities; + } + } + + if (m_modelDataReader) + { + if (whatToRead.testFlag(CDbFlags::LiveryEntity) || whatToRead.testFlag(CDbFlags::DistributorEntity) || whatToRead.testFlag(CDbFlags::ModelEntity)) + { + CDbFlags::Entity modelEntities = whatToRead & CDbFlags::DistributorLiveryModel; + m_modelDataReader->readInBackgroundThread(modelEntities); + triggeredRead |= modelEntities; + } + } + return triggeredRead; + } + + CDistributorList CWebDataServices::getDistributors() const + { + if (m_modelDataReader) { return m_modelDataReader->getDistributors(); } + return CDistributorList(); + } + + int CWebDataServices::getDistributorsCount() const + { + if (m_modelDataReader) { return m_modelDataReader->getDistributorsCount(); } + return 0; + } + + CDistributor CWebDataServices::smartDistributorSelector(const CDistributor &distributor) const + { + if (m_modelDataReader) { return m_modelDataReader->smartDistributorSelector(distributor); } + return CDistributor(); + } + + CLiveryList CWebDataServices::getLiveries() const + { + if (m_modelDataReader) { return m_modelDataReader->getLiveries(); } + return CLiveryList(); + } + + int CWebDataServices::getLiveriesCount() const + { + if (m_modelDataReader) { return m_modelDataReader->getLiveriesCount(); } + return 0; + } + + CLivery CWebDataServices::getLiveryForCombinedCode(const QString &combinedCode) const + { + if (m_modelDataReader) { return m_modelDataReader->getLiveryForCombinedCode(combinedCode); } + return CLivery(); + } + + CLivery CWebDataServices::getLiveryForDbKey(int id) const + { + if (m_modelDataReader) { return m_modelDataReader->getLiveryForDbKey(id); } + return CLivery(); + } + + CLivery CWebDataServices::smartLiverySelector(const CLivery &livery) const + { + if (m_modelDataReader) { return m_modelDataReader->smartLiverySelector(livery); } + return livery; + } + + CAircraftModelList CWebDataServices::getModels() const + { + if (m_modelDataReader) { return m_modelDataReader->getModels(); } + return CAircraftModelList(); + } + + int CWebDataServices::getModelsCount() const + { + if (m_modelDataReader) { return m_modelDataReader->getModelsCount(); } + return 0; + } + + CAircraftModelList CWebDataServices::getModelsForAircraftDesignatorAndLiveryCombinedCode(const QString &aircraftDesignator, const QString &combinedCode) const + { + if (m_modelDataReader) { return m_modelDataReader->getModelsForAircraftDesignatorAndLiveryCombinedCode(aircraftDesignator, combinedCode); } + return CAircraftModelList(); + } + + CAircraftModel CWebDataServices::getModelForModelString(const QString &modelString) const + { + if (m_modelDataReader) { return m_modelDataReader->getModelForModelString(modelString); } + return CAircraftModel(); + } + + CAircraftIcaoCodeList CWebDataServices::getAircraftIcaoCodes() const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAircraftIcaoCodes(); } + return CAircraftIcaoCodeList(); + } + + int CWebDataServices::getAircraftIcaoCodesCount() const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAircraftIcaoCodesCount(); } + return 0; + } + + CAircraftIcaoCode CWebDataServices::getAircraftIcaoCodeForDesignator(const QString &designator) const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAircraftIcaoCodeForDesignator(designator); } + return CAircraftIcaoCode(); + } + + CAircraftIcaoCode CWebDataServices::getAircraftIcaoCodeForDbKey(int key) const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAircraftIcaoCodeForDbKey(key); } + return CAircraftIcaoCode(); + } + + CAircraftIcaoCode CWebDataServices::smartAircraftIcaoSelector(const CAircraftIcaoCode &icao) const + { + if (m_icaoDataReader) { return m_icaoDataReader->smartAircraftIcaoSelector(icao); } + return icao; + } + + CAirlineIcaoCodeList CWebDataServices::getAirlineIcaoCodes() const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAirlineIcaoCodes(); } + return CAirlineIcaoCodeList(); + } + + int CWebDataServices::getAirlineIcaoCodesCount() const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAirlineIcaoCodesCount(); } + return 0; + } + + CAirlineIcaoCode CWebDataServices::getAirlineIcaoCodeForDbKey(int key) const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAirlineIcaoCodeForDbKey(key); } + return CAirlineIcaoCode(); + } + + CCountryList CWebDataServices::getCountries() const + { + if (m_icaoDataReader) { return m_icaoDataReader->getCountries(); } + return CCountryList(); + } + + int CWebDataServices::getCountriesCount() const + { + if (m_icaoDataReader) { return m_icaoDataReader->getCountriesCount(); } + return 0; + } + + CCountry CWebDataServices::getCountryForName(const QString &name) const + { + if (m_icaoDataReader) { return m_icaoDataReader->getCountryForName(name); } + return CCountry(); + } + + CCountry CWebDataServices::getCountryForIsoCode(const QString &iso) const + { + if (m_icaoDataReader) { return m_icaoDataReader->getCountryForIsoCode(iso); } + return CCountry(); + } + + CAirlineIcaoCode CWebDataServices::getAirlineIcaoCodeForDesignator(const QString &designator) const + { + if (m_icaoDataReader) { return m_icaoDataReader->getAirlineIcaoCodeForDesignator(designator); } + return CAirlineIcaoCode(); + } + + void CWebDataServices::gracefulShutdown() + { + this->disconnect(); // all signals + if (this->m_vatsimBookingReader) { this->m_vatsimBookingReader->gracefulShutdown(); } + if (this->m_vatsimDataFileReader) { this->m_vatsimDataFileReader->gracefulShutdown(); } + if (this->m_modelDataReader) { this->m_modelDataReader->gracefulShutdown(); } + if (this->m_icaoDataReader) { this->m_icaoDataReader->gracefulShutdown(); } + if (this->m_databaseWriter) { this->m_databaseWriter->gracefulShutdown(); } + } + + const CLogCategoryList &CWebDataServices::getLogCategories() + { + static const BlackMisc::CLogCategoryList cats { CLogCategory("swift.datareader") }; + return cats; + } + + void CWebDataServices::initReaders(CWebReaderFlags::WebReader flags) + { + // 1. VATSIM bookings + if (flags.testFlag(CWebReaderFlags::WebReaderFlags::VatsimBookingReader)) + { + this->m_vatsimBookingReader = new CVatsimBookingReader(this, CGlobalReaderSettings::instance().bookingsUrl()); + bool c = connect(this->m_vatsimBookingReader, &CVatsimBookingReader::dataRead, this, &CWebDataServices::ps_receivedBookings); + Q_ASSERT_X(c, Q_FUNC_INFO, "VATSIM reader signals"); + Q_UNUSED(c); + this->m_vatsimBookingReader->start(); + this->m_vatsimBookingReader->setInterval(3 * 60 * 1000); + } + + // 2. VATSIM data file + if (flags.testFlag(CWebReaderFlags::WebReaderFlags::VatsimDataReader)) + { + this->m_vatsimDataFileReader = new CVatsimDataFileReader(this, CGlobalReaderSettings::instance().vatsimDataFileUrls()); + bool c = connect(this->m_vatsimDataFileReader, &CVatsimDataFileReader::dataRead, this, &CWebDataServices::ps_dataFileRead); + Q_ASSERT_X(c, Q_FUNC_INFO, "VATSIM reader signals"); + Q_UNUSED(c); + this->m_vatsimDataFileReader->start(); + this->m_vatsimDataFileReader->setInterval(90 * 1000); + } + + // 3. ICAO data reader + if (flags.testFlag(CWebReaderFlags::WebReaderFlags::IcaoDataReader)) + { + bool c; + this->m_icaoDataReader = new CIcaoDataReader(this, CGlobalReaderSettings::instance().protocolIcaoReader(), CGlobalReaderSettings::instance().serverIcaoReader(), CGlobalReaderSettings::instance().baseUrlIcaoReader()); + c = connect(this->m_icaoDataReader, &CIcaoDataReader::readData, this, &CWebDataServices::ps_readFromSwiftDb); + Q_ASSERT_X(c, Q_FUNC_INFO, "ICAO reader signals"); + Q_UNUSED(c); + this->m_icaoDataReader->start(); + } + + // 4. Model reader + if (flags.testFlag(CWebReaderFlags::WebReaderFlags::ModelReader)) + { + this->m_modelDataReader = new CModelDataReader(this, CGlobalReaderSettings::instance().protocolModelReader(), CGlobalReaderSettings::instance().serverModelReader(), CGlobalReaderSettings::instance().baseUrlModelReader()); + bool c = connect(this->m_modelDataReader, &CModelDataReader::readData, this, &CWebDataServices::ps_readFromSwiftDb); + Q_ASSERT_X(c, Q_FUNC_INFO, "Model reader signals"); + Q_UNUSED(c); + this->m_modelDataReader->start(); + } + } + + void CWebDataServices::initWriters() + { + this->m_databaseWriter = new CDatabaseWriter( + CGlobalReaderSettings::instance().protocolModelReader(), + CGlobalReaderSettings::instance().serverModelReader(), + CGlobalReaderSettings::instance().baseUrlModelReader(), + this); + } + + void CWebDataServices::ps_receivedBookings(const CAtcStationList &stations) + { + CLogMessage(this).info("Read bookings from network"); + emit vatsimBookingsRead(stations.size()); + } + + void CWebDataServices::ps_dataFileRead(int lines) + { + CLogMessage(this).info("Read VATSIM data file, %1 lines") << lines; + emit vatsimDataFileRead(lines); + } + + void CWebDataServices::ps_readFromSwiftDb(CDbFlags::Entity entity, CDbFlags::ReadState state, int number) + { + CLogMessage(this).info("Read data %1 %3 %2") << CDbFlags::flagToString(entity) << number << CDbFlags::flagToString(state); + emit readSwiftDbData(entity, state, number); + } + + void CWebDataServices::readAllInBackground(int delayMs) + { + if (delayMs > 100) + { + BlackMisc::singleShot(delayMs, QThread::currentThread(), [ = ]() + { + this->readAllInBackground(0); + }); + } + else + { + // only readers requested will be read + if (this->m_vatsimBookingReader) {this->m_vatsimBookingReader->readInBackgroundThread(); } + if (this->m_vatsimDataFileReader) this->m_vatsimDataFileReader->readInBackgroundThread(); + if (this->m_icaoDataReader) { this->m_icaoDataReader->readInBackgroundThread(CDbFlags::AllIcaoAndCountries); } + if (this->m_modelDataReader) { this->m_modelDataReader->readInBackgroundThread(CDbFlags::DistributorLiveryModel); } + } + } + + void CWebDataServices::readAtcBookingsInBackground() const + { + if (!this->m_vatsimBookingReader) { return; } + this->m_vatsimBookingReader->readInBackgroundThread(); + } + +} // ns diff --git a/src/blackcore/webdataservices.h b/src/blackcore/webdataservices.h new file mode 100644 index 000000000..58b5a1ea6 --- /dev/null +++ b/src/blackcore/webdataservices.h @@ -0,0 +1,266 @@ +/* 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. + */ + +//! \file + +#ifndef BLACKCORE_WEB_DATASERVICES_H +#define BLACKCORE_WEB_DATASERVICES_H + +#include "blackcore/blackcoreexport.h" +#include "blackcore/webreaderflags.h" +#include "blackmisc/aviation/atcstationlist.h" +#include "blackmisc/aviation/liverylist.h" +#include "blackmisc/aviation/airlineicaocodelist.h" +#include "blackmisc/aviation/aircrafticaocodelist.h" +#include "blackmisc/network/serverlist.h" +#include "blackmisc/network/voicecapabilities.h" +#include "blackmisc/network/webdataservicesprovider.h" +#include "blackmisc/simulation/distributorlist.h" +#include "blackmisc/logcategorylist.h" +#include "blackmisc/countrylist.h" +#include + +namespace BlackCore +{ + class CVatsimBookingReader; + class CVatsimDataFileReader; + class CIcaoDataReader; + class CModelDataReader; + class CDatabaseWriter; + + /*! + * Encapsulates reading data from web sources + */ + class BLACKCORE_EXPORT CWebDataServices : + public QObject, + public BlackMisc::Network::IWebDataServicesProvider + { + Q_OBJECT + Q_INTERFACES(BlackMisc::Network::IWebDataServicesProvider) + + public: + //! Constructor + CWebDataServices(CWebReaderFlags::WebReader readerFlags, QObject *parent = nullptr); + + //! Shutdown + void gracefulShutdown(); + + //! Read ATC bookings + void readAtcBookingsInBackground() const; + + //! Booking reader + CVatsimBookingReader *getBookingReader() const { return m_vatsimBookingReader; } + + //! Data file reader + CVatsimDataFileReader *getDataFileReader() const { return m_vatsimDataFileReader; } + + //! Reader flags + CWebReaderFlags::WebReader getReaderFlags() const { return m_readerFlags; } + + //! Log categories + static const BlackMisc::CLogCategoryList &getLogCategories(); + + // ------------------------ provider functionality ------------------------------ + + //! \copydoc IWebDataReaderProvider::connectVatsimDataSignals + //! \ingroup webdatareaderprovider + virtual QList connectVatsimDataSignals( + QObject *receiver, + std::function bookingsRead, std::function dataFileRead) override; + + //! \copydoc IWebDataReaderProvider::connectSwiftDatabaseSignals + //! \ingroup webdatareaderprovider + virtual QList connectSwiftDatabaseSignals( + QObject *receiver, + std::function dataRead) override; + + //! \copydoc IWebDataReaderProvider::connectSwiftDatabaseSignals + //! \ingroup webdatareaderprovider + virtual BlackMisc::Network::CDbFlags::Entity triggerRead(BlackMisc::Network::CDbFlags::Entity whatToRead) override; + + //! \copydoc IWebDataReaderProvider::getVatsimFsdServers + //! \ingroup webdatareaderprovider + virtual BlackMisc::Network::CServerList getVatsimFsdServers() const override; + + //! \copydoc IWebDataReaderProvider::getVatsimVoiceServers + //! \ingroup webdatareaderprovider + virtual BlackMisc::Network::CServerList getVatsimVoiceServers() const override; + + //! \copydoc IWebDataReaderProvider::getDistributors + //! \ingroup webdatareaderprovider + virtual BlackMisc::Simulation::CDistributorList getDistributors() const override; + + //! \copydoc IWebDataReaderProvider::getDistributorsCount + //! \ingroup webdatareaderprovider + virtual int getDistributorsCount() const override; + + //! \copydoc IWebDataReaderProvider::smartDistributorSelector + //! \ingroup webdatareaderprovider + virtual BlackMisc::Simulation::CDistributor smartDistributorSelector(const BlackMisc::Simulation::CDistributor &distributor) const override; + + //! \copydoc IWebDataReaderProvider::getLiveries + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CLiveryList getLiveries() const override; + + //! \copydoc IWebDataReaderProvider::getLiveriesCount + //! \ingroup webdatareaderprovider + virtual int getLiveriesCount() const override; + + //! \copydoc IWebDataReaderProvider::getLiveryForCombinedCode + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CLivery getLiveryForCombinedCode(const QString &combinedCode) const override; + + //! \copydoc IWebDataReaderProvider::getLiveryForDbKey + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CLivery getLiveryForDbKey(int id) const override; + + //! \copydoc IWebDataReaderProvider::smartLiverySelector + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CLivery smartLiverySelector(const BlackMisc::Aviation::CLivery &livery) const override; + + //! \copydoc IWebDataReaderProvider::getModels + //! \ingroup webdatareaderprovider + virtual BlackMisc::Simulation::CAircraftModelList getModels() const override; + + //! \copydoc IWebDataReaderProvider::getModelsCount + //! \ingroup webdatareaderprovider + virtual int getModelsCount() const override; + + //! \copydoc IWebDataReaderProvider::getModelsForAircraftDesignatorAndLiveryCombinedCode + //! \ingroup webdatareaderprovider + virtual BlackMisc::Simulation::CAircraftModelList getModelsForAircraftDesignatorAndLiveryCombinedCode(const QString &aircraftDesignator, const QString &combinedCode) const override; + + //! \copydoc IWebDataReaderProvider::getModelForModelString + //! \ingroup webdatareaderprovider + virtual BlackMisc::Simulation::CAircraftModel getModelForModelString(const QString &modelString) const override; + + //! \copydoc IWebDataReaderProvider::getAircraftIcaoCodes + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAircraftIcaoCodeList getAircraftIcaoCodes() const override; + + //! \copydoc IWebDataReaderProvider::getAircraftIcaoCodesCount + //! \ingroup webdatareaderprovider + virtual int getAircraftIcaoCodesCount() const override; + + //! \copydoc IWebDataReaderProvider::getAircraftIcaoCodeForDesignator + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAircraftIcaoCode getAircraftIcaoCodeForDesignator(const QString &designator) const override; + + //! \copydoc IWebDataReaderProvider::getAircraftIcaoCodeForDbKey + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAircraftIcaoCode getAircraftIcaoCodeForDbKey(int key) const override; + + //! \copydoc IWebDataReaderProvider::getAircraftIcaoCodeForDbKey + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAircraftIcaoCode smartAircraftIcaoSelector(const BlackMisc::Aviation::CAircraftIcaoCode &icao) const override; + + //! \copydoc IWebDataReaderProvider::getAirlineIcaoCodes + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAirlineIcaoCodeList getAirlineIcaoCodes() const override; + + //! \copydoc IWebDataReaderProvider::getAirlineIcaoCodesCount + //! \ingroup webdatareaderprovider + virtual int getAirlineIcaoCodesCount() const override; + + //! \copydoc IWebDataReaderProvider::getAirlineIcaoCodeForDbKey + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAirlineIcaoCode getAirlineIcaoCodeForDbKey(int key) const override; + + //! \copydoc IWebDataReaderProvider::getAirlineIcaoCodeForDesignator + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAirlineIcaoCode getAirlineIcaoCodeForDesignator(const QString &designator) const override; + + //! \copydoc IWebDataReaderProvider::getCountries + //! \ingroup webdatareaderprovider + virtual BlackMisc::CCountryList getCountries() const override; + + //! \copydoc IWebDataReaderProvider::getCountries + //! \ingroup webdatareaderprovider + virtual int getCountriesCount() const override; + + //! \copydoc IWebDataReaderProvider::getCountryForName + //! \ingroup webdatareaderprovider + virtual BlackMisc::CCountry getCountryForName(const QString &name) const override; + + //! \copydoc IWebDataReaderProvider::getCountryForIsoCode + //! \ingroup webdatareaderprovider + virtual BlackMisc::CCountry getCountryForIsoCode(const QString &iso) const override; + + //! \copydoc IWebDataReaderProvider::getUsersForCallsign + //! \ingroup webdatareaderprovider + virtual BlackMisc::Network::CUserList getUsersForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const override; + + //! \copydoc IWebDataReaderProvider::getAtcStationsForCallsign + //! \ingroup webdatareaderprovider + virtual BlackMisc::Aviation::CAtcStationList getAtcStationsForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const override; + + //! \copydoc IWebDataReaderProvider::getVoiceCapabilityForCallsign + //! \ingroup webdatareaderprovider + virtual BlackMisc::Network::CVoiceCapabilities getVoiceCapabilityForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const override; + + //! \copydoc IWebDataReaderProvider::updateWithWebData + //! \ingroup webdatareaderprovider + virtual void updateWithVatsimDataFileData(BlackMisc::Simulation::CSimulatedAircraft &aircraftToBeUdpated) const override; + + //! \copydoc IWebDataReaderProvider::asyncWriteModel + //! \ingroup webdatareaderprovider + virtual BlackMisc::CStatusMessageList asyncWriteModel(BlackMisc::Simulation::CAircraftModel &model) const override; + + //! \copydoc IWebDataReaderProvider::canConnectSwiftDb + //! \ingroup webdatareaderprovider + virtual bool canConnectSwiftDb() const override; + + public slots: + //! First read (allows to immediately read in background) + void readAllInBackground(int delayMs); + + signals: + //! Data file read + void vatsimDataFileRead(int lines); + + //! Bookings read + void vatsimBookingsRead(int number); + + //! Combined read signal + void readSwiftDbData(BlackMisc::Network::CDbFlags::Entity entity, BlackMisc::Network::CDbFlags::ReadState state, int number); + + //! Model has been written + void modelWritten(const BlackMisc::Simulation::CAircraftModel &model); + + private slots: + //! ATC bookings received + void ps_receivedBookings(const BlackMisc::Aviation::CAtcStationList &bookedStations); + + //! Data file has been read + void ps_dataFileRead(int lines); + + //! Read from model reader + void ps_readFromSwiftDb(BlackMisc::Network::CDbFlags::Entity entity, BlackMisc::Network::CDbFlags::ReadState state, int number); + + private: + //! Init the readers + void initReaders(CWebReaderFlags::WebReader flags); + + //! Init the writers + void initWriters(); + + CWebReaderFlags::WebReader m_readerFlags = CWebReaderFlags::WebReaderFlags::None; //!< which readers are available + + // for reading XML and VATSIM data files + CVatsimBookingReader *m_vatsimBookingReader = nullptr; + CVatsimDataFileReader *m_vatsimDataFileReader = nullptr; + CIcaoDataReader *m_icaoDataReader = nullptr; + CModelDataReader *m_modelDataReader = nullptr; + + // writing objects directly into DB + CDatabaseWriter *m_databaseWriter = nullptr; + }; +} // namespace + +#endif diff --git a/src/blackcore/webreaderflags.cpp b/src/blackcore/webreaderflags.cpp new file mode 100644 index 000000000..16176d1ba --- /dev/null +++ b/src/blackcore/webreaderflags.cpp @@ -0,0 +1,55 @@ +/* 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 "webreaderflags.h" + +using namespace BlackMisc::Network; + +namespace BlackCore +{ + CWebReaderFlags::WebReader CWebReaderFlags::entityToReader(CDbFlags::Entity entity) + { + WebReader f = None; + if (entity.testFlag(CDbFlags::AircraftIcaoEntity) || + entity.testFlag(CDbFlags::AirlineIcaoEntity) || + entity.testFlag(CDbFlags::CountryEntity)) + { + f |= IcaoDataReader; + } + + if (entity.testFlag(CDbFlags::ModelEntity) || + entity.testFlag(CDbFlags::DistributorEntity) || + entity.testFlag(CDbFlags::LiveryEntity)) + { + f |= ModelReader; + } + + if (entity.testFlag(CDbFlags::VatsimBookings)) + { + f |= VatsimBookingReader; + } + + if (entity.testFlag(CDbFlags::VatsimDataFile)) + { + f |= VatsimDataReader; + } + return f; + } + + bool CWebReaderFlags::isFromSwiftDb(CDbFlags::Entity entity) + { + return isFromSwiftDb(entityToReader(entity)); + } + + bool CWebReaderFlags::isFromSwiftDb(WebReader reader) + { + return reader.testFlag(ModelReader) || reader.testFlag(IcaoDataReader); + } + +} // namespace diff --git a/src/blackcore/webreaderflags.h b/src/blackcore/webreaderflags.h new file mode 100644 index 000000000..edcf55965 --- /dev/null +++ b/src/blackcore/webreaderflags.h @@ -0,0 +1,57 @@ +/* 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. + */ + +//! \file + +#include "blackcoreexport.h" +#include "blackmisc/network/dbflags.h" +#include +#include + +#ifndef BLACKCORE_CWEBREADERFLAGS_H +#define BLACKCORE_CWEBREADERFLAGS_H + +namespace BlackCore +{ + /*! + * Flags reg. the web readers + */ + class BLACKCORE_EXPORT CWebReaderFlags + { + public: + //! Which readers to init + enum WebReaderFlags + { + None = 0, ///< no reader at all + VatsimBookingReader = 1 << 0, ///< reader for VATSIM booking data + VatsimDataReader = 1 << 1, ///< reader for VATSIM data + IcaoDataReader = 1 << 2, ///< reader for ICAO data + ModelReader = 1 << 3, ///< reader for model data such as liveries, models, .. + AllVatsimReaders = VatsimBookingReader | VatsimDataReader, ///< all readers + AllSwiftDbReaders = IcaoDataReader | ModelReader, ///< all swift data + AllReaders = AllSwiftDbReaders | AllVatsimReaders ///< everything + }; + Q_DECLARE_FLAGS(WebReader, WebReaderFlags) + + //! Relationship between reader and entity + static WebReader entityToReader(BlackMisc::Network::CDbFlags::Entity entity); + + //! Read from swift DB + static bool isFromSwiftDb(BlackMisc::Network::CDbFlags::Entity entity); + + //! Read from swift DB + static bool isFromSwiftDb(WebReader reader); + }; +} // namespace + +Q_DECLARE_METATYPE(BlackCore::CWebReaderFlags::WebReaderFlags) +Q_DECLARE_METATYPE(BlackCore::CWebReaderFlags::WebReader) +Q_DECLARE_OPERATORS_FOR_FLAGS(BlackCore::CWebReaderFlags::WebReader) + +#endif