refs #526, network

* signal when data have been published
* parsing of publishing JSON object
* utility functions
This commit is contained in:
Klaus Basan
2016-01-02 20:44:26 +01:00
parent 6fc39fb2d5
commit c7121e3f9f
10 changed files with 157 additions and 43 deletions

View File

@@ -109,6 +109,17 @@ namespace BlackCore
return cl; return cl;
} }
QList<QMetaObject::Connection> CWebDataServices::connectDataPublishSignal(QObject *receiver, std::function<void (const CAircraftModelList &, const CAircraftModelList &, const CStatusMessageList &)> dataPublished)
{
Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver");
QList<QMetaObject::Connection> cl;
if (!m_databaseWriter) { return cl; }
QMetaObject::Connection con = connect(this->m_databaseWriter, &CDatabaseWriter::published, receiver, dataPublished);
Q_ASSERT_X(con, Q_FUNC_INFO, "connect failed publishing signal");
cl.push_back(con);
return cl;
}
CServerList CWebDataServices::getVatsimFsdServers() const CServerList CWebDataServices::getVatsimFsdServers() const
{ {
if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getFsdServers(); } if (m_vatsimDataFileReader) { return m_vatsimDataFileReader->getFsdServers(); }
@@ -144,9 +155,9 @@ namespace BlackCore
if (m_vatsimDataFileReader) { m_vatsimDataFileReader->updateWithVatsimDataFileData(aircraftToBeUdpated); } if (m_vatsimDataFileReader) { m_vatsimDataFileReader->updateWithVatsimDataFileData(aircraftToBeUdpated); }
} }
CStatusMessageList CWebDataServices::asyncWriteModel(const CAircraftModel &model) const CStatusMessageList CWebDataServices::asyncPublishModels(const CAircraftModelList &models) const
{ {
if (m_databaseWriter) { return m_databaseWriter->asyncWriteModel(model);} if (m_databaseWriter) { return m_databaseWriter->asyncPublishModels(models);}
return CStatusMessageList(); return CStatusMessageList();
} }

View File

@@ -83,6 +83,12 @@ namespace BlackCore
QObject *receiver, QObject *receiver,
std::function<void (BlackMisc::Network::CEntityFlags::Entity, BlackMisc::Network::CEntityFlags::ReadState, int)> dataRead) override; std::function<void (BlackMisc::Network::CEntityFlags::Entity, BlackMisc::Network::CEntityFlags::ReadState, int)> dataRead) override;
//! \copydoc BlackMisc::Network::IWebDataServicesProvider::connectDataPublishSignal
//! \ingroup webdatareaderprovider
virtual QList<QMetaObject::Connection> connectDataPublishSignal(
QObject *receiver,
std::function<void (const BlackMisc::Simulation::CAircraftModelList &, const BlackMisc::Simulation::CAircraftModelList &, const BlackMisc::CStatusMessageList &)> dataPublished) override;
//! \copydoc BlackMisc::Network::IWebDataServicesProvider::triggerRead //! \copydoc BlackMisc::Network::IWebDataServicesProvider::triggerRead
//! \ingroup webdatareaderprovider //! \ingroup webdatareaderprovider
virtual BlackMisc::Network::CEntityFlags::Entity triggerRead(BlackMisc::Network::CEntityFlags::Entity whatToRead) override; virtual BlackMisc::Network::CEntityFlags::Entity triggerRead(BlackMisc::Network::CEntityFlags::Entity whatToRead) override;
@@ -227,15 +233,15 @@ namespace BlackCore
//! \ingroup webdatareaderprovider //! \ingroup webdatareaderprovider
virtual void updateWithVatsimDataFileData(BlackMisc::Simulation::CSimulatedAircraft &aircraftToBeUdpated) const override; virtual void updateWithVatsimDataFileData(BlackMisc::Simulation::CSimulatedAircraft &aircraftToBeUdpated) const override;
//! \copydoc BlackMisc::Network::IWebDataServicesProvider::asyncWriteModel //! \copydoc BlackMisc::Network::IWebDataServicesProvider::asyncPublishModels
//! \ingroup webdatareaderprovider //! \ingroup webdatareaderprovider
virtual BlackMisc::CStatusMessageList asyncWriteModel(const BlackMisc::Simulation::CAircraftModel &model) const override; virtual BlackMisc::CStatusMessageList asyncPublishModels(const BlackMisc::Simulation::CAircraftModelList &models) const override;
//! \copydoc BlackMisc::Network::IWebDataServicesProvider::canConnectSwiftDb //! \copydoc BlackMisc::Network::IWebDataServicesProvider::canConnectSwiftDb
//! \ingroup webdatareaderprovider //! \ingroup webdatareaderprovider
virtual bool canConnectSwiftDb() const override; virtual bool canConnectSwiftDb() const override;
//! Save all DB data to JSON files //! Save all DB data to a JSON files
//! \ingroup webdatareaderprovider //! \ingroup webdatareaderprovider
virtual bool writeDbDataToDisk(const QString &dir) const override; virtual bool writeDbDataToDisk(const QString &dir) const override;

