Add methods to receive and write raw FSD messages

This commit adds methods to register for live FSD message reception. The
amount of traffic can be quite high, therefore no normal signal is used -
which would be available via DBus. Instead one has to connect manually
by passing a functor. This guarantees that we communicate only in-process.
If someone tries to connect on the proxy side, the connection will fail.
This needs to be handled properly in client code.
This commit also adds a method to write the FSD message to a selected file.

Maniphest Tasks: T222
This commit is contained in:
Roland Winklmeier
2018-01-22 14:18:50 +01:00
parent 7b9ad0ea07
commit 704068d299
13 changed files with 236 additions and 2 deletions

View File

@@ -40,6 +40,8 @@
#include "blackmisc/statusmessage.h"
#include "blackmisc/weather/metar.h"
#include <functional>
//! \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<void(const BlackMisc::Network::CRawFsdMessage &)>;
//! 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) {}

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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<BlackMisc::Weather::CMetar>(QLatin1String("getMetarForAirport"), airportIcaoCode);
}
QMetaObject::Connection CContextNetworkProxy::connectRawFsdMessageSignal(QObject *receiver, RawFsdMessageReceivedSlot rawFsdMessageReceivedSlot)
{
Q_UNUSED(receiver);
Q_UNUSED(rawFsdMessageReceivedSlot);
return {};
}
} // ns
} // ns

View File

@@ -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 */

View File

@@ -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

View File

@@ -49,5 +49,6 @@ namespace BlackCore
Data::CVatsimSetup::registerMetadata();
Data::CLauncherSetup::registerMetadata();
Vatsim::CReaderSettings::registerMetadata();
Vatsim::CRawFsdMessageSettings::registerMetadata();
}
} // namespace

View File

@@ -52,6 +52,7 @@
#include <QList>
#include <QRegularExpression>
#include <QTextCodec>
#include <QTextStream>
#include <QVector>
#include <Qt>
#include <QtDebug>
@@ -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())

View File

@@ -32,6 +32,7 @@
#include <stdbool.h>
#include <vatlib/vatlib.h>
#include <QByteArray>
#include <QFile>
#include <QJsonObject>
#include <QList>
#include <QObject>
@@ -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<BlackMisc::Aviation::CCallsign, PendingAtisQuery> m_pendingAtisQueries;
BlackMisc::CSettingReadOnly<BlackCore::Vatsim::TRawFsdMessageSetting> m_fsdMessageSetting { this, &CNetworkVatlib::fsdMessageSettingsChanged };
QFile m_rawFsdMessageLogFile;
};
} //namespace
} //namespace

View File

@@ -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<ColumnIndex>();
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<CRawFsdMessageSettings>(); return; }
ColumnIndex i = index.frontCasted<ColumnIndex>();
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<FileWriteMode>(); break;
default: CValueObject::setPropertyByIndex(index, variant); break;
}
}
} // ns
} // ns

View File

@@ -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<BlackCore::Vatsim::CRawFsdMessageSettings>
{
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<CRawFsdMessageSettings>
{
//! \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<BlackCore::Vatsim::CReaderSettings>)
Q_DECLARE_METATYPE(BlackMisc::CSequence<BlackCore::Vatsim::CReaderSettings>)
Q_DECLARE_METATYPE(BlackCore::Vatsim::CRawFsdMessageSettings)
Q_DECLARE_METATYPE(BlackCore::Vatsim::CRawFsdMessageSettings::FileWriteMode)
#endif

View File

@@ -158,6 +158,7 @@ namespace BlackMisc
GlobalIndexCGeneralGuiSettings = 14600,
GlobalIndexCTextMessageSettings = 14700,
GlobalIndexCAtcStationsSettings = 14800,
GlobalIndexRawFsdMessageSettings = 14900,
GlobalIndexCInterpolatioRenderingSetup = 16000,
GlobalIndexCInterpolationHints = 16100,
GlobalIndexSwiftPilotClient = 17000,