Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+352
View File
@@ -0,0 +1,352 @@
/**
* @RDE_HEADER@
* Data Plugin for The Timeline - DDS => GUI
* $Id$
* $HeadURL$
* $Author$
*
* Created by Mike Wille, SLSE, 2017-03-27
*/
#include "tln_data_plugin.h"
#include <DDS/DDSConnector/dds_connector.h>
#include <LtsSession/lts_session_data_dds.h>
#include <nglsettings/nglsettings_connections.h>
#include <ExerciseEventManagement/eem_db_structs.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QTimer>
#include <QUrlQuery>
#include <QWebSocket>
namespace TimeLineManagement
{
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
{
return std::make_shared<DataInterfaceImpl>(session);
}
DataInterfaceImpl::DataInterfaceImpl(LtsSession::LtsSessionDataDds *session)
: DataInterface()
, m_foreign(std::make_shared<ForeignInterfaceImpl>(session))
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Plugins.Timeline.Data"))
{}
ForeignInterfaceImpl::ForeignInterfaceImpl(LtsSession::LtsSessionDataDds *session)
: m_session(session)
, m_webSocketScm(nullptr)
, m_webSocketEem(nullptr)
, m_liveHistoryBufferTimer(new QTimer(this))
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Plugins.Timeline.Data"))
{
connect(m_liveHistoryBufferTimer, &QTimer::timeout, this, &ForeignInterfaceImpl::onClearHistoryBuffer);
m_liveHistoryBufferTimer->setInterval(5000);
m_liveHistoryBufferTimer->start();
// open ws socket to exercise event management
QTimer::singleShot(0, this, &ForeignInterfaceImpl::connectToScm);
}
ForeignInterfaceImpl::~ForeignInterfaceImpl()
{
m_pendingRequests.clear();
m_liveHistoryBuffer.clear();
cleanupSocket(m_webSocketScm);
cleanupSocket(m_webSocketEem);
}
static ExerciseEventManagement::Event db2dds(const ExerciseEventManagement::Database::EemEvent &evDb)
{
ExerciseEventManagement::Event ev;
ev.id(evDb.id & 0xffffffff);
ev.sampleTime(evDb.sampleTime);
ev.eventTypeId(evDb.eventTypeId);
ev.participantId(evDb.participantId);
ev.partyId(evDb.partyId);
ev.equipmentNumber(evDb.equipmentNumber);
ev.properties(evDb.properties.toUtf8().data());
// Add Originator to Hit Building
if ( ev.eventTypeId() == ProjectDataManagement::EventType_def::HitBuilding)
{
QJsonObject properties = QJsonDocument::fromJson(QString::fromStdString(ev.properties()).toUtf8()).object();
if ( properties.contains(QStringLiteral("AesName")))
{
properties.insert(QStringLiteral("Originator"), properties.value(QStringLiteral("AesName")).toString());
} else if ( properties.contains(QStringLiteral("OriginatorEquipmentNumber")))
{
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(ev.properties()), &parseError);
long originatorEquipmentNumber = properties.value(QStringLiteral("OriginatorEquipmentNumber")).toInt();
QString originatorEquipmentNumberStr = QString::number(originatorEquipmentNumber);
properties.insert(QStringLiteral("Originator"),originatorEquipmentNumberStr);
}
QJsonDocument doc(properties);
//QString strJson(QStringLiteral( doc.toJson(QJsonDocument::Compact)));
std::string propertiesStd = QJsonDocument(properties).toJson(QJsonDocument::Compact).toStdString();
ev.properties(propertiesStd);
}
ev.position(Core::GeoPosition(evDb.position.x(), evDb.position.y(), evDb.position.z()));
return ev;
}
TimelineDataProvider::TimelineDataProvider(int requestId, const QUrl &url,
qint64 from, qint64 to,
const QVector<int> &eventTypeIds,
const QJsonObject &filter)
: m_webSocketEem(new QWebSocket)
, m_requestId(requestId)
, m_bFinshed(false)
, m_requestMin(from)
, m_requestMax(to)
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Plugins.Timeline.Data"))
{
connect(m_webSocketEem, &QWebSocket::disconnected,
this, &TimelineDataProvider::disconnectedFromEem);
connect(m_webSocketEem, &QWebSocket::textMessageReceived,
this, &TimelineDataProvider::textMessageFromEem);
if (from > to)
std::swap(from, to);
QUrl realUrl(url);
realUrl.setPath(QStringLiteral("/request"));
QUrlQuery query;
query.addQueryItem(QStringLiteral("from"), QString::number(from));
query.addQueryItem(QStringLiteral("to"), QString::number(to));
query.addQueryItem(QStringLiteral("requestId"), QString::number(requestId));
if (!eventTypeIds.isEmpty())
{
QStringList sl;
sl.reserve(eventTypeIds.size());
for (int id : eventTypeIds)
sl += QString::number(id);
query.addQueryItem(QStringLiteral("eventTypeId"), sl.join(QLatin1Char(',')));
}
if (!filter.isEmpty())
{
const QJsonDocument doc(filter);
query.addQueryItem(QStringLiteral("filter"), QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));
}
realUrl.setQuery(query);
m_webSocketEem->open(realUrl);
DEBUG_LOG(m_logger) << "requesting data from EEM: " << realUrl.toString();
}
TimelineDataProvider::~TimelineDataProvider()
{
m_webSocketEem->disconnect(this);
m_webSocketEem->close();
m_webSocketEem->deleteLater();
}
void TimelineDataProvider::disconnectedFromEem()
{
m_webSocketEem->close();
if (m_bFinshed)
return;
m_bFinshed = true;
emit finished();
}
void TimelineDataProvider::textMessageFromEem(const QString &message)
{
if (message.isEmpty() || message == QStringLiteral("{}"))
{
DEBUG_LOG(m_logger) << "textMessageFromEem - finished";
disconnectedFromEem();
return;
}
const QJsonDocument doc(QJsonDocument::fromJson(message.toUtf8()));
const QJsonArray arr = doc.array();
DEBUG_LOG(m_logger) << "textMessageFromEem - #events: " << arr.size();
m_eventData.reserve(m_eventData.size() + arr.size());
using namespace ExerciseEventManagement::Database;
std::transform(arr.begin(), arr.end(),
std::back_inserter(m_eventData),
[](const QJsonValue &val) { return db2dds(fromJson<EemEvent>(val.toObject())); });
}
TimelineDataProviderInterface *ForeignInterfaceImpl::requestData(qint64 from, qint64 to, const QVector<int> &eventTypeIds, const QJsonObject &filter)
{
if (!m_webSocketEem)
{
WARNING_LOG(m_logger) << "No connection to EEM - can not request data!";
return nullptr;
}
static int s_requestId = 0;
++s_requestId;
int curRequestId = s_requestId;
TimelineDataProvider *tldp = new TimelineDataProvider(curRequestId, eemUrl(), from, to, eventTypeIds, filter);
connect(tldp, &TimelineDataProvider::finished, this, &ForeignInterfaceImpl::requestFinished);
connect(tldp, &TimelineDataProvider::destroyed, this, [this, curRequestId]() { m_pendingRequests.remove(curRequestId);});
m_pendingRequests[curRequestId] = tldp;
DEBUG_LOG(m_logger) << "add to m_pendingRequests: " << curRequestId << ", " << tldp;
return tldp;
}
QVector<ExerciseEventManagement::Event> ForeignInterfaceImpl::liveHistory() const
{
QVector<ExerciseEventManagement::Event> ret;
for (const QVector<ExerciseEventManagement::Event> &vec : m_liveHistoryBuffer)
ret += vec;
return ret;
}
void ForeignInterfaceImpl::connectToScm()
{
cleanupSocket(m_webSocketScm);
m_webSocketScm = new QWebSocket;
connect(m_webSocketScm, &QWebSocket::connected,
this, &ForeignInterfaceImpl::connectedToScm);
connect(m_webSocketScm, &QWebSocket::textMessageReceived,
this, &ForeignInterfaceImpl::textMessageFromScm);
const QUrl scmUrl(QStringLiteral("ws://%1:%2")
.arg(NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET))
.arg(NGL::Connections::port(NGL::Connections::eConnection::SCM_WEBSOCKET)));
DEBUG_LOG(m_logger) << "Trying to connect to SCM at " << scmUrl.toString();
m_webSocketScm->open(scmUrl);
}
void ForeignInterfaceImpl::connectedToScm()
{
DEBUG_LOG(m_logger) << "Connected to SCM...";
m_webSocketScm->sendTextMessage(QStringLiteral("{\"type\": \"servicePortsInformationRequest\",\"uuid\": \"7777\"}"));
}
void ForeignInterfaceImpl::textMessageFromScm(const QString &message)
{
DEBUG_LOG(m_logger) << "textMessageFromScm from scm: " << message;
const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
const QJsonArray exercises = doc.object().value(QStringLiteral("data")).toArray();
for (const QJsonValue &valEx : exercises)
{
const QJsonObject &exercise = valEx.toObject();
const int exerciseId = exercise.value(QStringLiteral("exerciseId")).toInt();
DEBUG_LOG(m_logger) << "textMessageFromScm from scm - exerciseId " << exerciseId;
if (exerciseId != m_session->exerciseId())
continue;
const QJsonArray services = exercise.value(QStringLiteral("services")).toArray();
for (const QJsonValue &valSvc : services)
{
const QJsonObject &service = valSvc.toObject();
const QString svcName = service.value(QStringLiteral("nameAbbrevation")).toString().toUpper();
DEBUG_LOG(m_logger) << "textMessageFromScm from scm - svcName " << svcName;
if (svcName != QStringLiteral("EEM"))
continue;
const QJsonArray ports = service.value(QStringLiteral("ports")).toArray();
for (const QJsonValue &valPort : ports)
{
const QJsonObject &port = valPort.toObject();
int typeId = port.value(QStringLiteral("typeId")).toInt();
if (typeId == Core::PortType::WebSocketServer)
{
m_eemPort = port.value(QStringLiteral("number")).toInt();
connectToEem();
cleanupSocket(m_webSocketScm);
m_webSocketScm = nullptr;
return;
}
}
}
}
}
void ForeignInterfaceImpl::connectToEem()
{
cleanupSocket(m_webSocketEem);
m_webSocketEem = new QWebSocket;
connect(m_webSocketEem, &QWebSocket::connected,
this, &ForeignInterfaceImpl::connectedToEem);
connect(m_webSocketEem, &QWebSocket::disconnected,
this, &ForeignInterfaceImpl::disconnectedFromEem);
connect(m_webSocketEem, &QWebSocket::textMessageReceived,
this, &ForeignInterfaceImpl::textMessageFromEem);
QUrl url(eemUrl());
url.setPath(QStringLiteral("/live"));
DEBUG_LOG(m_logger) << "Trying to connect to EEM at " << url.toString();
m_webSocketEem->open(url);
}
void ForeignInterfaceImpl::connectedToEem()
{
DEBUG_LOG(m_logger) << "Connected to EEM...";
}
void ForeignInterfaceImpl::disconnectedFromEem()
{
WARNING_LOG(m_logger) << "EEM connection closed - try to reconnect";
QTimer::singleShot(500, this, &ForeignInterfaceImpl::connectToScm);
}
void ForeignInterfaceImpl::textMessageFromEem(const QString &message)
{
TRACE_LOG(m_logger) << "textMessageFromEem: " << message;
const QJsonObject obj(QJsonDocument::fromJson(message.toUtf8()).object());
using namespace ExerciseEventManagement::Database;
ExerciseEventManagement::Event ev(db2dds(fromJson<EemEvent>(obj)));
emit liveEvent(ev);
m_liveHistoryBuffer[ev.sampleTime() / 1000].push_back(std::move(ev));
}
void ForeignInterfaceImpl::requestFinished()
{
TimelineDataProvider *tldp = qobject_cast<TimelineDataProvider *>(sender());
if (!tldp)
{
WARNING_LOG(m_logger) << "requestFinished without valid sender";
return;
}
auto it = m_pendingRequests.find(tldp->requestId());
if (it == m_pendingRequests.end())
{
WARNING_LOG(m_logger) << "requestFinished but request not found in pending requests: " << tldp->requestId() << ", " << tldp;
return;
}
DEBUG_LOG(m_logger) << "emit requestedDataAvailable for " << tldp->requestId() << ", #events: " << tldp->eventData().size() << ", " << tldp;
emit requestedDataAvailable(it.value());
it.value()->deleteLater();
m_pendingRequests.erase(it);
}
void ForeignInterfaceImpl::cleanupSocket(QWebSocket *s)
{
if (!s)
return;
s->disconnect(this);
s->close();
s->deleteLater();
}
const QUrl ForeignInterfaceImpl::eemUrl() const
{
return QUrl(QStringLiteral("ws://%1:%2")
.arg(NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET))
.arg(m_eemPort));
}
void ForeignInterfaceImpl::onClearHistoryBuffer()
{
qint64 toRemove = time(nullptr) - 10;
auto it = m_liveHistoryBuffer.begin();
while (it != m_liveHistoryBuffer.end() && it.key() < toRemove)
it = m_liveHistoryBuffer.erase(it);
}
} // namespace TimeLineManagement