View File

@@ -35,6 +35,14 @@ namespace BlackMisc
this->m_dbKey = k; this->m_dbKey = k;
} }
int IDatastoreObjectWithIntegerKey::stringToDbKey(const QString &candidate)
{
if (candidate.isEmpty()) { return invalidDbKey(); }
bool ok;
int k = candidate.toInt(&ok);
return ok ? k : invalidDbKey();
}
QJsonValue IDatastoreObjectWithIntegerKey::getDbKeyAsJsonValue() const QJsonValue IDatastoreObjectWithIntegerKey::getDbKeyAsJsonValue() const
{ {
if (this->hasValidDbKey()) { return QJsonValue(this->m_dbKey); } if (this->hasValidDbKey()) { return QJsonValue(this->m_dbKey); }

View File

@@ -55,6 +55,9 @@ namespace BlackMisc
//! Invalid key //! Invalid key
static int invalidDbKey() { return -1; } static int invalidDbKey() { return -1; }
//! Convert string to DB key
static int stringToDbKey(const QString &candidate);
protected: protected:
//! Constructor //! Constructor
IDatastoreObjectWithIntegerKey() {} IDatastoreObjectWithIntegerKey() {}

View File

@@ -7,12 +7,16 @@
* contained in the LICENSE file. * contained in the LICENSE file.
*/ */
#include "blackmisc/simulation/aircraftmodellist.h"
#include "blackmisc/datastoreutility.h" #include "blackmisc/datastoreutility.h"
#include "blackmisc/blackmiscfreefunctions.h" #include "blackmisc/blackmiscfreefunctions.h"
#include "blackmisc/stringutils.h" #include "blackmisc/stringutils.h"
#include <QJsonObject> #include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
using namespace BlackMisc;
using namespace BlackMisc::Simulation;
namespace BlackMisc namespace BlackMisc
{ {
bool CDatastoreUtility::dbBoolStringToBool(const QString &dbBool) bool CDatastoreUtility::dbBoolStringToBool(const QString &dbBool)
@@ -48,7 +52,6 @@ namespace BlackMisc
QDateTime CDatastoreUtility::parseTimestamp(const QString &timestamp) QDateTime CDatastoreUtility::parseTimestamp(const QString &timestamp)
{ {
Q_ASSERT_X(!timestamp.isEmpty(), Q_FUNC_INFO, "Missing timestamp");
if (!timestamp.isEmpty()) if (!timestamp.isEmpty())
{ {
QString ts(timestamp.trimmed().remove(' ').remove('-').remove(':')); // normalize QString ts(timestamp.trimmed().remove(' ').remove('-').remove(':')); // normalize
@@ -61,33 +64,76 @@ namespace BlackMisc
} }
} }
bool CDatastoreUtility::parseSwiftWriteResponse(const QString &jsonResponse, CStatusMessageList &messages, CVariant &key) bool CDatastoreUtility::parseSwiftPublishResponse(const QString &jsonResponse, CAircraftModelList &publishedModels, CAircraftModelList &skippedModels, CStatusMessageList &messages)
{ {
if (jsonResponse.isEmpty()) { return ""; } static const CLogCategoryList cats({ CLogCategory::swiftDbWebservice()});
QJsonDocument jsonDoc(QJsonDocument::fromJson(jsonResponse.toUtf8())); if (jsonResponse.isEmpty())
if (!jsonDoc.isObject()) { return ""; } {
QJsonObject json(jsonDoc.object()); messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Empty JSON data"));
Q_ASSERT_X(!json.value("id").isNull(), Q_FUNC_INFO, "malformed response"); return false;
if (json.value("id").isNull()) { return false; } }
QString id(json.value("id").toString().trimmed());
QJsonArray msgObject(json.value("messages").toArray());
messages.push_back(CStatusMessageList::fromDatabaseJson(msgObject));
bool success = false;
int intKey; QJsonDocument jsonDoc(QJsonDocument::fromJson(jsonResponse.toUtf8()));
bool isInt;
intKey = id.toInt(&isInt); // array of messages
if (isInt) if (jsonDoc.isArray())
{ {
key.setValue(intKey); CStatusMessageList msgs(CStatusMessageList::fromDatabaseJson(jsonDoc.array()));
success = (intKey >= 0); messages.push_back(msgs);
return true;
} }
else
// no object -> most likely some fucked up HTML string with the PHP error
if (!jsonDoc.isObject())
{ {
key.setValue(id); QString phpError(jsonResponse);
success = !id.isEmpty(); phpError.remove(QRegExp("<[^>]*>"));
messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, phpError));
return false;
} }
return success;
// fully blown object
QJsonObject json(jsonDoc.object());
bool data = false;
if (json.contains("msgs"))
{
QJsonValue msgJson(json.take("msgs"));
CStatusMessageList msgs(CStatusMessageList::fromDatabaseJson(msgJson.toArray()));
if (!msgs.isEmpty())
{
messages.push_back(msgs);
data = true;
}
}
if (json.contains("publishedModels"))
{
QJsonValue publishedJson(json.take("publishedModels"));
CAircraftModelList published = CAircraftModelList::fromDatabaseJson(publishedJson.toArray());
if (!published.isEmpty())
{
publishedModels.push_back(published);
data = true;
}
}
if (json.contains("skippedModels"))
{
QJsonValue skippedJson(json.take("skippedModels"));
CAircraftModelList skipped = CAircraftModelList::fromDatabaseJson(skippedJson.toArray());
if (!skipped.isEmpty())
{
skippedModels.push_back(skipped);
data = true;
}
}
if (!data)
{
messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Received response, but no JSON data"));
}
return data;
} }
} // namespace } // namespace

View File

@@ -41,8 +41,8 @@ namespace BlackMisc
//! Parse a timestamp object //! Parse a timestamp object
static QDateTime parseTimestamp(const QString &timestamp); static QDateTime parseTimestamp(const QString &timestamp);
//! Get id from a DB response //! Get data from a DB response
static bool parseSwiftWriteResponse(const QString &jsonResponse, BlackMisc::CStatusMessageList &messages, BlackMisc::CVariant &key); static bool parseSwiftPublishResponse(const QString &jsonResponse, BlackMisc::Simulation::CAircraftModelList &publishedModels, BlackMisc::Simulation::CAircraftModelList &skippedModels, BlackMisc::CStatusMessageList &messages);
}; };
} // namespace } // namespace

