diff --git a/src/blackcore/context/contextnetwork.h b/src/blackcore/context/contextnetwork.h index 16ac01b5c..210870ace 100644 --- a/src/blackcore/context/contextnetwork.h +++ b/src/blackcore/context/contextnetwork.h @@ -40,6 +40,8 @@ #include "blackmisc/statusmessage.h" #include "blackmisc/weather/metar.h" +#include + //! \addtogroup dbus //! @{ @@ -302,6 +304,13 @@ namespace BlackCore //! Request parts for callsign (from another client) virtual void testRequestAircraftConfig(const BlackMisc::Aviation::CCallsign &callsign) = 0; + public: + //! Raw FSD message receiver functor + using RawFsdMessageReceivedSlot = std::function; + + //! Connect to receive raw fsd messages + virtual QMetaObject::Connection connectRawFsdMessageSignal(QObject *receiver, RawFsdMessageReceivedSlot rawFsdMessageReceivedSlot) = 0; + protected: //! Constructor IContextNetwork(CCoreFacadeConfig::ContextMode mode, CCoreFacade *runtime) : CContext(mode, runtime) {} diff --git a/src/blackcore/context/contextnetworkempty.h b/src/blackcore/context/contextnetworkempty.h index b132404cf..dba702b91 100644 --- a/src/blackcore/context/contextnetworkempty.h +++ b/src/blackcore/context/contextnetworkempty.h @@ -385,6 +385,16 @@ namespace BlackCore logEmptyContextWarning(Q_FUNC_INFO); Q_UNUSED(enabled); } + + public: + //! \copydoc IContextNetwork::connectRawFsdMessageSignal + virtual QMetaObject::Connection connectRawFsdMessageSignal(QObject *receiver, RawFsdMessageReceivedSlot rawFsdMessageReceivedSlot) override + { + logEmptyContextWarning(Q_FUNC_INFO); + Q_UNUSED(receiver); + Q_UNUSED(rawFsdMessageReceivedSlot); + return {}; + } }; } // namespace } // namespace diff --git a/src/blackcore/context/contextnetworkimpl.cpp b/src/blackcore/context/contextnetworkimpl.cpp index add268343..119950098 100644 --- a/src/blackcore/context/contextnetworkimpl.cpp +++ b/src/blackcore/context/contextnetworkimpl.cpp @@ -751,5 +751,16 @@ namespace BlackCore rooms.push_back(s2.getVoiceRoom()); return rooms; } + + QMetaObject::Connection CContextNetwork::connectRawFsdMessageSignal(QObject *receiver, RawFsdMessageReceivedSlot rawFsdMessageReceivedSlot) + { + Q_ASSERT_X(receiver, Q_FUNC_INFO, "Missing receiver"); + + // bind does not allow to define connection type, so we use receiver as workaround + const QMetaObject::Connection uc; // unconnected + const QMetaObject::Connection c = rawFsdMessageReceivedSlot ? connect(m_network, &INetwork::rawFsdMessageReceived, receiver, rawFsdMessageReceivedSlot) : uc; + Q_ASSERT_X(c || !rawFsdMessageReceivedSlot, Q_FUNC_INFO, "connect failed"); + return c; + } } // namespace } // namespace diff --git a/src/blackcore/context/contextnetworkimpl.h b/src/blackcore/context/contextnetworkimpl.h index ad7677fcd..0211df185 100644 --- a/src/blackcore/context/contextnetworkimpl.h +++ b/src/blackcore/context/contextnetworkimpl.h @@ -191,6 +191,10 @@ namespace BlackCore //! Gracefully shut down, e.g. for thread safety void gracefulShutdown(); + public: + //! \copydoc IContextNetwork::connectRawFsdMessageSignal + virtual QMetaObject::Connection connectRawFsdMessageSignal(QObject *receiver, RawFsdMessageReceivedSlot rawFsdMessageReceivedSlot) override; + protected: //! Constructor, with link to runtime CContextNetwork(CCoreFacadeConfig::ContextMode, CCoreFacade *runtime); diff --git a/src/blackcore/context/contextnetworkproxy.cpp b/src/blackcore/context/contextnetworkproxy.cpp index 2c7136842..095224fe0 100644 --- a/src/blackcore/context/contextnetworkproxy.cpp +++ b/src/blackcore/context/contextnetworkproxy.cpp @@ -93,6 +93,7 @@ namespace BlackCore s = connection.connect(serviceName, IContextNetwork::ObjectPath(), IContextNetwork::InterfaceName(), "removedAircraft", this, SIGNAL(removedAircraft(BlackMisc::Aviation::CCallsign))); Q_ASSERT(s); + Q_UNUSED(s); this->relayBaseClassSignals(serviceName, connection, IContextNetwork::ObjectPath(), IContextNetwork::InterfaceName()); } @@ -331,5 +332,12 @@ namespace BlackCore { return m_dBusInterface->callDBusRet(QLatin1String("getMetarForAirport"), airportIcaoCode); } + + QMetaObject::Connection CContextNetworkProxy::connectRawFsdMessageSignal(QObject *receiver, RawFsdMessageReceivedSlot rawFsdMessageReceivedSlot) + { + Q_UNUSED(receiver); + Q_UNUSED(rawFsdMessageReceivedSlot); + return {}; + } } // ns } // ns diff --git a/src/blackcore/context/contextnetworkproxy.h b/src/blackcore/context/contextnetworkproxy.h index 54dfe95e7..895c01abf 100644 --- a/src/blackcore/context/contextnetworkproxy.h +++ b/src/blackcore/context/contextnetworkproxy.h @@ -124,6 +124,10 @@ namespace BlackCore virtual void testRequestAircraftConfig(const BlackMisc::Aviation::CCallsign &callsign) override; //! @} + public: + //! \copydoc IContextNetwork::connectRawFsdMessageSignal + virtual QMetaObject::Connection connectRawFsdMessageSignal(QObject *receiver, RawFsdMessageReceivedSlot rawFsdMessageReceivedSlot) override; + private: BlackMisc::CGenericDBusInterface *m_dBusInterface; /*!< DBus interface */ diff --git a/src/blackcore/network.h b/src/blackcore/network.h index ed5511171..51fe25978 100644 --- a/src/blackcore/network.h +++ b/src/blackcore/network.h @@ -16,6 +16,7 @@ #include "blackmisc/simulation/simulatorplugininfo.h" #include "blackmisc/simulation/simulatedaircraft.h" #include "blackmisc/geo/coordinategeodetic.h" +#include "blackmisc/network/rawfsdmessage.h" #include "blackmisc/network/serverlist.h" #include "blackmisc/network/textmessagelist.h" #include "blackmisc/aviation/informationmessage.h" @@ -526,6 +527,11 @@ namespace BlackCore */ void aircraftConfigPacketReceived(const BlackMisc::Aviation::CCallsign &callsign, const QJsonObject &incremental, bool isFull); + /*! + * We received a raw message for debugging purposes + */ + void rawFsdMessageReceived(const BlackMisc::Network::CRawFsdMessage &rawFsdMessage); + //! @} //////////////////////////////////////////////////////////////// //! \name Weather signals diff --git a/src/blackcore/registermetadata.cpp b/src/blackcore/registermetadata.cpp index 94f7ca7d5..4a3cc389a 100644 --- a/src/blackcore/registermetadata.cpp +++ b/src/blackcore/registermetadata.cpp @@ -49,5 +49,6 @@ namespace BlackCore Data::CVatsimSetup::registerMetadata(); Data::CLauncherSetup::registerMetadata(); Vatsim::CReaderSettings::registerMetadata(); + Vatsim::CRawFsdMessageSettings::registerMetadata(); } } // namespace diff --git a/src/blackcore/vatsim/networkvatlib.cpp b/src/blackcore/vatsim/networkvatlib.cpp index d94b94bc0..7d2bd4012 100644 --- a/src/blackcore/vatsim/networkvatlib.cpp +++ b/src/blackcore/vatsim/networkvatlib.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -158,6 +159,7 @@ namespace BlackCore Vat_SetAircraftInfoHandler(m_net.data(), onPilotInfoReceived, this); Vat_SetCustomPilotPacketHandler(m_net.data(), onCustomPacketReceived, this); Vat_SetAircraftConfigHandler(m_net.data(), onAircraftConfigReceived, this); + Vat_SetFsdMessageHandler(m_net.data(), onRawFsdMessage, this); } CNetworkVatlib::~CNetworkVatlib() @@ -983,6 +985,11 @@ namespace BlackCore cbvar_cast(cbvar)->customPacketDispatcher(cbvar_cast(cbvar)->fromFSD(callsign), cbvar_cast(cbvar)->fromFSD(packetId), cbvar_cast(cbvar)->fromFSD(data, dataSize)); } + void CNetworkVatlib::onRawFsdMessage(VatFsdClient *, const char *message, void *cbvar) + { + cbvar_cast(cbvar)->handleRawFsdMessage(cbvar_cast(cbvar)->fromFSD(message)); + } + void CNetworkVatlib::customPacketDispatcher(const CCallsign &callsign, const QString &packetId, const QStringList &data) { if (packetId.compare("FSIPI", Qt::CaseInsensitive) == 0) @@ -1022,6 +1029,47 @@ namespace BlackCore } } + void CNetworkVatlib::handleRawFsdMessage(const QString &fsdMessage) + { + CRawFsdMessage rawFsdMessage(fsdMessage); + if (m_rawFsdMessageLogFile.isOpen()) + { + QTextStream stream(&m_rawFsdMessageLogFile); + stream << rawFsdMessage.toQString() << endl; + } + emit rawFsdMessageReceived(rawFsdMessage); + } + + void CNetworkVatlib::fsdMessageSettingsChanged() + { + if (m_rawFsdMessageLogFile.isOpen()) { m_rawFsdMessageLogFile.close(); } + const CRawFsdMessageSettings setting = m_fsdMessageSetting.get(); + if (!setting.isFileWritingEnabled() || setting.getFileDir().isEmpty()) { return; } + + if (setting.getFileWriteMode() == CRawFsdMessageSettings::Truncate) + { + QString filePath = CFileUtils::appendFilePaths(setting.getFileDir(), "rawfsdmessages.log"); + m_rawFsdMessageLogFile.setFileName(filePath); + m_rawFsdMessageLogFile.open(QIODevice::Text | QIODevice::WriteOnly); + } + else if (setting.getFileWriteMode() == CRawFsdMessageSettings::Append) + { + QString filePath = CFileUtils::appendFilePaths(setting.getFileDir(), "rawfsdmessages.log"); + m_rawFsdMessageLogFile.setFileName(filePath); + m_rawFsdMessageLogFile.open(QIODevice::Text | QIODevice::WriteOnly | QIODevice::Append); + } + else if (setting.getFileWriteMode() == CRawFsdMessageSettings::Timestamped) + { + QString filename("rawfsdmessages"); + filename += QLatin1String("_"); + filename += QDateTime::currentDateTime().toString(QStringLiteral("yyMMddhhmmss")); + filename += QLatin1String(".log"); + QString filePath = CFileUtils::appendFilePaths(setting.getFileDir(), filename); + m_rawFsdMessageLogFile.setFileName(filePath); + m_rawFsdMessageLogFile.open(QIODevice::Text | QIODevice::WriteOnly); + } + } + void CNetworkVatlib::consolidateTextMessage(const CTextMessage &textMessage) { if (textMessage.isSupervisorMessage()) diff --git a/src/blackcore/vatsim/networkvatlib.h b/src/blackcore/vatsim/networkvatlib.h index 28faae5ec..69dcb7202 100644 --- a/src/blackcore/vatsim/networkvatlib.h +++ b/src/blackcore/vatsim/networkvatlib.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -165,6 +166,7 @@ namespace BlackCore static void onPilotPositionUpdate(VatFsdClient *, const char *callsign, const VatPilotPosition *position, void *cbvar); static void onAircraftConfigReceived(VatFsdClient *, const char *callsign, const char *aircraftConfig, void *cbvar); static void onCustomPacketReceived(VatFsdClient *, const char *callsign, const char *packetId, const char **data, int dataSize, void *cbvar); + static void onRawFsdMessage(VatFsdClient *, const char *message, void *cbvar); //! @} QByteArray toFSD(const QString &qstr) const; @@ -198,6 +200,8 @@ namespace BlackCore void sendPositionUpdate(); void sendInterimPositions(); void customPacketDispatcher(const BlackMisc::Aviation::CCallsign &callsign, const QString &packetId, const QStringList &data); + void handleRawFsdMessage(const QString &fsdMessage); + void fsdMessageSettingsChanged(); signals: void terminate(); //!< \private @@ -251,10 +255,11 @@ namespace BlackCore { QDateTime m_queryTime = QDateTime::currentDateTimeUtc(); QStringList m_atisMessage; - }; - QHash m_pendingAtisQueries; + + BlackMisc::CSettingReadOnly m_fsdMessageSetting { this, &CNetworkVatlib::fsdMessageSettingsChanged }; + QFile m_rawFsdMessageLogFile; }; } //namespace } //namespace diff --git a/src/blackcore/vatsim/vatsimsettings.cpp b/src/blackcore/vatsim/vatsimsettings.cpp index 05f88a3be..0f7fa6eff 100644 --- a/src/blackcore/vatsim/vatsimsettings.cpp +++ b/src/blackcore/vatsim/vatsimsettings.cpp @@ -74,5 +74,47 @@ namespace BlackCore break; } } + + CRawFsdMessageSettings::CRawFsdMessageSettings() + { } + + CRawFsdMessageSettings::CRawFsdMessageSettings(bool enabled, const QString &FileDir) : + m_fileWritingEnabled(enabled), m_FileDir(FileDir) + { } + + QString CRawFsdMessageSettings::convertToQString(bool i18n) const + { + Q_UNUSED(i18n); + QString s("CRawFsdMessageSettings"); + s.append(" enabled: ").append(boolToYesNo(m_fileWritingEnabled)); + s.append(" dir: ").append(m_FileDir); + return s; + } + + CVariant CRawFsdMessageSettings::propertyByIndex(const BlackMisc::CPropertyIndex &index) const + { + if (index.isMyself()) { return CVariant::from(*this); } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexWriteEnabled: return CVariant::fromValue(this->m_fileWritingEnabled); + case IndexFileDir: return CVariant::fromValue(this->m_FileDir); + case IndexFileWriteMode: return CVariant::fromValue(this->m_fileWriteMode); + default: return CValueObject::propertyByIndex(index); + } + } + + void CRawFsdMessageSettings::setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant) + { + if (index.isMyself()) { (*this) = variant.to(); return; } + ColumnIndex i = index.frontCasted(); + switch (i) + { + case IndexWriteEnabled: this->m_fileWritingEnabled = variant.toBool(); break; + case IndexFileDir: this->m_FileDir = variant.toQString(); break; + case IndexFileWriteMode: this->m_fileWriteMode = variant.to(); break; + default: CValueObject::setPropertyByIndex(index, variant); break; + } + } } // ns } // ns diff --git a/src/blackcore/vatsim/vatsimsettings.h b/src/blackcore/vatsim/vatsimsettings.h index 2461649ba..6cbc8cc50 100644 --- a/src/blackcore/vatsim/vatsimsettings.h +++ b/src/blackcore/vatsim/vatsimsettings.h @@ -17,6 +17,8 @@ #include "blackmisc/valueobject.h" #include "blackmisc/pq/time.h" #include "blackmisc/network/serverlist.h" +#include "blackmisc/directoryutils.h" +#include "blackmisc/fileutils.h" namespace BlackCore { @@ -164,11 +166,94 @@ namespace BlackCore return reader; } }; + + //! FSD Message settings + class BLACKCORE_EXPORT CRawFsdMessageSettings : public BlackMisc::CValueObject + { + public: + //! File writing mode + enum FileWriteMode + { + Truncate, + Append, + Timestamped + }; + + //! Properties by index + enum ColumnIndex + { + IndexWriteEnabled = BlackMisc::CPropertyIndex::GlobalIndexRawFsdMessageSettings, + IndexFileDir, + IndexFileWriteMode + }; + + //! Default constructor. + CRawFsdMessageSettings(); + + //! Simplified constructor + CRawFsdMessageSettings(bool enabled, const QString &fileDir); + + //! Is file writing enabled? + bool isFileWritingEnabled() const { return m_fileWritingEnabled; } + + //! Get file directory + QString getFileDir() const { return m_FileDir; } + + //! Get file write mode + FileWriteMode getFileWriteMode () const { return m_fileWriteMode; } + + //! \copydoc BlackMisc::Mixin::Index::propertyByIndex + BlackMisc::CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; + + //! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex + void setPropertyByIndex(const BlackMisc::CPropertyIndex &index, const BlackMisc::CVariant &variant); + + //! \copydoc BlackMisc::Mixin::String::toQString + QString convertToQString(bool i18n = false) const; + + private: + bool m_fileWritingEnabled = false; + QString m_FileDir; + FileWriteMode m_fileWriteMode = Truncate; + + BLACK_METACLASS( + CRawFsdMessageSettings, + BLACK_METAMEMBER(fileWritingEnabled), + BLACK_METAMEMBER(FileDir), + BLACK_METAMEMBER(fileWriteMode) + ); + }; + + //! Raw FSD message settings + struct TRawFsdMessageSetting : public BlackMisc::TSettingTrait + { + //! \copydoc BlackCore::TSettingTrait::key + static const char *key() { return "network/rawfsdmessagelog"; } + + //! \copydoc BlackCore::TSettingTrait::humanReadable + static const QString &humanReadable() { static const QString name("FSD message Logging"); return name; } + + //! \copydoc BlackCore::TSettingTrait::isValid + static bool isValid(const CRawFsdMessageSettings &setting) + { + if (setting.isFileWritingEnabled()) { return !setting.getFileDir().isEmpty(); } + return true; + } + + //! \copydoc BlackCore::TSettingTrait::defaultValue + static const CRawFsdMessageSettings &defaultValue() + { + static const CRawFsdMessageSettings setting { false, BlackMisc::CDirectoryUtils::logDirectory() }; + return setting; + } + }; } // ns } // ns Q_DECLARE_METATYPE(BlackCore::Vatsim::CReaderSettings) Q_DECLARE_METATYPE(BlackMisc::CCollection) Q_DECLARE_METATYPE(BlackMisc::CSequence) +Q_DECLARE_METATYPE(BlackCore::Vatsim::CRawFsdMessageSettings) +Q_DECLARE_METATYPE(BlackCore::Vatsim::CRawFsdMessageSettings::FileWriteMode) #endif diff --git a/src/blackmisc/propertyindex.h b/src/blackmisc/propertyindex.h index c1832b579..9353c7322 100644 --- a/src/blackmisc/propertyindex.h +++ b/src/blackmisc/propertyindex.h @@ -158,6 +158,7 @@ namespace BlackMisc GlobalIndexCGeneralGuiSettings = 14600, GlobalIndexCTextMessageSettings = 14700, GlobalIndexCAtcStationsSettings = 14800, + GlobalIndexRawFsdMessageSettings = 14900, GlobalIndexCInterpolatioRenderingSetup = 16000, GlobalIndexCInterpolationHints = 16100, GlobalIndexSwiftPilotClient = 17000,