diff --git a/src/blackcore/db/databasewriter.cpp b/src/blackcore/db/databasewriter.cpp index 4d4a96501..e918b7dc0 100644 --- a/src/blackcore/db/databasewriter.cpp +++ b/src/blackcore/db/databasewriter.cpp @@ -49,6 +49,18 @@ namespace BlackCore return msgs; } + if (this->isReplyOverdue()) + { + bool killed = this->killPendingReply(); + if (killed) + { + const CStatusMessage msg(CStatusMessage::SeverityWarning, "Aborted outdated pending reply"); + msgs.push_back(CStatusMessage(msg)); + // need to let a potential receiver know it has failed + emit this->publishedModels(CAircraftModelList(), CAircraftModelList(), msg, false, false); + } + } + if (m_pendingReply) { msgs.push_back(CStatusMessage(CStatusMessage::SeverityWarning, "Another write operation in progress")); @@ -66,17 +78,14 @@ namespace BlackCore } m_pendingReply = sApp->postToNetwork(request, multiPart, { this, &CDatabaseWriter::ps_postModelsResponse}); + m_replyPendingSince = QDateTime::currentMSecsSinceEpoch(); return msgs; } void CDatabaseWriter::gracefulShutdown() { m_shutdown = true; - if (m_pendingReply) - { - m_pendingReply->abort(); - m_pendingReply = nullptr; - } + this->killPendingReply(); } void CDatabaseWriter::ps_postModelsResponse(QNetworkReply *nwReplyPtr) @@ -100,26 +109,42 @@ namespace BlackCore if (dataFileData.isEmpty()) { const CStatusMessageList msgs({CStatusMessage(cats, CStatusMessage::SeverityError, "No response data from " + urlString)}); - emit publishedModels(CAircraftModelList(), CAircraftModelList(), msgs); + emit publishedModels(CAircraftModelList(), CAircraftModelList(), msgs, false, false); return; } CAircraftModelList modelsPublished; CAircraftModelList modelsSkipped; CStatusMessageList msgs; - bool success = CDatastoreUtility::parseSwiftPublishResponse(dataFileData, modelsPublished, modelsSkipped, msgs); - emit publishedModels(modelsPublished, modelsSkipped, msgs); - Q_UNUSED(success); + bool directWrite; + const bool success = CDatastoreUtility::parseSwiftPublishResponse(dataFileData, modelsPublished, modelsSkipped, msgs, directWrite); + emit publishedModels(modelsPublished, modelsSkipped, msgs, success, directWrite); } else { QString error = nwReply->errorString(); nwReply->close(); // close asap const CStatusMessageList msgs( {CStatusMessage(cats, CStatusMessage::SeverityError, "HTTP error: " + error)}); - emit publishedModels(CAircraftModelList(), CAircraftModelList(), msgs); + emit publishedModels(CAircraftModelList(), CAircraftModelList(), msgs, false, false); } } + bool CDatabaseWriter::killPendingReply() + { + if (!m_pendingReply) { return false; } + m_pendingReply->abort(); + m_pendingReply = nullptr; + m_replyPendingSince = -1; + return true; + } + + bool CDatabaseWriter::isReplyOverdue() const + { + if (m_replyPendingSince < 0 || !m_pendingReply) { return false; } + qint64 ms = QDateTime::currentMSecsSinceEpoch() - m_replyPendingSince; + return ms > 7500; + } + CUrl CDatabaseWriter::getModelPublishUrl(const Network::CUrl &baseUrl) { return baseUrl.withAppendedPath("service/publishmodels.php"); diff --git a/src/blackcore/db/databasewriter.h b/src/blackcore/db/databasewriter.h index 66577cb8e..7435871b0 100644 --- a/src/blackcore/db/databasewriter.h +++ b/src/blackcore/db/databasewriter.h @@ -44,7 +44,10 @@ namespace BlackCore signals: //! Published models, the response to \sa asyncPublishModels - void publishedModels(const BlackMisc::Simulation::CAircraftModelList &modelsPublished, const BlackMisc::Simulation::CAircraftModelList &modelsSkipped, const BlackMisc::CStatusMessageList &messages); + void publishedModels(const BlackMisc::Simulation::CAircraftModelList &modelsPublished, + const BlackMisc::Simulation::CAircraftModelList &modelsSkipped, + const BlackMisc::CStatusMessageList &messages, + bool success, bool directWrite); private slots: //! Post response @@ -53,8 +56,15 @@ namespace BlackCore private: BlackMisc::Network::CUrl m_modelPublishUrl; QNetworkReply *m_pendingReply = nullptr; + qint64 m_replyPendingSince = -1; bool m_shutdown = false; + //! Kill the pending reply + bool killPendingReply(); + + //! Reply timed out? + bool isReplyOverdue() const; + //! URL model web service static BlackMisc::Network::CUrl getModelPublishUrl(const BlackMisc::Network::CUrl &baseUrl); diff --git a/src/blackgui/components/dbmappingcomponent.cpp b/src/blackgui/components/dbmappingcomponent.cpp index 59f9de2ef..e908f5f0d 100644 --- a/src/blackgui/components/dbmappingcomponent.cpp +++ b/src/blackgui/components/dbmappingcomponent.cpp @@ -595,9 +595,10 @@ namespace BlackGui emit this->tabIndexChanged(index); } - void CDbMappingComponent::ps_onModelsSuccessfullyPublished(const CAircraftModelList &models) + void CDbMappingComponent::ps_onModelsSuccessfullyPublished(const CAircraftModelList &models, bool directWrite) { if (models.isEmpty()) { return; } + if (!directWrite) { return; } // no models wwritten, but CRs emit this->requestUpdatedData(CEntityFlags::ModelEntity); } diff --git a/src/blackgui/components/dbmappingcomponent.h b/src/blackgui/components/dbmappingcomponent.h index ec01441cc..95cb9dd88 100644 --- a/src/blackgui/components/dbmappingcomponent.h +++ b/src/blackgui/components/dbmappingcomponent.h @@ -235,7 +235,7 @@ namespace BlackGui void ps_onStashedModelsDataChanged(int count, bool withFilter); //! Models have been published successfully - void ps_onModelsSuccessfullyPublished(const BlackMisc::Simulation::CAircraftModelList &models); + void ps_onModelsSuccessfullyPublished(const BlackMisc::Simulation::CAircraftModelList &models, bool directWrite); //! Stash drop request void ps_handleStashDropRequest(const BlackMisc::Aviation::CAirlineIcaoCode &code) const; diff --git a/src/blackgui/components/dbstashcomponent.cpp b/src/blackgui/components/dbstashcomponent.cpp index 7bde67858..72b3f6941 100644 --- a/src/blackgui/components/dbstashcomponent.cpp +++ b/src/blackgui/components/dbstashcomponent.cpp @@ -282,12 +282,12 @@ namespace BlackGui } } - void CDbStashComponent::ps_publishedModelsResponse(const CAircraftModelList &publishedModels, const CAircraftModelList &skippedModels, const CStatusMessageList &msgs) + void CDbStashComponent::ps_publishedModelsResponse(const CAircraftModelList &publishedModels, const CAircraftModelList &skippedModels, const CStatusMessageList &msgs, bool success, bool directWrite) { ui->tvp_StashAircraftModels->hideLoadIndicator(); - if (!publishedModels.isEmpty()) + if (!publishedModels.isEmpty() && success) { - emit this->modelsSuccessfullyPublished(publishedModels); + emit this->modelsSuccessfullyPublished(publishedModels, directWrite); } if (!msgs.isEmpty()) diff --git a/src/blackgui/components/dbstashcomponent.h b/src/blackgui/components/dbstashcomponent.h index ff25e0e2f..195902fb0 100644 --- a/src/blackgui/components/dbstashcomponent.h +++ b/src/blackgui/components/dbstashcomponent.h @@ -134,7 +134,7 @@ namespace BlackGui void stashedModelsChanged(); //! Models succesfully published - void modelsSuccessfullyPublished(const BlackMisc::Simulation::CAircraftModelList &publishedModels); + void modelsSuccessfullyPublished(const BlackMisc::Simulation::CAircraftModelList &publishedModels, bool directWrite); private slots: //! Unstash pressed @@ -152,7 +152,7 @@ namespace BlackGui //! Publish response received void ps_publishedModelsResponse(const BlackMisc::Simulation::CAircraftModelList &publishedModels, const BlackMisc::Simulation::CAircraftModelList &skippedModels, - const BlackMisc::CStatusMessageList &msgs); + const BlackMisc::CStatusMessageList &msgs, bool success, bool directWrite); //! Copy over values void ps_copyOverPartsToSelected(); diff --git a/src/blackmisc/db/datastoreutility.cpp b/src/blackmisc/db/datastoreutility.cpp index e9b85f2e6..1713d071d 100644 --- a/src/blackmisc/db/datastoreutility.cpp +++ b/src/blackmisc/db/datastoreutility.cpp @@ -77,9 +77,11 @@ namespace BlackMisc } } - bool CDatastoreUtility::parseSwiftPublishResponse(const QString &jsonResponse, CAircraftModelList &publishedModels, CAircraftModelList &skippedModels, CStatusMessageList &messages) + bool CDatastoreUtility::parseSwiftPublishResponse(const QString &jsonResponse, CAircraftModelList &publishedModels, CAircraftModelList &skippedModels, CStatusMessageList &messages, bool &directWrite) { static const CLogCategoryList cats({ CLogCategory::swiftDbWebservice()}); + directWrite = false; + if (jsonResponse.isEmpty()) { messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Empty JSON data")); @@ -88,7 +90,7 @@ namespace BlackMisc QJsonDocument jsonDoc(QJsonDocument::fromJson(jsonResponse.toUtf8())); - // array of messages + // array of messages only if (jsonDoc.isArray()) { CStatusMessageList msgs(CStatusMessageList::fromDatabaseJson(jsonDoc.array())); @@ -106,7 +108,7 @@ namespace BlackMisc // fully blown object QJsonObject json(jsonDoc.object()); - bool data = false; + bool hasData = false; if (json.contains("msgs")) { QJsonValue msgJson(json.take("msgs")); @@ -114,10 +116,17 @@ namespace BlackMisc if (!msgs.isEmpty()) { messages.push_back(msgs); - data = true; + hasData = true; } } + // direct write means models written, otherwise CRs + if (json.contains("directWrite")) + { + QJsonValue dw(json.take("directWrite")); + directWrite = dw.toBool(false); + } + if (json.contains("publishedModels")) { QJsonValue publishedJson(json.take("publishedModels")); @@ -125,7 +134,7 @@ namespace BlackMisc if (!published.isEmpty()) { publishedModels.push_back(published); - data = true; + hasData = true; } } @@ -136,16 +145,16 @@ namespace BlackMisc if (!skipped.isEmpty()) { skippedModels.push_back(skipped); - data = true; + hasData = true; } } - if (!data) + if (!hasData) { messages.push_back(CStatusMessage(cats, CStatusMessage::SeverityError, "Received response, but no JSON data")); } - return data; + return hasData; } } // ns } // ns diff --git a/src/blackmisc/db/datastoreutility.h b/src/blackmisc/db/datastoreutility.h index cf69bc5f7..16f0bbecc 100644 --- a/src/blackmisc/db/datastoreutility.h +++ b/src/blackmisc/db/datastoreutility.h @@ -46,7 +46,10 @@ namespace BlackMisc static QDateTime parseTimestamp(const QString ×tamp); //! Get data from a DB response - static bool parseSwiftPublishResponse(const QString &jsonResponse, BlackMisc::Simulation::CAircraftModelList &publishedModels, BlackMisc::Simulation::CAircraftModelList &skippedModels, BlackMisc::CStatusMessageList &messages); + static bool parseSwiftPublishResponse(const QString &jsonResponse, + BlackMisc::Simulation::CAircraftModelList &publishedModels, + BlackMisc::Simulation::CAircraftModelList &skippedModels, + BlackMisc::CStatusMessageList &messages, bool &directWrite); }; } // namespace } // namespace