View File

@@ -54,7 +54,7 @@ namespace BlackMisc
{ {
QStringList ips; QStringList ips;
if (!CNetworkUtils::hasConnectedInterface(false)) return ips; if (!CNetworkUtils::hasConnectedInterface(false)) return ips;
foreach(const QHostAddress & address, QNetworkInterface::allAddresses()) foreach (const QHostAddress &address, QNetworkInterface::allAddresses())
{ {
if (address.isLoopback() || address.isNull()) continue; if (address.isLoopback() || address.isNull()) continue;
if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost)) if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost))
@@ -207,13 +207,24 @@ namespace BlackMisc
qurl.addQueryItem("XDEBUG_SESSION_START", "ECLIPSE_DBGP"); qurl.addQueryItem("XDEBUG_SESSION_START", "ECLIPSE_DBGP");
} }
QHttpPart CNetworkUtils::getJsonTextMutlipart(const QJsonObject &json) QHttpPart CNetworkUtils::getJsonTextMultipart(const QJsonObject &json)
{
const QByteArray bytes(QJsonDocument(json).toJson(QJsonDocument::Compact));
return getJsonTextMultipart(bytes);
}
QHttpPart CNetworkUtils::getJsonTextMultipart(const QJsonArray &json)
{
const QByteArray bytes(QJsonDocument(json).toJson(QJsonDocument::Compact));
return getJsonTextMultipart(bytes);
}
QHttpPart CNetworkUtils::getJsonTextMultipart(const QByteArray &bytes)
{ {
const QByteArray jsonData(QJsonDocument(json).toJson(QJsonDocument::Compact));
QHttpPart textPart; QHttpPart textPart;
QString name("form-data; name=\"swiftjson\""); QString name("form-data; name=\"swiftjson\"");
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(name)); textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(name));
textPart.setBody(jsonData); textPart.setBody(bytes);
return textPart; return textPart;
} }

View File

@@ -99,7 +99,13 @@ namespace BlackMisc
static void addDebugFlag(QUrlQuery &qurl); static void addDebugFlag(QUrlQuery &qurl);
//! Multipart for JSON //! Multipart for JSON
static QHttpPart getJsonTextMutlipart(const QJsonObject &json); static QHttpPart getJsonTextMultipart(const QJsonObject &json);
//! Multipart for JSON
static QHttpPart getJsonTextMultipart(const QJsonArray &json);
//! Multipart for JSON
static QHttpPart getJsonTextMultipart(const QByteArray &bytes);
//! Our tweakes network request //! Our tweakes network request
static QNetworkRequest getNetworkRequest(const CUrl &url, RequestType type = Get); static QNetworkRequest getNetworkRequest(const CUrl &url, RequestType type = Get);

View File

@@ -261,11 +261,11 @@ namespace BlackMisc
return this->m_webDataReaderProvider->updateWithVatsimDataFileData(aircraftToBeUdpated); return this->m_webDataReaderProvider->updateWithVatsimDataFileData(aircraftToBeUdpated);
} }
CStatusMessageList CWebDataServicesAware::asyncWriteModel(const CAircraftModel &model) const CStatusMessageList CWebDataServicesAware::asyncPublishModels(const CAircraftModelList &models) const
{ {
Q_ASSERT_X(this->m_webDataReaderProvider, Q_FUNC_INFO, "Missing provider"); Q_ASSERT_X(this->m_webDataReaderProvider, Q_FUNC_INFO, "Missing provider");
if (!hasProvider()) { return CStatusMessageList(); } if (!hasProvider()) { return CStatusMessageList(); }
return this->m_webDataReaderProvider->asyncWriteModel(model); return this->m_webDataReaderProvider->asyncPublishModels(models);
} }
void CWebDataServicesAware::setProvider(IWebDataServicesProvider *webDataReaderProvider) void CWebDataServicesAware::setProvider(IWebDataServicesProvider *webDataReaderProvider)
@@ -296,6 +296,16 @@ namespace BlackMisc
} }
} }
void CWebDataServicesAware::connectDataPublishSignal(QObject *receiver, std::function<void (const CAircraftModelList &, const CAircraftModelList &, const CStatusMessageList &)> dataPublished)
{
Q_ASSERT_X(this->m_webDataReaderProvider, Q_FUNC_INFO, "Missing provider");
if (!hasProvider()) { return; }
if (receiver)
{
this->m_swiftConnections.append(this->m_webDataReaderProvider->connectDataPublishSignal(receiver, dataPublished));
}
}
CEntityFlags::Entity CWebDataServicesAware::triggerRead(CEntityFlags::Entity whatToRead) CEntityFlags::Entity CWebDataServicesAware::triggerRead(CEntityFlags::Entity whatToRead)
{ {
Q_ASSERT_X(this->m_webDataReaderProvider, Q_FUNC_INFO, "Missing provider"); Q_ASSERT_X(this->m_webDataReaderProvider, Q_FUNC_INFO, "Missing provider");

View File

@@ -184,10 +184,10 @@ namespace BlackMisc
//! \threadsafe //! \threadsafe
virtual int getMetarsCount() const = 0; virtual int getMetarsCount() const = 0;
//! Write directly to database //! Publish models to database
virtual BlackMisc::CStatusMessageList asyncWriteModel(const BlackMisc::Simulation::CAircraftModel &model) const = 0; virtual BlackMisc::CStatusMessageList asyncPublishModels(const BlackMisc::Simulation::CAircraftModelList &models) const = 0;
//! Relay signals for swift data //! Relay signals for read swift data
//! Connect signals to slot receiver. As the interface is no QObject, slots can not be connected directly. //! Connect signals to slot receiver. As the interface is no QObject, slots can not be connected directly.
//! In order to disconnect a list of connections is provided, which have to be disconnected manually. //! In order to disconnect a list of connections is provided, which have to be disconnected manually.
//! \note receiver is required for connection type //! \note receiver is required for connection type
@@ -195,16 +195,24 @@ namespace BlackMisc
QObject *receiver, QObject *receiver,
std::function<void(BlackMisc::Network::CEntityFlags::Entity, BlackMisc::Network::CEntityFlags::ReadState, int)> dataRead) = 0; std::function<void(BlackMisc::Network::CEntityFlags::Entity, BlackMisc::Network::CEntityFlags::ReadState, int)> dataRead) = 0;
//! Relay signals for published swift data
//! Connect signals to slot receiver. As the interface is no QObject, slots can not be connected directly.
//! In order to disconnect a list of connections is provided, which have to be disconnected manually.
//! \note receiver is required for connection type
virtual QList<QMetaObject::Connection> connectDataPublishSignal(
QObject *receiver,
std::function<void(const BlackMisc::Simulation::CAircraftModelList &, const BlackMisc::Simulation::CAircraftModelList &, const BlackMisc::CStatusMessageList &)> dataPublished) = 0;
//! Trigger read of new data //! Trigger read of new data
virtual BlackMisc::Network::CEntityFlags::Entity triggerRead(BlackMisc::Network::CEntityFlags::Entity whatToRead) = 0; virtual BlackMisc::Network::CEntityFlags::Entity triggerRead(BlackMisc::Network::CEntityFlags::Entity whatToRead) = 0;
//! Can connect to swift DB? //! Can connect to swift DB?
virtual bool canConnectSwiftDb() const = 0; virtual bool canConnectSwiftDb() const = 0;
//! Write data to disk //! Write data to disk (mainly for testing scenarios)
virtual bool writeDbDataToDisk(const QString &dir) const = 0; virtual bool writeDbDataToDisk(const QString &dir) const = 0;
//! Load DB data from disk //! Load DB data from disk (mainly for testing scenarios)
virtual bool readDbDataFromDisk(const QString &dir, bool inBackground) = 0; virtual bool readDbDataFromDisk(const QString &dir, bool inBackground) = 0;
}; };
@@ -322,8 +330,8 @@ namespace BlackMisc
//! \copydoc IWebDataServicesProvider::updateWithVatsimDataFileData //! \copydoc IWebDataServicesProvider::updateWithVatsimDataFileData
void updateWithVatsimDataFileData(BlackMisc::Simulation::CSimulatedAircraft &aircraftToBeUdpated) const; void updateWithVatsimDataFileData(BlackMisc::Simulation::CSimulatedAircraft &aircraftToBeUdpated) const;
//! \copydoc IWebDataServicesProvider::asyncWriteModel //! \copydoc IWebDataServicesProvider::asyncPublishModels
BlackMisc::CStatusMessageList asyncWriteModel(const BlackMisc::Simulation::CAircraftModel &model) const; BlackMisc::CStatusMessageList asyncPublishModels(const BlackMisc::Simulation::CAircraftModelList &models) const;
//! Set the provider //! Set the provider
virtual void setProvider(IWebDataServicesProvider *webDataReaderProvider); virtual void setProvider(IWebDataServicesProvider *webDataReaderProvider);
@@ -339,6 +347,11 @@ namespace BlackMisc
QObject *receiver, QObject *receiver,
std::function<void(BlackMisc::Network::CEntityFlags::Entity, BlackMisc::Network::CEntityFlags::ReadState, int)> dataRead); std::function<void(BlackMisc::Network::CEntityFlags::Entity, BlackMisc::Network::CEntityFlags::ReadState, int)> dataRead);
//! \copydoc IWebDataServicesProvider::connectDataPublishSignal
virtual void connectDataPublishSignal(
QObject *receiver,
std::function<void(const BlackMisc::Simulation::CAircraftModelList &, const BlackMisc::Simulation::CAircraftModelList &, const BlackMisc::CStatusMessageList &)> dataPublished);
//! \copydoc IWebDataServicesProvider::triggerRead //! \copydoc IWebDataServicesProvider::triggerRead
BlackMisc::Network::CEntityFlags::Entity triggerRead(BlackMisc::Network::CEntityFlags::Entity whatToRead); BlackMisc::Network::CEntityFlags::Entity triggerRead(BlackMisc::Network::CEntityFlags::Entity whatToRead);